1

I've to join a process to a new namespace, so i'm extracting the namespace fd's of a process, so that it can call setns on those fd's.

But the problem is all returned fd's are -1s.

I did this:

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 are declared paths. How can i resolve this ?

EDIT1: on printing stderror it says permission denied On doing sudo chmod 755 on whole proc filesystem it prints operation not permitted

EDIT2: I was doing the mistake the of not compiling and running the executable with sudo. This time it can open the fds and returned fds are all positive. Similar to above i've opened other namespace fds too like usr_fd to join user namespace, ipc_fd to join ipc namespace and uts_fd to join uts namespace of the target process, but when doing setns on userfd it is givng error of Invalid argument. Below is the code i've written to join namespaces.

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);                                                                                        
    }

I wanted the child process to execute the getcode program in that namespace but it is not doing so? If it is the wrong way to do this, then how can the child run a program in that namespace?

mycode.cpp

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

EDIT3: However replacing below line:

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

with this

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

works.

user13145713
  • 109
  • 8

1 Answers1

0

In short, you need the CAP_SYS_PTRACE capability to access namespace references (and several other things) inside the /proc process filesystem, including the namespace-related subparts coming from the nsfs namespace filesystem inside procfs. Here, CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE are only part of the game. Depending on your exact deployment they might be needed, when running as non-UID0 with limited capabilities.

Running as root usually grants you all capabilities, including CAP_SYS_PTRACE. A non-UID0 process can be granted access by giving it the bounded, permitted, and not least effective CAP_SYS_PTRACE capability (-ies).

One way to do this is to set the ("POSIX") file capabilities using the setcap CLI tool. As usual, with great power comes great responsibility, so make sure to properly harden your binary so it cannot be used as a trampoline to gain forbidden system access.

TheDiveO
  • 2,183
  • 2
  • 19
  • 38