Linux unshare / nsenter 的用户态 namespace 创建与进入技巧

4次阅读

unshare 创建新 Namespace 后 ps 看不到进程隔离,因其默认不切换当前进程视图;需加 –fork 并配合 bash 等命令使新进程在新 pid namespace 中启动,且 user ns 需正确映射 uid 并禁用 setgroups。

Linux unshare / nsenter 的用户态 namespace 创建与进入技巧

unshare 创建新 namespace 后为什么 ps 看不到进程隔离?

因为 unshare 默认只创建 namespace,不切换当前进程的视图——它仍运行在原 PID namespace 中,只是获得了新 namespace 的“所有权”。要真正看到隔离效果,必须配合 --fork 和后续命令(如 bash),让新进程在新 namespace 中启动。

常见错误现象:unshare --user --pid --mount /bin/bash 进入后执行 ps aux 仍能看到宿主机所有进程。这是因为没加 --forkbash 还在原 PID namespace 里运行。

  • unshare --user --pid --fork --mount /bin/bash 才能让 bash 成为新 PID namespace 的 1 号进程
  • --user 必须搭配 --map-root-user 或手动写 /proc/self/uid_map,否则非 root 用户无法映射 UID,导致 setuid 失败、多数命令拒绝执行
  • --mount 单独用没意义:新 mount namespace 默认继承父视图,得立刻 mount --make-privatemount 新文件系统,否则挂载操作会泄漏到外部

nsenter 进入已有进程的 namespace 时权限不足怎么办?

nsenter 本质是打开目标进程的 /proc/PID/ns/XXX 文件并 setns(),所以核心限制就两条:能否读取 /proc/PID/ns/ 下的文件,以及是否有对应 namespace 的操作权限(比如进入 user ns 需 CAP_SYS_ADMIN 或已映射 UID)。

典型报错:nsenter: failed to open /proc/1234/ns/pid: Permission denied

  • 普通用户默认无法读取其他用户的 /proc/PID/ns/,哪怕 PID 是自己的子进程——除非该进程设置了 PR_SET_DUMPABLE(很多容器 runtime 会设)
  • 进 user namespace 前,必须先进 pid+mnt+uts 等“非特权” namespace,否则内核拒绝切换(顺序敏感!)
  • 推荐组合:nsenter -t 1234 -m -u -i -n -p /bin/bash,其中 -i 是 user ns,-p 是 pid ns;漏掉 -p 就会卡在 “can’t change process namespace”

user namespace 映射不生效,id 还显示 root?

user namespace 不等于自动获得 root 权限,它只是提供 UID/GID 映射能力。映射是否生效,取决于三件事:是否写了 uid_map、是否关闭了 setgroups、当前进程是否在该 user ns 内。

现象:进了 unshare 的 user ns,id -u 还是 0,但 touch /tmp/testOperation not permitted

  • 必须向 /proc/self/uid_map 写入映射,例如:echo "0 1000 1" > /proc/self/uid_map(把 host UID 1000 映射为 ns 内 UID 0)
  • uid_map 前必须先写 /proc/self/setgroupsdeny,否则内核拒绝写 uid_map(安全强制)
  • 映射只对当前进程及其 fork 出的子进程有效;如果用 exec bash 替换 shell,需确保 bash 是 fork 后 exec 的,而不是另起一个未映射的进程

为什么 nsenter 进去后 ls /proc 看不到其他进程?

因为 /proc 是伪文件系统,它的内容由内核按当前进程所处的 PID namespace 动态生成。你用 nsenter -t 1234 -p 进入某个进程的 PID namespace 后,/proc 就只显示该 namespace 内的进程——这是正确行为,不是 bug

但要注意:如果只进 PID namespace,没进 mount namespace,/proc 路径本身可能还是挂载在宿主机的 procfs 上(即看到的是宿主机 PID 视图)。必须同时指定 -m 才能确保看到该 PID namespace 对应的 /proc 实例。

  • 安全做法:nsenter -t 1234 -m -p -u -n -i /bin/bash,五连进保证上下文完整
  • 进完立刻检查:cat /proc/self/status | grep NSpid,确认 NSpid 字段存在且值合理(比如第一个是 1)
  • 别依赖 ps:它可能从宿主机 /proc 读取,优先用 ls /proc/[0-9]*cat /proc/sys/kernel/ns_last_pid 验证 PID namespace 是否真生效

事情说清了就结束。namespace 的嵌套、跨 namespace 信号传递、cgroup 关联这些,都得在 map 和 mount 都稳住之后才谈得上。

text=ZqhQzanResources