在vfork()/ clone()中调用execv()之前的setuid()
我需要从服务器派生一个exec。 由于我的服务器内存占用量很大,我打算使用vfork()
/ linux clone()
。 我还需要为stdin
/ stdout
/ stderr
打开管道。 这是clone()
/ vfork()
允许的吗?
从标准:
[..]如果由
vfork()
创建的进程修改除了用于存储vfork()
的返回值的pid_t
类型的变量以外的任何数据,或者从调用vfork()
的函数返回,则行为未定义,或在成功调用_exit()
或exec
系列函数之前调用任何其他函数。
调用setuid
或pipe
等函数的问题是它们可能会影响父进程和子进程之间共享的地址空间中的内存。 如果你需要在exec
之前做任何事情,最好的方法是编写一个小的shim进程,它可以exec
你需要的任何操作,然后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()
和setresuid()
设置它们(可能先调用setgroups()
或initgroups()
来设置其他组 – 参见man 2 setresuid , man 2 setgroups , man 3 initgroups for details)根本不会影响父级。
CLONE_VFORK|CLONE_VM
标志意味着此clone()
应该像vfork()
,子进程在与父进程相同的内存空间中运行直到execve()
调用。
这种方法避免了使用中间可执行文件时的延迟 – 这非常重要 – 但这种方法完全取决于Linux。