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.
当您提供 --pid
时 unshare
实际做的是将当前进程的 /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)的信息,您要做的第一件事就是阅读每个名称空间的手册页。写得很好,信息量很大。
我正在学习 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.
当您提供 --pid
时 unshare
实际做的是将当前进程的 /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)的信息,您要做的第一件事就是阅读每个名称空间的手册页。写得很好,信息量很大。