登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux user namespace 怎么判断权限映射是否生效:uid_map、gid_map 与容器内核边界

来源:17golang原创

时间:2026-08-26 11:08:10 411浏览 收藏

在容器或沙箱里执行 id 看到 uid=0(root),并不能直接说明进程拥有宿主机的 root 权限。真正要看的,是这个 user namespace 的身份映射是否已经写入,以及映射到父 namespace 的哪一段 UID/GID。最实用的核验顺序是:先读 /proc/self/uid_map/proc/self/gid_map,再确认 setgroups 状态,最后用一个受控文件的属主读写结果交叉验证。

要点速览

  • 映射表的三列依次表示 namespace 内起始 ID、父 namespace 起始 ID 和连续数量。
  • gid_map 写入前经常需要先把 /proc/self/setgroups 设为 deny,否则会得到权限错误。
  • namespace 内的 root 只在自己的身份空间里成立,不能跳过宿主机文件权限和能力检查。

先看 uid_map:root 到底映射到了谁

user namespace 新建时,UID/GID 映射默认是空的。映射稳定后,进程可以直接读取自己的三份状态:

cat /proc/self/uid_map
cat /proc/self/gid_map
cat /proc/self/setgroups

典型的单用户映射可能是:

         0       1000          1

第一列的 0 是 namespace 内的 UID,第二列的 1000 是父 namespace 中对应的 UID,第三列的 1 表示只有一个连续 ID。也就是说,namespace 内看到的 root,可能只是父 namespace 里的普通用户。

Linux user namespace 空映射与单范围 uid_map 对照,展示 namespace 内 root 到父用户的映射关系

三列映射如何判断是否写对

不要只检查第一列是否为 0。逐行核对三个条件更稳:

  1. 三个字段都是非负整数,数量字段大于 0。
  2. namespace 内的范围不能互相重叠,父 namespace 的目标范围也不能与另一行冲突。
  3. 写入完成后再次读取文件,确认实际内容与预期一致,而不是只看创建命令有没有报错。

如果只给当前用户做映射,常见形式是 0 1。如果要映射一段范围,第三列就应该反映实际连续数量,并同时检查宿主机上的 UID 范围是否可用。映射文件是一次性定义的,后续再写通常会失败,所以调试时先把目标进程和写入顺序记录清楚。

gid_map 为什么经常卡在 setgroups

GID 映射比 UID 映射多一道安全前置条件。对没有足够权限的写入者,通常要先执行:

printf 'deny\n' > /proc//setgroups
cat /proc//setgroups

确认结果是 deny 后,再写入 gid_map。这里的顺序不能反过来:先写 gid_map,常见结果是 EPERM。此外,写入者的有效 UID、创建 namespace 的进程以及父 namespace 的关系也会影响权限判断,不能把所有失败都归结为文件格式。

排查时建议保留失败现场:

set -x
cat /proc//setgroups
cat /proc//uid_map
cat /proc//gid_map
printf '0 1000 1\n' > /proc//uid_map
printf '0 1000 1\n' > /proc//gid_map

用文件属主做一次交叉验证

映射表读对了,还需要验证它在实际对象上如何呈现。可以在一个专用临时目录里创建测试文件,再分别从 namespace 内外读取:

mkdir -p /tmp/ns-map-check
touch /tmp/ns-map-check/probe
stat -c '%u:%g %n' /tmp/ns-map-check/probe
id

如果 namespace 内显示的属主与父 namespace 看到的数字不同,不要马上判定为异常,这正是 ID 转换的表现。真正需要警惕的是:映射表为空、文件显示为无效 ID,或者你以为映射了整段范围,实际只写进了一行单用户映射。

Linux user namespace 核验路径,从 setgroups 到 uid_map、gid_map 再到文件属主检查

它和容器权限边界是什么关系

user namespace 解决的是身份编号和部分能力归属问题,不等于自动获得所有宿主机资源权限。某个 namespace 由哪个 user namespace 所拥有,会影响能力检查;文件系统、挂载、网络和设备访问仍有各自的权限边界。看到 namespace 内的 root 后,仍应检查挂载目录是否可写、设备节点是否暴露,以及宿主机文件的实际 UID/GID。

在容器运行时里,映射通常由运行时负责生成。手工写映射适合做最小复现和故障定位,不建议在生产容器里绕过运行时自行改动。尤其是多个 namespace 联动时,先确认 user namespace,再确认 mount、PID 或 network namespace 的拥有关系,排错会更快。

常见问题

uid_map 为空是不是创建失败了?

不一定。新 user namespace 初始就是空映射,创建成功与映射完成是两个阶段。只要后续按权限规则写入并重新读取即可。

为什么 uid_map 能写,gid_map 却返回 EPERM?

优先检查 /proc//setgroups 是否已经写入 deny,再核对写入者和创建者的有效身份。GID 映射额外受 setgroups 安全限制。

namespace 内 root 能删除宿主机任意文件吗?

不能这样推断。它只能在映射和资源权限允许的范围内操作;挂载、文件属主、能力和运行时配置都会继续限制结果。

最后核对清单

  • 读取并保存 uid_map、gid_map、setgroups 的实际内容。
  • 逐行核对三列含义、范围和写入顺序。
  • 用受控文件的 stat 结果从 namespace 内外交叉检查。
  • 把 namespace 内的 root 当作局部身份,不把它等同于宿主机 root。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>