我有这个简短的 C 片段:
const char *name = "/asdf";
int desc = shm_open(name, O_RDWR | O_CREAT, 0777);
ftruncate(desc, 4096);
void *block = mmap(NULL, 4096, PROT_EXEC, MAP_SHARED, desc, 0);
shm_unlink(name);
它创建了一个共享内存对象,每个人都可写、可读和可执行;然后将其映射到具有可执行权限的内存中。然而,
mmap
调用失败 EPERM
因为某些原因。Strace 给出了以下内容:
statfs("/dev/shm/", {f_type=0x1021994, f_bsize=4096, f_blocks=450722, f_bfree=450372, f_bavail=450372, f_files=450722, f_ffree=450713, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
futex(0x7fa7f4c8b330, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/dev/shm/asdf", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0777) = 3
fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
ftruncate(3, 4096) = 0
mmap(NULL, 4096, PROT_EXEC, MAP_SHARED, 3, 0) = -1 EPERM (Operation not permitted)
问题似乎来自于
PROT_EXEC
的使用, 如 mmap
只要没有 PROT_EXEC
,任何权限组合都会成功.mmap
没有执行权限,然后尝试 mprotect
它也失败了。
最佳答案
假设您在这里运行 Linux,[no]exec
/dev/shm
mount 被传播到由 shm_open
创建的共享内存区域在当前的 Linux 内核中。因此,如果您的 /dev/shm
,您的问题就会发生。安装在 noexec
挂载选项(某些发行版(Debian?)默认情况下可能会这样做)。
我已修改您的代码以添加 perror
(并返回 2)在 mmap
的情况下失败:
testbox $ mount|grep shm
tmpfs on /dev/shm type tmpfs (rw)
testbox $ ./a.out ; echo $?
0
testbox $ sudo mount -o remount,noexec /dev/shm
testbox $ mount|grep shm
tmpfs on /dev/shm type tmpfs (rw,noexec)
testbox $ ./a.out ; echo $?
mmap: Operation not permitted
2
关于executable - 共享可执行内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25275777/