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
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.
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.
--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.