$RodHat_
Syscall reference · Memory

memfd_secret(2)

Create memory removed from the kernel's direct map, mapped only by fd holders.

Since
Linux 5.14check your kernel →
glibc
none (use syscall(2))
System
Linux
Man page
memfd_secret(2)

Synopsis

#include <sys/syscall.h>
#include <unistd.h>

int syscall(SYS_memfd_secret, unsigned int flags);

Rod's take

mlock keeps a secret out of swap, but the kernel can still read every byte through its direct map. memfd_secret pulls the pages out of the direct map, so only the processes holding the fd have them mapped at all. The kernel can't reach them either, so don't bother passing pointers into syscalls. The price is chopping up the kernel's huge-page direct map, and that TLB tax shows up on busy servers, so benchmark before you sprinkle it around. Wipe it with explicit_bzero, not memset, or the compiler will helpfully delete your wipe.

Flags and arguments that matter

NameWhat it does
O_CLOEXECThe only accepted flag: close-on-exec. The man page says FD_CLOEXEC; mm/secretmem.c checks O_CLOEXEC, and FD_CLOEXEC gets EINVAL.
secretmem.enable=yBefore Linux 6.5 the call was disabled by default unless the kernel was booted with this parameter.
RLIMIT_MEMLOCKMappings are locked like mlock(2) and count against RLIMIT_MEMLOCK; pages never swap.

Errors you will actually hit

errnoMeaning
ENOSYSNot implemented on this architecture, or not enabled on the kernel command line.
EINVALflags included unknown bits.
EMFILEPer-process open file descriptor limit reached.
ENOMEMInsufficient memory to create the anonymous file.

Example

int fd = syscall(SYS_memfd_secret, 0);
if (fd < 0)
    err(1, "memfd_secret");   /* ENOSYS: not enabled */
if (ftruncate(fd, size) < 0)
    err(1, "ftruncate");

void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);                      /* the mapping keeps the pages */
if (p == MAP_FAILED)
    err(1, "mmap");
/* ... use the key ... */
explicit_bzero(p, size);
munmap(p, size);

Trimmed from the full walkthrough in memfd_secret: memory the kernel itself cannot read.

BSD equivalent

none

The long version, from the console

Sources

  1. mm/secretmem.c (flag mask is O_CLOEXEC), torvalds/linux
  2. memfd_secret(2), man7.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.