'unshare'在C api中无法正常工作

Ric*_*ico 20 c linux linux-namespaces

这一系列命令有效:

unshare --fork --pid --mount 
umount /proc
mount -t proc proc /proc
umount /dev/pts
mount -t devpts devpts /dev/pts
Run Code Online (Sandbox Code Playgroud)

但是,相应的C程序没有按预期工作(似乎它没有卸载以前的/ proc,并且它还提供了尝试卸载devpts的EBUSY):

unshare(CLONE_NEWPID | CLONE_NEWNS );
int pid = fork();
if (pid != 0) {
    int status;
    waitpid(-1, &status, 0);
    return status;
}

printf("My pid: %i\n", getpid()); // It prints 1 as expected

umount("/proc"); // Returns 0

system("mount"); // Should print error on mtab, but it prints the previous mounted filesystems

mount("proc", "/proc", "proc",
      MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV,
      NULL));  // Returns 0

umount("/dev/pts");  // Returns -1 errno = 0 (??)

mount("devpts", "/dev/pts", "devpts", 
      MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_NODEV,
      NULL) ); // Returns -1 errno = EBUSY
Run Code Online (Sandbox Code Playgroud)

我在这里省略了错误检查的可读性

我认为unshare或unmount不能按预期工作:即使它返回零,似乎没有卸载/ proc(如果我尝试执行一个system("mount")后,它打印已挂载的文件系统).

Ric*_*ico 1

我在检查unshare 命令的源代码时发现了问题。必须在有它们的/proc情况下卸载MS_PRIVATE | MS_REC并在没有它们的情况下安装,这本质上是为了确保安装仅在当前(新)命名空间中有效。第二个问题是不可能在/dev/pts不对全局命名空间产生影响的情况下卸载(这是由 devpts 驱动程序的内部例程引起的)。要拥有私有 /dev/pts ,唯一的方法是使用专用-o newinstance选项挂载它。最后/dev/ptmx还应该重新绑定。

因此,这是预期的 C 工作代码:

unshare(CLONE_NEWPID | CLONE_NEWNS );
int pid = fork();
if (pid != 0) {
    int status;
    waitpid(-1, &status, 0);
    return status;
}

printf("New PID after unshare is %i", getpid());

if (mount("none", "/proc", NULL, MS_PRIVATE|MS_REC, NULL)) {
    printf("Cannot umount proc! errno=%i", errno);
    exit(1);
}

if (mount("proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL)) {
    printf("Cannot mount proc! errno=%i", errno);
    exit(1);
}


if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL | MS_NOSUID | MS_NOEXEC, "newinstance") ) {
    printf("Cannot mount pts! errno=%i", errno);
    exit(1);
}

if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_MGC_VAL | MS_NOSUID | MS_NOEXEC | MS_BIND, NULL) ) {
    printf("Cannot mount ptmx! errno=%i", errno);
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)