【问题标题】:execve(2) system commands exit before executionexecve(2) 系统命令在执行前退出
【发布时间】: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


【解决方案1】:

您需要将正确的argv 数组传递给execve。如果你只想传递当前环境,请使用execv 而不是execve

char *argv[] = {"bash", NULL};
if(execv("/bin/bash", argv) == -1 ){
    perror("execv");
    return -1;
}

【讨论】:

  • 进程仍然没有做任何事情就死掉了。
  • 它的标准输入是怎么连接的?也许它正在读取 EOF 并正常退出。
  • 与原始问题相同。
  • 现在我正在制作可执行文件和参数字符串作为问题,所以没有输入,如果这是一个不相关的答案告诉我如何测试我的标准输入连接,当我添加任何a.out 可执行文件到我的挂载命名空间,它工作得很好,没有任何问题。
  • 所以这适用于随机的a.out,但不适用于/bin/bash
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-26
  • 2017-12-02
  • 1970-01-01
  • 2021-09-07
  • 2011-03-12
  • 2011-03-29
相关资源
最近更新 更多