在vfork()/ clone()中调用execv()之前的setuid()

我需要从服务器派生一个exec。 由于我的服务器内存占用量很大,我打算使用vfork() / linux clone() 。 我还需要为stdin / stdout / stderr打开管道。 这是clone() / vfork()允许的吗?

从标准:

[..]如果由vfork()创建的进程修改除了用于存储vfork()的返回值的pid_t类型的变量以外的任何数据,或者从调用vfork()的函数返回,则行为未定义,或在成功调用_exit()exec系列函数之前调用任何其他函数。

调用setuidpipe等函数的问题是它们可能会影响父进程和子进程之间共享的地址空间中的内存。 如果你需要在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。