1. pidNamespace
什么是pidNamespace
pid是什么?
为了让每个进程human readable。每个进程都有一个pid(当然在linux里面进程和线程分的并没有那么大)。他是某个系统的一个唯一标识符。
pidNamespace是什么
man page 如是说
PID namespaces isolate the process ID number space, meaning that processes in different PID namespaces can have the same PID.
pidNamespace 的应用
单一的系统中,没有什么特别用处,因为可以直接通过pid的自增来进行区分。
应用在于有一个容器需要从机器A迁移到机器B,(这里所说的机器的学名大概是是所谓host),这时候需要pid namespace来进行区分
pid = 1 的特性
pid=1(又名init process) 的进程有一些特性,比如杀了进程树的进程节点后,其子节点会以pid=1为根(他是总根)而杀了pid=1的进程本身,pidNamespace也会随之消失
探索pidNamespace
pidNamespace是单向可视的
一个性质(略)
pidNamespace 需要和其他的搭配使用(比如mount namespace和user namespace)
一个实验
unshare -p /bin/bash
The error is caused by the PID 1 process exits in the new namespace.
After bash start to run, bash will fork several new sub-processes to do somethings. If you run unshare without -f, bash will have the same pid as the current "unshare" process. The current "unshare" process call the unshare systemcall, create a new pid namespace, but the current "unshare" process is not in the new pid namespace. It is the desired behavior of linux kernel: process A creates a new namespace, the process A itself won't be put into the new namespace, only the sub-processes of process A will be put into the new namespace. So when you run:
unshare -p /bin/bash
The unshare process will exec /bin/bash, and /bin/bash forks several sub-processes, the first sub-process of bash will become PID 1 of the new namespace, and the subprocess will exit after it completes its job. So the PID 1 of the new namespace exits.
The PID 1 process has a special function: it should become all the orphan processes' parent process. If PID 1 process in the root namespace exits, kernel will panic. If PID 1 process in a sub namespace exits, linux kernel will call the disable_pid_allocation function, which will clean the PIDNS_HASH_ADDING flag in that namespace. When linux kernel create a new process, kernel will call alloc_pid function to allocate a PID in a namespace, and if the PIDNS_HASH_ADDING flag is not set, alloc_pid function will return a -ENOMEM error. That's why you got the "Cannot allocate memory" error.
You can resolve this issue by use the '-f' option:
unshare -fp /bin/bash
If you run unshare with '-f' option, unshare will fork a new process after it create the new pid namespace. And run /bin/bash in the new process. The new process will be the pid 1 of the new pid namespace. Then bash will also fork several sub-processes to do some jobs. As bash itself is the pid 1 of the new pid namespace, its sub-processes can exit without any problem.
(摘自:https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory)
首先,创建new namespace的进程不会被纳入新的,namespace中。这是linux kernel的规则。
此时梳理一下/bin/bash干了些什么,/bin/bash将会fork一些子进程,处理好一些事务以后,那些子进程会结束自己。
unshare -p /bin/bash 会导致unshare进程本身exec了/bin/bash(注意是exec不是fork)。但是根据内核的规则,它是留在进程外面的。于是/bin/bash fork的第一个子进程变成了新namespace中pid=1的进程。后来那些子进程挨个结束自己。所以出现了,pid=1的进程把自己结束了的事情。
还是根据kernel规则(简单搜索PID 1的特性即可了解) PID 1 进程会成为所有孤儿的父进程,如果PID 1自己退出了的话。linux kernel就会十分困惑。此时linux kernel就会调用disable_pid_allocation程序,它将会clean掉相应namespace的PIDNS_HASH_ADDING flag。
而当linux kernel调用新进程的时候,就会,当这个flag没有被设置就会返回一个-ENOMEM 错误,所以就是“cannot allocate memory”错误了。
解决方案是unshare创建namespace,由/bin/bash成为pid=1
因此解决方案是
unshare -pf /bin/bash
ps -al
再探pid Namespace
unshare -pf /bin/bash
ps -ef
e 是 所有进程
f 是 output 中full format
为什么会这样呢?
因为是从ps是从/proc中导入进来的。挂载没变,进程清单也没变。
真的改变了么?
真的改变了,因为,因为此时kill -9 一个namespace以外的程序,会发现它无法执行。
如何才能让他ok呢?
unshare 时再带一个mount_namespace
这样就好了。
但是这样就麻了....
如果不小心让子进程搞到了root权限,还是暴露了。这可怎么办呢。。不知道诶。(root权限当然想做什么做什么了。。谁会在意umount呢?笑死(
和 unprivileged users 的关系
“user and mnt namespace 可以通过regular user搞出来,但是呢 pid namespace 则是不可以的。”
麻了,好像不可以哦。
这个确实不可以呢。
已知不是nobody的非权限用户可以搞出user namespace 和 mnt namespace 不过呢。pid namespace 应该是完全不行的。
如果可以的话怎么办呢?可以通过那什么。。。unshare -Urmpf 来实现。雾
总结
在容器日益流行化的今天,pidnamespace 隔离了 pid space,使得不同pid可以有相同的pid。
When combined with the user and mnt namespaces, the PID namespace provides a great deal of protection without requiring root privileges. Modern browsers such as Firefox and Vivaldi make use of namespaces to provide browser sandboxing.
In the next article, I'll demonstrate the net namespace and see how you can continue to construct your container by hand by adding in discrete network components.
[1] https://www.redhat.com/sysadmin/pid-namespace
[2] https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?