unshare 命令不会创建新的 PID 命名空间

unshare command doesn't create new PID namespace

我正在学习 linux 核心,我现在正在学习 namepsaces 主题。 我尝试使用“unshare”命令只是为了了解名称空间及其要点。 问题是它没有,或者更有可能的是,我做错了什么。 如果你能帮助我理解,我将不胜感激。 我尝试在它自己的 PID 命名空间中执行 busybox sh 程序。我就是这样做的:

[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

因此,正如我从 ps 命令的输出中看到的那样,所有进程在新环境中都是可见的。当我检查新创建的进程和当前进程的 pid 命名空间 ID 时,它得到确认。见下文

[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]

因此,尽管我为 unshare 调用提供了 --pid 参数,但 pid 命名空间保持不变。 你能帮我理解为什么会这样吗? 谢谢

解决方案

您应该添加 --fork 并将 --mount-proc 切换到 unshare,如手册页中所述

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

当您提供 --pidunshare 实际做的是将当前进程的 /proc/[PID]/ns/pid_for_children 处的文件描述符设置为新的 PID 命名空间,随后导致 children由这个进程创建的放置在不同的 PID 命名空间中(它的 children 不是它自己!!重要!)。

因此,当您将 --fork 提供给 unshare 时,它将分叉您的程序(在本例中为 busybox sh)作为取消共享的 child 进程并将其放置在新的 PID 命名空间中。

为什么我需要 --mount-proc

尝试 运行仅与 --pid--fork 取消共享,让我们看看会发生什么。

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

echo $$ 我们可以看到 pid 实际上是 1 所以我们知道我们必须在新的 PID 命名空间中,但是当我们 运行 ps 我们看到其他进程好像我们仍在 parent PID 命名空间中。

这是因为 /proc 是内核在内存中创建的一个名为 procfs 的特殊文件系统,来自手册页。

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.

因此,为了使 ps 等工具正常工作,我们需要 re-mount /proc 使用新命名空间中的进程。

但是,假设您的进程位于根挂载命名空间中,如果我们 re-mount /proc,这将对同一挂载命名空间中的其他进程造成很多混乱,因为现在它们可以看不到任何东西(在 /proc 中)。所以你也应该把你的进程也放在新的挂载命名空间中。

还好取消分享了 --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).

让我们验证 --mount-proc 是否也将您的进程放在新的挂载命名空间中。

bash外:

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]'

请注意,它们的用户命名空间相同,但 mount 和 pid 不同。

注意:你可以看到我引用了很多手册页。如果您想了解更多关于 linux 名称空间(或任何真正的 unix)的信息,您要做的第一件事就是阅读每个名称空间的手册页。写得很好,信息量很大。