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.