memfd_create and File Seals for Safer Temporary Data Handoff
Passing temporary data between processes often starts with a predictable filename in a shared directory. That design introduces path collisions, cleanup races and a chance that another process changes the file before the receiver reads it. Linux memfd_create() offers a different primitive: an anonymous, memory-backed file represented by a file descriptor. File seals can then restrict later changes to the underlying object.
An ordinary anonymous descriptor can be created without a name. MFD_ALLOW_SEALING adds the ability to apply seals. MFD_CLOEXEC should usually accompany it so the descriptor does not survive an accidental exec. The file has no directory entry, so another process cannot replace it by changing a pathname. The receiver gets the object through descriptor transfer, not through a shared filename.
Seals are added with fcntl() and F_ADD_SEALS. Available controls include preventing growth, shrinking, writes and future seal changes. A producer can write the complete payload, apply the required seals and then hand the descriptor to a consumer. The consumer can still read the same open file description and can use F_GET_SEALS to inspect the current state.
int fd = memfd_create("payload", MFD_CLOEXEC | MFD_ALLOW_SEALING);
write(fd, data, length);
fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK |
F_SEAL_WRITE | F_SEAL_SEAL);
The ordering is part of the security property. Applying F_SEAL_WRITE can fail while writable mappings exist, so the producer should finish its work, remove mappings that block the seal, apply the seal and check the result before transfer. A successful handoff should not continue writing through another alias after the receiver assumes the data is frozen.
Seals are not access control. A process that already has a writable descriptor may have privileges the producer did not intend to delegate. Descriptor passing through a Unix domain socket should send only the least privileged descriptor available, using SCM_RIGHTS and explicit close-on-exec flags. The receiver should inspect the seals rather than trusting a message that says the file was sealed.
Memory-backed data also consumes memory or swap. A producer needs a size limit before accepting input. A sender-controlled growth path can otherwise create pressure even when the final file is sealed. The service should enforce a maximum payload, apply backpressure and avoid copying the same large buffer several times.
The technique is useful for configuration snapshots, signed manifests, test fixtures and worker handoff, where the object identity matters more than a path. It is less suitable when other software requires a visible filesystem name. In that case, a private directory with restrictive permissions and an atomic rename still needs its own review.
The safest design treats the descriptor as the identity and the seal state as a promise that can be checked. It keeps the handoff narrow, limits size and lifetime, and avoids rebuilding a filename API around a primitive that was chosen to remove one.
Top comments (0)