我需要从服务器分叉一个 exec。由于我的服务器内存占用很大,我打算使用vfork()
/linux clone()
。我还需要为stdin
/ stdout
/打开管道stderr
。这是否允许使用clone()
/ vfork()
?
2 回答
从标准:
[..] 如果创建的进程修改了除用于存储返回值
vfork()
的类型变量以外的任何数据,或从被调用的函数返回,或在成功调用或之前调用任何其他函数,则行为未定义函数族之一。pid_t
vfork()
vfork()
_exit()
exec
调用setuid
or之类的函数的问题pipe
在于它们可能会影响父进程和子进程之间共享的地址空间中的内存。如果您之前需要做任何事情exec
,最好的方法是编写一个小的 shim 进程来执行您需要的任何操作,然后exec
转到最终的子进程(可能是通过 提供的参数argv
)。
shim.c
======
enum {
/* initial arguments */
ARGV_FILE = 5, ARGV_ARGS
};
int main(int argc, char *argv[]) {
/* consume instructions from argv */
/* setuid, pipe() etc. */
return execvp(argv[ARGV_FILE], argv + ARGV_ARGS);
}
我会改用clone()
标志CLONE_VFORK|CLONE_VM
;有关详细信息,请参见man 2 clone。
因为CLONE_FILES
没有设置,所以子进程有自己的文件描述符,可以关闭和打开标准描述符,完全不影响父进程。
因为克隆的进程是一个单独的进程,它有自己的用户和组 ID,所以通过setresgid()
and设置它们setresuid()
(可能调用setgroups()
或initgroups()
首先设置额外的组 - 请参阅man 2 setresuid、man 2 setgroups和man 3 initgroups了解详细信息) 根本不会影响父母。
CLONE_VFORK|CLONE_VM
标志意味着这应该clone()
表现得像vfork()
,子进程在与父进程相同的内存空间中运行,直到execve()
调用。
这种方法避免了使用中间可执行文件时的延迟——它非常重要——但这种方法完全是 Linux 特定的。