这一系列命令起作用:
unshare --fork --pid --mount
umount /proc
mount -t proc proc /proc
umount /dev/pts
mount -t devpts devpts /dev/pts但是,相应的C程序不像预期的那样工作(它似乎没有卸载以前的/proc,而且它还提供了尝试卸载开发文件的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我在这里省略了对可读性的错误检查
我认为卸载或卸载不像预期的那样工作:即使它返回零,似乎也没有卸载/proc (如果我在之后尝试执行一个system("mount"),它会打印已安装的文件系统)。
发布于 2016-01-30 21:48:27
我发现了检查取消共享命令的源代码的问题。/proc必须使用MS_PRIVATE | MS_REC卸载并在没有它们的情况下挂载,这基本上是为了确保挂载只在当前(新)命名空间中有效。第二个问题是,如果不对全局命名空间产生影响,就不可能对/dev/pts产生影响(这是由devpts驱动程序的内部例程造成的)。要拥有私有/dev/ it,唯一的方法是使用专用的-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);
}发布于 2016-01-27 19:24:06
尽管你的评论
“有时”
umount返回0“有时”-1,但最终它根本不卸载/proc。
在您的pastebin代码的10000次试用中,umount()总是为我失败,返回-1而不是卸载/proc。我不相信umount()会返回0,尽管它没有执行所请求的卸载,但是如果它执行了,那么这将构成umount()中的一个bug。如果你真的能证实这样的错误,那么有社区意识的反应将是针对glibc提交一个bug报告。
然后,问题就变成了为什么以及您的bash脚本的行为是如何不同的。然而,事实上,似乎并没有这样做。
首先,您对unshare(1)命令有错误的期望。与unshare(2)函数不同,unshare命令不影响执行它的shell。相反,它启动一个单独的进程,该进程拥有自己指定名称空间的私有副本。通常,您将指定在unshare命令行上启动该进程的命令,实际上,程序的手册页表明这样做是强制性的。
根据经验,我发现如果我没有指定这样的命令--正如您所做的--那么unshare启动一个新的shell作为目标进程。特别是,当我运行您的脚本(有足够的权限使用unshare)时,我立即得到一个新的提示符,但它是在前台运行的新shell的提示。这一点在我看来是显而易见的,因为提示符是不同的(但是,在这种情况下,您的提示可能没有什么不同)。此时没有来自umount的错误消息等,因为它还没有运行。如果我在( umount d)子subshell中手动尝试unshare proc,它就会失败,因为“设备很忙”--这是C程序试图做的事情的模拟。
当我退出子subshell时,脚本的其余部分会运行,umount和mount都会失败。这是意料之中的,因为主脚本共享其挂载命名空间。
完全可信的是,/proc真的很忙,因此不能卸载,即使对于具有挂载命名空间的私有副本的进程也是如此。很可能这样的过程本身就是使用/proc挂载的私有副本。相反,我发现我可以在一个进程中成功地卸载带有未共享的挂载命名空间的/dev/pts,但不能在共享该命名空间的系统副本的进程中卸载。
发布于 2016-01-27 16:38:12
我认为问题在于这个系统(“挂载”),它产生了一个外壳,并且没有携带到umount。尝试在umount之后在/proc/中打开一个文件,并看到它按预期工作。
看这个-
unshare(CLONE_NEWPID | CLONE_NEWNS );
int rc = 0;
int pid = fork();
if (pid != 0) {
int status;
waitpid(-1, &status, 0);
return status;
}
printf(">>> My pid: %d\n", getpid()); // It prints 1 as expected
rc = umount2("/proc", MNT_FORCE); // Returns 0
printf(">>> umount returned %d. errno = %d, desc = (%s)\n", rc, errno, strerror(errno));
rc = open("/proc/cpuinfo", O_RDONLY);
printf(">>> open returned %d. errno = %d, desc = (%s)\n", rc, errno, strerror(errno));https://stackoverflow.com/questions/34872453
复制相似问题