Re: Bug#1134639: nsenter -t 1 -m escapes mount and pid namespaces

Christian Albrecht Goeschel Ndjomouo <[email protected]> Thu, 4 Jun 2026 04:03:44 +0000
Newsgroups org.kernel.vger.util-linux
Message-ID <SJ0P220MB0541F8F40FD5C0E972BBD715E9102@SJ0P220MB0541.NAMP220.PROD.OUTLOOK.COM>
> First: {unshare -m -p -f chroot FS} will change root into that=0A> filesy=
stem with unshared mount and pid namespaces.=0A>=0A=0AThis will successfull=
y changes the root directory path of the child process,=0Ahowever, the newl=
y created mount namespace's root mount will still=0Apoint to the host's roo=
t filesystem, which is the actual root cause of the=0Aescape (it'll become =
clearer below).=0A=0A> Next: {mount -t proc proc /proc} will mount the proc=
fs for that pid=0A> namespace. We see with {ls -l /proc/1/ns/mnt} the ident=
ity of the=0A> unshared mount namespace, which is different from the identi=
ty before=0A> chroot.=0A>=0A=0AAs the mount(8) command has copied the execu=
tion context of the container=0Aprocess, it will see it's root filesystem a=
s `FS`, so the 'procfs' will be mounted=0Aon FS/proc, rightfully so. The ls=
 command is also running with that context,=0Aand will show the container's=
 mount namespace ID.=0A=0A> But: {nsenter -t 1 -m -- ls -l /proc/1/ns/mnt} =
shows the identity of=0A> the host mount namespace -- the outer namespace.=
=0A>=0A> Thus {nsenter -t 1 -m} "escapes" from the unshared namespace to th=
e=0A> containing namespace. And for example: {nsenter -t 1 -m /bin/sh}=0A> =
starts a shell in the outer mount and pid namespace(s)!=0A>=0A=0AThe reason=
 why you escaped is that when nsenter(1) calls setns(fd, CLONE_NEWNS)=0A, t=
he kernel will set the root filesystem for the calling process to the absol=
ute root of=0Athe target mount namespace. And, whatever binary it forks wil=
l now be decoupled=0Afrom the container's chroot and point back to the host=
's root filesystem. This is why=0Ayou are also able to view the host's moun=
t table or resolve paths relative to the host=0Afs while inside the contain=
er, for example, when you executed a shell with nsenter(8).=0A=0AIf you wis=
h to completely cut ties with the VFS structure of the host, you can make u=
se=0Aof pivot_root(8). It let's you set the global root mount of the mount =
namespace and truly=0Aisolates the mount namespace.=0A=0AYou can do somethi=
ng like this:=0A=0A$ unshare --mount --pid --fork=0A$ mount --bind FS FS/=
=0A$ cd FS/=0A$ mkdir -p old_root/=0A$ /sbin/pivot_root . old_root/=0A$ cd =
/=0A$ mount -t proc proc /proc=0A$ umount -l old_root/=0A$ rmdir old_root=
=0A=0AYou should then be able to see the exact same mnt namespace ID.=0A=0A=
$ ls -l /proc/1/ns/mnt=0A[...] /proc/1/ns/mnt -> 'mnt:[4026533461]'=0A$ nse=
nter --mount --target 1 -- ls -l /proc/1/ns/mnt=0A[...] /proc/1/ns/mnt -> '=
mnt:[4026533461]'=0A=0A=0AMaybe Karel has more to say about this.=0A=0AAnyw=
ays I hope this cleared up at least some of the confusion.=0A=0A=0AChristia=
n Goeschel Ndjomouo=0A=0A