namespaceslinux-namespaces

unshare command doesn't create new PID namespace


I'm learning linux core and I'm on the namepsaces topic now. I tried to play with "unshare" command just to get hang of namespace and its essentials. The problem is that it doesn't or, what is more probable, I'm doing something wrong. I'd appreciate if you could help me to understand. I try to execute busybox sh program as within its own PID namespace. That's what I do:

[ab@a ~]$ sudo unshare --pid  busybox sh
/home/ab # ps
PID TTY          TIME CMD
6014 pts/1    00:00:00 sudo
6016 pts/1    00:00:00 busybox
6026 pts/1    00:00:00 ps

So as I can see it from the output of the ps command all process are visible in the new env. And it gets confirmed when I check pid namespace id of newly created process and current one. See below

[ab@a ~]$ ps -p 6016,$$
PID TTY          TIME CMD
4604 pts/0    00:00:00 bash
6016 pts/1    00:00:00 busybox
[ab@a ~]$ sudo ls -l /proc/4604/ns
total 0
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 net -> net:[4026531968]
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 pid -> pid:[4026531836]
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 user -> user:[4026531837]
lrwxrwxrwx. 1 ab ab 0 Aug  8 23:49 uts -> uts:[4026531838]
[ab@a ~]$ sudo ls -l /proc/6016/ns
total 0
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 net -> net:[4026531968]
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 Aug  9 00:07 uts -> uts:[4026531838]

So, pid namespace stays the same eventhough I provided --pid argument to unshare call. Could you please help me to understand why it happens. Thanks


Solution

  • Solution

    you should add --fork and --mount-proc switch to unshare as stated in the man page

    -f, --fork
              Fork the specified program as a child process of unshare rather than running it directly. This is useful
              when creating a new PID namespace. Note that when unshare is waiting for the child process, then it
              ignores SIGINT and SIGTERM and does not forward any signals to the child. It is necessary to send
              signals to the child process.
    

    Explanation (from man pid_namespaces)

    a process's PID namespace membership is determined when the process is created and cannot be changed thereafter.

    what unshare actually does when you supply --pid is setting the file descriptor at /proc/[PID]/ns/pid_for_children for the current process to the new PID namespace, causing children subsequently created by this process to be places in a different PID namespace (its children not itself!! important!).

    So, when you supply --fork to unshare, it will fork your program (in this case busybox sh) as a child process of unshare and place it in the new PID namespace.

    Why do I need --mount-proc ?

    Try running unshare with only --pid and --fork and let's see what happen.

    wendel@gentoo-grill ~ λ sudo unshare --pid --fork busybox sh
    /home/wendel # echo $$
    1
    /home/wendel # ps
    PID   USER     TIME  COMMAND
    12443 root      0:00 unshare --pid --fork busybox sh
    12444 root      0:00 busybox sh
    24370 root      0:00 {ps} busybox sh
    .
    .
    . // bunch more
    

    from echo $$ we can see that the pid is actually 1 so we know that we must be in the new PID namespace, but when we run ps we see other processes as if we are still in the parent PID namespace.

    This is because of /proc is a special filesystem called procfs that kernel created in memory, and from the man page.

    A /proc filesystem shows (in the /proc/[pid] directories) only processes visible in the PID namespace of the process that performed the mount, even if the /proc filesystem is viewed from processes in other namespaces.

    So, in order for tools such as ps to work correctly, we need to re-mount /proc using a process in the new namespace.

    But, assuming that your process is in the root mount namespace, if we re-mount /proc, this will mess up many things for other processes in the same mount namespace, because now they can't see anything (in /proc). So you should also put your process in new mount namespace too.

    Good thing is unshare has --mount-proc.

    --mount-proc[=mountpoint]
              Just before running the program, mount the proc filesystem at mountpoint (default is /proc). This is useful when creating a new PID namespace. It also implies creating a new mount namespace since the /proc mount would
              otherwise mess up existing programs on the system. The new proc filesystem is explicitly mounted as private (with MS_PRIVATE|MS_REC).
    

    Let's verify that --mount-proc also put your process in new mount namespace.

    bash outside:

    wendel@gentoo-grill ~ λ ls -go /proc/$$/ns/{user,mnt,pid}
    lrwxrwxrwx 1 0 Aug  9 10:05 /proc/17011/ns/mnt -> 'mnt:[4026531840]'
    lrwxrwxrwx 1 0 Aug  9 10:10 /proc/17011/ns/pid -> 'pid:[4026531836]'
    lrwxrwxrwx 1 0 Aug  9 10:10 /proc/17011/ns/user -> 'user:[4026531837]'
    

    busybox:

    wendel@gentoo-grill ~ λ doas ls -go /proc/16436/ns/{user,mnt,pid}
    lrwxrwxrwx 1 0 Aug  9 10:05 /proc/16436/ns/mnt -> 'mnt:[4026533479]'
    lrwxrwxrwx 1 0 Aug  9 10:04 /proc/16436/ns/pid -> 'pid:[4026533481]'
    lrwxrwxrwx 1 0 Aug  9 10:17 /proc/16436/ns/user -> 'user:[4026531837]'
    

    Notice that their user namespace is the same but mount and pid aren't.

    Note: You can see that I cited a lot from man pages. If you want to learn more about linux namespaces (or anything unix really) first thing for you to do is to read the man page of each namespace. It is well written and really informative.