1

我必须将一个进程加入一个新的命名空间,所以我正在提取一个进程的命名空间 fd,以便它可以在这些 fd 上调用 setns。

但问题是所有返回的 fd 都是 -1s。

我这样做了:

cout<<mnt<<"\n"; // prints /proc/4563/ns/mnt
int mnt_fd =  open(mnt, O_RDONLY | O_CLOEXEC);      
cout<<mnt_fd<<" \n"; // prints -1


cout<<net<<"\n"; // prints /proc/4563/ns/net
int net_fd =  open(net, O_RDONLY | O_CLOEXEC);          
cout<<net_fd<<" \n"; //prints -1

cout<<pid<<"\n"; // prints /proc/4563/ns/pid
int pid_fd =  open(pid, O_RDONLY | O_CLOEXEC);
cout<<pid_fd<<" \n"; // prints -1

pid, mnt,net是声明的路径。我该如何解决这个问题?

EDIT1:在打印 stderror 时,它说permission denied On doing sudo chmod 755on whole proc filesystem 它打印operation not permitted

EDIT2:我犯了一个错误,即不使用 sudo 编译和运行可执行文件。这次可以打开fds,返回的fds都是正数。与上面类似,我也打开了其他命名空间 fd,例如 usr_fd 加入用户命名空间,ipc_fd 加入 ipc 命名空间和 uts_fd 加入目标进程的 uts 命名空间,但是在这样做setnsuserfd会出现Invalid argument. 下面是我为加入命名空间而编写的代码。

pid_t cpid = fork();
    if(cpid == 0){
       if (setns(pid_fd, 0) == -1)        /* Join pid namespace */
           cout<<"joining pid "<<strerror(errno);
       if (setns(uts_fd, 0) == -1)        /* Join uts namespace */
           cout<<"joining uts "<<strerror(errno);
       if (setns(ipc_fd, 0) == -1)        /* Join pic namespace */
           cout<<"joining ipc "<<strerror(errno);
       if (setns(usr_fd, 0) == -1)        /* Join usr namespace */
           cout<<"joining usr "<<strerror(errno);
       if (setns(net_fd, 0) == -1)        /* Join net namespace */
           cout<<"joining net "<<strerror(errno);
       if (setns(mnt_fd, 0) == -1)        /* Join mnt namespace */
           cout<<"joining mnt "<<strerror(errno);

        char *argv[] = { "sudo ./mycode",NULL };
        execve(argv[0], argv, NULL);                                                                                        
    }

我希望子进程在该命名空间中执行 getcode 程序,但它没有这样做?如果这样做是错误的方法,那么孩子如何在该命名空间中运行程序?

我的代码.cpp

int main() {
  
  printf("I am child process %d of parent %d\n", getpid(), getppid());
  while (true) {
  }
  
  return 0;
}

EDIT3:但是替换以下行:

char *argv[] = { "sudo ./mycode",NULL };
execve(argv[0], argv, NULL); 

有了这个

    char *argv[] = {"ps", NULL};  
    execvp(argv[0], &argv[0]); 

作品。

4

1 回答 1

0

简而言之,您需要CAP_SYS_PTRACE能够访问进程文件系统内的命名空间引用(和其他一些东西)/proc,包括来自 procfs 内的nsfs 命名空间文件系统的命名空间相关子部分。在这里,CAP_DAC_READ_SEARCH并且CAP_DAC_OVERRIDE只是游戏的一部分。根据您的确切部署,当作为具有有限功能的非 UID0 运行时,可能需要它们。

以 root 身份运行通常会授予您所有功能,包括CAP_SYS_PTRACE. 一个非 UID0 的进程可以通过赋予它有限的、允许的和最不重要的CAP_SYS_PTRACE能力 (-ies) 来获得访问权限。

一种方法是使用setcapCLI 工具设置(“POSIX”)文件功能。像往常一样,强大的力量伴随着巨大的责任,因此请确保适当地强化您的二进制文件,以免它被用作蹦床来获得被禁止的系统访问权限。

于 2021-10-26T13:35:08.557 回答