Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mmap() fails on tmpfs (operation not permitted) #2974

Closed
therealkenc opened this issue Feb 23, 2018 · 7 comments
Closed

mmap() fails on tmpfs (operation not permitted) #2974

therealkenc opened this issue Feb 23, 2018 · 7 comments
Assignees

Comments

@therealkenc
Copy link
Collaborator

therealkenc commented Feb 23, 2018

Version 17101. Took a bit to figure out where mmap() was going wrong here. Works on lxfs (/home), but not tmpfs (/run). Fine on Real Linux tmpfs (but we know that) [edit: don't assume things, Ken]. Code below is taken nearly verbatim from here.

Repro:

$ g++ mmap-fail.cpp -o mmap-fail
$ sudo ./mmap-fail
mmap() failed: : Operation not permitted

Test case:

// mmap-fail.cpp
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, const char* argv[])
{
    //const char* path = "./eightbytes.bin"; // okay on lxfs
    const char* path = "/run/eightbytes.bin";
    int fd = open(path, 
        O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
    if (fd < 0) {
        perror("open() failed: ");
        return 1;
    }
    int r = posix_fallocate(fd, 0, sizeof(uint64_t));
    if (r < 0) {
        perror("posix_fallocate() failed: ");
        return 1;
    }
    uint64_t *p = (uint64_t*)mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (p == MAP_FAILED) {
        perror("mmap() failed: ");
        return 1;
    }

    printf("Whee!\n");
    return 0;
}

And sudo strace -o mmap-fail.strace ./mmap-fail for pedantry:

execve("./mmap-fail", ["./mmap-fail"], [/* 15 vars */]) = 0
[...blah blah]
open("/run/eightbytes.bin", O_RDWR|O_CREAT|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC, 0644) = 3
fallocate(3, 0, 0, 8)                   = 0
mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = -1 EPERM (Operation not permitted)
dup(2)                                  = 4
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
brk(NULL)                               = 0x1390000
brk(0x13b1000)                          = 0x13b1000
fstat(4, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(4, "mmap() failed: : Operation not p"..., 41) = 41
@benhillis benhillis self-assigned this Feb 26, 2018
@benhillis
Copy link
Member

Thanks for filing, @therealkenc. I'll take a look this morning and see what's going on, this is unexpected.

@benhillis
Copy link
Member

@therealkenc I believe your Linux configuration is different than what comes on a stock Ubuntu install. Take a look at your /proc/self/mountinfo file. Is the /run tmpfs mount mounted with the noexec flag?

I suspect for you it's not, but for me it is:
image

@therealkenc
Copy link
Collaborator Author

Thanks for looking Ben and great analysis. Never say "fine on Real Linux natch", dammit. The real code is remounting /run (far away) and I need to look closer at why it is failing. Ugh. I'll post once/if I find an actual diverge. But your reply really helped, this is easier with two eyeballs.

@benhillis
Copy link
Member

@therealkenc - No problem, let me know if you' find anything that jumps out at you.

@therealkenc
Copy link
Collaborator Author

therealkenc commented Feb 27, 2018

Nah. This is squarely linux-behavior.

What I saw was: works on Linux (because journald works obv), identical sequence works on lxfs, identical sequence doesn't work on WSL tmpfs, and stopped right there assuming broken mmap() on tmpfs. I didn't consider external factors on the mount. I am not sure precisely how/where in the code /run gets set up to make journald happy (because /run "looks" noexec on Linux too), but everything is all namespacy so what you see isn't necessarily what a process gets. Sigh.

@therealkenc
Copy link
Collaborator Author

@therealkenc I believe your Linux configuration is different than what comes on a stock Ubuntu install.
Take a look at your /proc/self/mountinfo file. Is the /run tmpfs mount mounted with the noexec flag?

Dammit... No, /run is noexec on my Real Linux too, seems. Now it is going to haunt me whether really wasn't noexec back in February 2018, and I never really looked because the explanation was so plausible. Because not bothering to look sounds like something I would do.

Re-ran the OP test case on stock Ubuntu Bionic just now. Yeah, passes even with noexec, and, my previous supposition "the real code is remounting /run (far away) and I need to look closer at why it is failing" is almost certainly wrong. I never did "look closer" into why it was failing (my systemd experiment ran course). The OP snippet was from systemd-journald(8). Which probably still won't run and has resurfaced ref #3937.

@therealkenc therealkenc reopened this May 1, 2019
@therealkenc
Copy link
Collaborator Author

WSL2 good enough for me. WSL1 LZ can be #3937.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants