Logo Questions Linux Laravel Mysql Ubuntu Git Menu

memfd_secret(): how is it supposed to work? [closed]

memfd_secret() was merged in the kernel, but I do not see the real security benefit of it. I mean, this has the idea of avoiding sideline attacks, but this is like when the car keys are locked and nobody knows where they are.

AFAIK, the page given to the application simply is not mapped when in kernel mode, but this cant be used to isolate a virus, or whatever of the kernel itself.

How is it supposed to be safer to isolate a range of memory of the kernel?

Could someone provide a code example showing how this protects of spectre or like that?


int main(int argc, char *argv[]) {
    while(true) {
        int rc = fork();
        if(rc == -1) {
            perror("fork error");
like image 361
avelardo Avatar asked Mar 01 '23 11:03


1 Answers

memfd_secret() allows a user-space process to have a "secret" memory area. In this context, "secret" means that other processes cannot have access to that memory area (not even the kernel itself, or at least not by accident).

This syscall allows a process to store confidential information (like a password or a private key) in a more secure way, because it's harder for a malware to access that secret memory area. This syscall should also protect from vulnerabilities like Spectre, because the secret memory area is uncached; and should also protect (albeit not completely, but at least partially) from kernel bugs, since the kernel has no access to that memory area.

In order to use this syscall (that will be available in Linux 5.14), you first make a call to memfd_secret() in order to obtain a file descriptor; then you make a call to ftruncate() in order to choose the size of the secret memory region; and finally you use mmap() in order to map the secret memory, so you can access it via pointers as usual.

Other details are available here.

EDIT: unfortunately, the "uncached" feature that made memfd_secret() less vulnerable to attacks like Spectre has been removed because there was a concern for perfomance.

EDIT 2: additional details about why secret memory areas obtained with memfd_secret() makes programs safer (source, slightly modified by me for clearness):

  • Enhanced protection (in conjunction with all the other in-kernel attack prevention systems) against ROP attacks. Secret memory makes "simple" ROP insufficient to perform exfiltration, which increases the required complexity of the attack. Along with other protections like the kernel stack size limit and address space layout randomization which make finding gadgets is really hard, absence of any in-kernel primitive for accessing secret memory means the one gadget ROP attack can't work. Since the only way to access secret memory is to reconstruct the missing mapping entry, the attacker has to recover the physical page and insert a PTE pointing to it in the kernel and then retrieve the contents. That takes at least three gadgets which is a level of difficulty beyond most standard attacks.

  • Prevent cross-process secret user-space memory exposures. Once the secret memory is allocated, the user can't accidentally pass it into the kernel to be transmitted somewhere. The secret memory pages cannot be accessed via the direct map and they are disallowed in GUP.

  • Harden against exploited kernel flaws. In order to access secret memory, a kernel-side attack would need to either walk the page tables and create new ones, or spawn a new privileged user-space process to perform secrets exfiltration using ptrace.

EDIT 3: just a note that I think may be relevant: secret memory areas can be accessed by child processes created using fork(), so one must be cautious. At least, using flag O_CLOEXEC (passed to memfd_secret()), the process will not make the secret memory available to processes created with execve().

like image 146
Luca Polito Avatar answered Mar 05 '23 14:03

Luca Polito