我被要求将这个问题从 stackoverflow 移到这里。
我fork了guitmz的memrun repo(用于asm和go)。
我确实在我的 fork 中为 C 提供了 memrun 和 memfd_create :
https://github.com/Hermann-SW/memrun?organization=Hermann-SW&organization=Hermann-SW#fork-mission-statement
memfd_create.c创建一个内存文件(/memfd:...)并返回进程 pid 和内存文件描述符:
pi@raspberrypi400:~/memrun/C $ gcc memfd_create.c -o memfd_create
pi@raspberrypi400:~/memrun/C $ ./memfd_create
1880 3
pi@raspberrypi400:~/memrun/C $ ls -l /proc/1880/fd
total 0
lrwx------ 1 pi pi 64 Oct 6 20:54 0 -> /dev/pts/0
lrwx------ 1 pi pi 64 Oct 6 20:54 1 -> /dev/pts/0
lrwx------ 1 pi pi 64 Oct 6 20:54 2 -> /dev/pts/0
lrwx------ 1 pi pi 64 Oct 6 20:54 3 -> '/memfd:rab.oof (deleted)'
pi@raspberrypi400:~/memrun/C $
在内存文件中创建 10MB 文件系统的工作原理:
pi@raspberrypi400:~/memrun/C $ dd if=/dev/zero of=/proc/1880/fd/3 bs=1024 count=10240 2> /dev/null
pi@raspberrypi400:~/memrun/C $ mkfs.ext2 /proc/1880/fd/3 > /dev/null
mke2fs 1.44.5 (15-Dec-2018)
pi@raspberrypi400:~/memrun/C $
在 32 位 Raspberry Pi OS (debian) 以及 64 位 Intel Ubuntu 上,在 /proc(!) 下安装该文件系统是可行的:
pi@raspberrypi400:~/memrun/C $ ls -l /proc/1880/fd
total 12
drwx------ 2 root root 12288 Oct 6 20:56 lost+found
pi@raspberrypi400:~/memrun/C $
/proc 下的相同挂载不适用于 Red Hat Enterprise Linux:
$ ./memfd_create
26611 3
$ ls -l /proc/26611/fd
total 0
lrwx------. 1 stammw stammw 64 Oct 6 21:00 0 -> /dev/pts/0
lrwx------. 1 stammw stammw 64 Oct 6 21:00 1 -> /dev/pts/0
lrwx------. 1 stammw stammw 64 Oct 6 21:00 2 -> /dev/pts/0
lrwx------. 1 stammw stammw 64 Oct 6 21:00 3 -> '/memfd:rab.oof (deleted)'
$
$ dd if=/dev/zero of=/proc/26611/fd/3 bs=1024 count=10240 2> /dev/null
$ mkfs.ext2 /proc/26611/fd/3 > /dev/null
mke2fs 1.45.6 (20-Mar-2020)
$
$ sudo mount /proc/26611/fd/3 /proc/26611/fd
[sudo] password for stammw:
mount: /proc/26611/fd: cannot mount /dev/loop0 read-only.
$
在 /proc 下安装应该根本不起作用吗?
如果应该的话,需要什么才能在 RHEL 的 /proc 下成功挂载?
也许我这样做的原因是:tcc“-run”选项增强了 g++/gcc,所有 gcc/g++ 临时文件以及 RAM 中的可执行文件,并从 RAM 执行:
pi@raspberrypi400:~/memrun/C $ fortune -s | bin/g++ -run demo.cpp foo 123
bar foo
Sorry. I forget what I was going to say.
pi@raspberrypi400:~/memrun/C $
pi@raspberrypi400:~/memrun/C $ cat demo.cpp
/**
*/
#include <iostream>
int main(int argc, char *argv[])
{
printf("bar %s\n", argc>1 ? argv[1] : "(undef)");
for(char c; std::cin.read(&c, 1); ) { std::cout << c; }
return 0;
}
pi@raspberrypi400:~/memrun/C $
来自其他线程的第一个答案:
您的 RHEL 输出显示一个 .在权限之后,意味着还有其他 SELinux 权限在起作用。你能看到它们是什么吗? – 另一个人
在 RHEL 上:
$ sudo ls -Z /proc/26611/fd
[sudo] password for stammw:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 0
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 1
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3
$
$ ls -Z /proc/26611 | grep fd$
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 fd
$
答案1
/proc 下的相同挂载不适用于 Red Hat Enterprise Linux:
mount: /proc/26611/fd: cannot mount /dev/loop0 read-only.
您应该查看日志,并尝试其中的内容;-)
[root@rhel8 ~]# journalctl --no-pager -n1 | sed 's/^ *//'
-- Logs begin at Thu 2021-10-07 03:05:03 BST, end at Thu 2021-10-07 03:10:49 BST. --
Oct 07 03:06:54 rhel8.od platform-python[2154]: SELinux is preventing mount from mounton access on the directory /proc/<pid>/fd.
***** Plugin catchall (100. confidence) suggests **************************
If you believe that mount should be allowed mounton access on the fd directory by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'mount' --raw | audit2allow -M my-mount
# semodule -X 300 -i my-mount.pp
但我认为这不是一个好主意。最好保持原样并尝试其他方法,而不是将其安装在/proc/<pid>/fd
.
tcc“-run”选项增强了 g++/gcc,所有 gcc/g++ 临时文件以及 RAM 中的可执行文件,并从 RAM 执行:
临时目录或 tmpfs 就可以了,你让自己变得过于复杂了。
答案2
安装在下面
/proc
根本不起作用吗?
不,下面的目录/proc
在这方面与其他目录没有什么不同,只要没有其他限制(请参阅其他回答),你可以在那里安装任何东西。
路径的一个特殊性/proc/<pid>/*
是此类目录上的任何挂载都将自动延迟卸载 [1]当<pid>
终止时。
您可以使用该功能创建一个临时目录,当您的进程终止时(无论它如何终止),通过在/proc/self
.
示例脚本:
#! /bin/sh
set -e
mount -t tmpfs tmpfs /proc/$$/attr
cd /proc/$$/attr
bash
这将使您处于当前目录位于 的 shell 中/proc/$$/attr
,您可以在其中创建其他文件和目录,一旦您退出 shell,这些文件和目录就会消失。
但更好的选择是创建一个私有挂载命名空间,这将为您提供更多关于挂载位置的选项:
$ export T=$(mktemp -d)
$ unshare -Urm
root# mount -t tmpfs t $T
root# echo > $T/somefile
root# ls $T
somefile
root# exit
$ ls $T
<nothing left>
注意:在某些类似 Debian 的系统上,您必须启用sysctl kernel.unprivileged_userns_clone=1
(以 root 身份)才能以普通用户身份运行它;或者,取而代之的是cap_sys_admin+eip
二进制包装器可以取消共享挂载命名空间,将其挂载传播设置为私有,执行 tmpfs 挂载(无需创建额外的用户命名空间),然后执行另一个程序或脚本。
[1] 延迟卸载的目录保持“浮动”状态,直到所有对其中文件和目录的引用都被关闭。这会产生一个奇怪的情况,您有一个独立的(但功能齐全的)文件系统,它没有出现在 中/proc/mounts
,并且getcwd(2)
系统调用返回一个以(unreachable)/
( 必须在 glibc 的包装器中修补以匹配 POSIX 的定义,这需要getcwd()
失败或返回绝对路径):
# sleep 2 & mount -t tmpfs t /proc/$!/attr; cd /proc/$!/attr
[1] 6585
/proc/6585/attr#
[1]+ Done sleep 2 (wd: ~)
/proc/6585/attr# /bin/pwd
/bin/pwd: couldn't find directory entry in '..' with matching i-node
/proc/6585/attr# strace /bin/pwd 2>&1 | grep cwd
getcwd("(unreachable)/", 4096) = 15
/proc/6585/attr# mkdir sub # you can still use the dir normally
请注意,您还可以懒洋洋umount(MNT_DETACH)
使用/显式卸载文件系统umount -l
。