此命令序列有效:

unshare --fork --pid --mount
umount /proc
mount -t proc proc /proc
umount /dev/pts
mount -t devpts devpts /dev/pts

但是,相应的C程序无法按预期运行(它似乎没有卸载先前的/proc,并且它提供EBUSY试图卸载devpts):
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

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

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

最佳答案

尽管您有评论



,在您的pastebin进行的10000次代码试用中,umount()总是对我失败,返回-1而不卸载/proc。我不敢相信umount()会返回0,尽管未能执行请求的卸载,但是如果这样做,那将构成umount()中的错误。如果实际上您可以证实这种错误,那么社区意识的回应就是针对glibc提交错误报告。

问题变成了为什么以及您的bash脚本表现不同。但是实际上,它似乎没有。

首先,您对unshare(1)命令有错误的期望。与unshare(2)函数不同,unshare命令不影响在其中执行命令的shell。相反,它将启动一个单独的进程,该进程具有自己的指定 namespace 的私有(private)副本。通常,您将在unshare命令行上指定启动该进程的命令,实际上,该程序的手册页指示这样做是强制性的。

根据经验,我发现,如果您未能指定这样的命令(如您所做的那样),那么unshare将启动一个新的Shell作为目标进程。特别是,当我运行您的脚本(具有足够的特权来使用unshare)时,我立即获得一个新的提示,但这是在前台运行的新shell的提示。这对我来说立即显而易见,因为提示有所不同(但是,在这种情况下,您的提示可能没有任何不同)。此时umount尚无错误消息等,因为它尚未运行。如果我手动尝试在(umount d)子 shell 中使用unshare proc,它将因“设备繁忙”而失败-这类似于您的C程序尝试执行的操作。

当我退出子Shell时,脚本的其余部分将运行,并且umountmount都失败。这是可以预期的,因为主脚本共享其安装 namespace 。

完全合理的是,/proc确实很忙,因此无法卸载,即使对于具有安装命名空间的专用副本的进程也是如此。这样的过程很可能本身就是使用/proc挂载的私有(private)副本。相反,我发现我可以在具有未共享的安装 namespace 的进程中成功卸载/dev/pts,但不能在共享该 namespace 的系统副本的进程中成功卸载ojit_code。

关于c - 'unshare'在C api中无法正常工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34872453/

10-13 01:48