答案1
明显的矛盾来自于文章中对用户命名空间层次结构的遗漏。引用联机帮助页:
用户命名空间可以嵌套;也就是说,每个用户命名空间(初始(“根”)命名空间除外)都有一个父用户命名空间,并且可以有零个或多个子用户命名空间。父用户命名空间是通过调用创建用户命名空间的进程的用户命名空间
unshare(2)
或者clone(2)
与CLONE_NEWUSER
旗帜。
在本文中,进程 D 是用户命名空间 2 的一部分,该命名空间嵌套在用户命名空间 1 内。单个进程属于单个用户命名空间,但该用户命名空间嵌套在其连续的父命名空间内,一直到根命名空间。
进程可以从多个用户命名空间可见;特别是,所有进程从最顶层的用户命名空间(或者如果您愿意,从所有用户命名空间外部)都是可见的。附加到进程的用户 id 会根据从中查询它们的用户命名空间以及每个用户命名空间中使用的 uid/gid 映射来更改值,这就是本文试图阐述的要点。
例如,您可以通过启动运行的无根容器来看到这一点bash
;ps
然后容器内会显示
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 12024 3196 pts/0 Ss 13:49 0:00 /bin/bash
但是相同的 bash
过程将显示为
skitt 23345 0.0 0.0 12024 3208 pts/0 Ss+ 15:49 0:00 /bin/bash
容器外。/proc/.../uid_map
显示正在使用的 uid 映射:
$ cat /proc/23345/uid_map
0 1000 1
1 624288 65536
这意味着uid的“范围”从0到0里面相应的用户命名空间映射到我查询的用户命名空间中的1000,并且从1到65536的范围映射到624288–689823。
答案2
经过一番头痛之后,我想我已经有了一些答案。每个过程确实是一部分正好一个用户命名空间(如此处确认的),文章中的图片准确地描绘了它。除了init之外,进程也是由其他进程创建的。当进程创建子进程时,它可以选择将子进程分配给新的用户命名空间,该命名空间也称为父进程用户命名空间的“子命名空间”。
所谓UID(用户ID)和GID(组ID)映射使进程的 UID 和 GID 成为可能出现从另一个命名空间检查时会有所不同。映射很重要,因为进程可能会修改系统上其他命名空间的进程想要访问的文件,并且它们还希望从命名空间外部查看这些文件上有意义的 UID 或 GID。
映射 UID(与 GID 相同)的工作原理是获取创建新命名空间的进程的 UID,将其与/proc/<Process_ID>/uid_map
新命名空间中的新进程进行匹配并分配映射的 UID。如果在创建新用户命名空间时未指定映射,则新命名空间中的进程 UID 将采用值。有关/proc/sys/kernel/overflowuid
如何定义此类映射的更多详细信息,请参阅这篇 LWN 文章。