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
| Name | What it does |
|---|---|
| O_CLOEXEC | The 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=y | Before Linux 6.5 the call was disabled by default unless the kernel was booted with this parameter. |
| RLIMIT_MEMLOCK | Mappings are locked like mlock(2) and count against RLIMIT_MEMLOCK; pages never swap. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| ENOSYS | Not implemented on this architecture, or not enabled on the kernel command line. |
| EINVAL | flags included unknown bits. |
| EMFILE | Per-process open file descriptor limit reached. |
| ENOMEM | Insufficient 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
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
