【发布时间】:2019-10-01 17:42:35
【问题描述】:
我正在尝试实现一个容器,为此我使用带有适当标志的 clone(2) 系统调用来创建一个进程:
if ((child_pid = clone(child_main, process_struct.Stack + process_struct.StackPtr,
CLONE_NEWCGROUP
|CLONE_NEWIPC
|CLONE_NEWNET
|CLONE_NEWNS
|CLONE_NEWPID
|CLONE_NEWUTS
|SIGCHLD, &process_struct, checkpoint)) == -1){
fprintf(stderr,"Failed...%m \n");
exit(EXIT_FAILURE);
}else{
fprintf(stderr,"Done\n");
waitpid(child_pid, NULL, 0);
}
在 child_main() 中我更改了进程命名空间的主机名,还设置了挂载命名空间,我在分区上安装了 Linux 文件系统层次结构,就像普通的 Linux 安装一样(我这样做是为了创建一个干净的文件系统映像清理我的文件和二进制文件),然后将传播类型设置为 MS_UNBINDABLE,然后我使用 pivot_root(2) 更改进程的根目录。
const int child_main(struct process *process_struct, int *checkpoint){
char c;
fprintf(stderr,"=> IPC setup...");
//double check the IPC
close(checkpoint[1]);
fprintf(stderr,"Done\n");
if ( sethostname(process_struct->Hostname,
strlen(process_struct->Hostname)) || mounting(process_struct)){
return -1;
}
// startup the IPC pipes
read(checkpoint[0], &c, 1);
if(execve("/bin/bash", (char*)0, NULL) == -1 ){
fprintf(stderr,"--> Launching process Failed %m\n");
return -1;
}
return 0;
}
问题是我的系统通过了 execve(2) 并且没有启动 /bin/bash 并且程序没有错误地运行。当我在 execve(2) 之前添加 system(2) 语句时:system("ls"); 它列出了适当的文件系统和当前工作目录。此外,当我将 execve(2) 参数更改为:
execve("/bin/ls", (char*)0, NULL) 或 execve("/bin/pstree", (char*)0, NULL) 或任何其他参数将返回错误:没有这样的文件或目录或通过 exec 系统调用传递了 NULL argv[0],当我在 execve(2) 系统调用中对我的程序进行 strace 时,它会给出:NULL, 0, NULL) = 17992
该错误与文件系统映像无关,我已经执行了更多测试并且如下所示,我将系统的文件系统用于挂载命名空间,而不是我安装在分区上并运行 /bin/bash 的文件系统'仍然不起作用,我创建了一个简单的 C 程序并编译它,它运行良好,所以有一些错误阻止执行 bin/bash,为了进一步测试这些结果,我将我的文件系统重用于我的挂载命名空间将相同的可执行文件首先移动到"/" 下的文件系统,然后移动到相同路径下的第二个文件系统
我的可执行文件的主系统路径= /home/omar/docs/test.out
我从分区路径到可执行文件的挂载文件系统= /home/omar/docs/test.out
因为我想检查在向每个可执行文件中添加语句时相同的路径是否会引起混淆,因此可以判断我的程序采用了哪个路径,并且它运行良好,没有任何问题并且按预期正确,所以问题只是那个系统基本命令将不起作用。
【问题讨论】:
-
execve()的第二个参数不能是空指针,它必须是指向以空结尾的数组的指针。 -
并且该数组至少需要一个元素,
argv[0]必须是程序的名称。 -
第三个参数也必须是指向数组的指针,而不是
NULL。 -
你真的希望子进程有空的环境变量吗?如果不需要指定环境,并且希望它继承当前环境,使用
execv而不是execve。 -
应该是
char *argv[] = {"/bin/bash",(char*)0};
标签: c linux namespaces