unshare --pid/bin/bash - fork无法分配内存

Mat*_*att 12 linux bash linux-namespaces

我正在尝试使用linux命名空间.特别是pid命名空间.

我以为我用bash测试了一些东西但遇到了这个问题:

unshare -p /bin/bash
bash: fork: Cannot allocate memory
Run Code Online (Sandbox Code Playgroud)

从那里运行ls给了一个核心转储.退出是唯一可能的事情.

它为什么这样做?

yup*_*921 18

该错误是由新的命名空间中的PID 1进程退出引起的.

在bash开始运行之后,bash将分叉几个新的子进程来做事.如果在没有-f的情况下运行unshare,bash将具有与当前"unshare"进程相同的pid.当前的"unshare"进程调用unshare systemcall,创建一个新的pid命名空间,但当前的"unshare"进程不在新的pid命名空间中.这是linux内核的理想行为:进程A创建一个新的命名空间,进程A本身不会被放入新的命名空间,只有进程A的子进程将被放入新的命名空间.所以当你跑:

unshare -p /bin/bash

unhare进程将执行exec/bin/bash,而/ bin/bash会分叉几个子进程,bash的第一个子进程将成为新命名空间的PID 1,子进程将在完成其作业后退出.所以新命名空间的PID 1退出.

PID 1进程具有特殊功能:它应该成为所有孤立进程的父进程.如果根命名空间中的PID 1进程退出,则内核将发生混乱.如果子命名空间中的PID 1进程退出,则linux内核将调用disable_pid_allocation函数,该函数将清除该命名空间中的PIDNS_HASH_ADDING标志.当linux内核创建一个新进程时,内核将调用alloc_pid函数在命名空间中分配PID,如果未设置PIDNS_HASH_ADDING标志,则alloc_pid函数将返回-ENOMEM错误.这就是你得到"无法分配内存"错误的原因.

您可以使用'-f'选项解决此问题:

unshare -fp /bin/bash

如果使用'-f'选项运行unshare,unshare将在创建新的pid命名空间后派生一个新进程.并在新进程中运行/ bin/bash.新进程将是新pid命名空间的pid 1.然后bash还会分叉几个子进程来做一些工作.由于bash本身是新pid命名空间的pid 1,因此其子进程可以毫无问题地退出.

  • 用一些手册页参考来支持这个非常有用的答案:[`man 2 unshare`](http://man7.org/linux/man-pages/man2/unshare.2.html) 说到`CLONE_NEWPID`:_Unshare PID 命名空间,以便调用进程为其子进程拥有一个新的 PID 命名空间,该命名空间不与任何先前存在的进程共享。调用进程不会移动到新的命名空间中。**调用进程创建的第一个子进程的进程 ID 为 1**,并将在新命名空间中承担 init(1) 的角色。_ (2认同)

hek*_*mgl 7

这并不能解释为什么会发生这种情况,但是显示了如何在新的pid名称空间中正确启动shell:

使用该-f标志从unshare以下位置派生shell :

unshare -fp /bin/bash
Run Code Online (Sandbox Code Playgroud)

您还需要传递该--mount-proc选项以确保外壳程序将在新创建的命名空间中获得PID 1:

unshare -fp --mount-proc /bin/bash
Run Code Online (Sandbox Code Playgroud)

现在运行ps

# ps
   PID TTY          TIME CMD
 1 pts/1    00:00:00 bash
11 pts/1    00:00:00 ps
Run Code Online (Sandbox Code Playgroud)