当我调用Linux系统函数unshare(CLONE_NEWNS)时,它返回0表示成功.但是,它似乎并没有像我期望的那样起作用.特别是当我然后添加一个新的挂载(如tmpfs)时,它是全局可见的.因此,它实际上不是预期的私有安装命名空间.
这是一个演示该问题的示例程序.编译它并在一个终端中运行它.然后打开另一个终端并检查示例程序写入的路径是否可见.它不应该是.它表现得好像取消共享呼叫没有做任何事情.我期待的是,从那一刻开始,该程序执行的任何后续安装将不会被其他进程看到.
/* Run this program as root. As mount and unshare requires higher privileges. */ #define _GNU_SOURCE #include#include #include #include #include #include #include #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { // Create a temporary directory at /tmp/unshare mkdir("/tmp/unshare", S_IRWXG); if (unshare(CLONE_NEWNS) == -1) errExit("unshare"); if (mount("none", "/tmp/unshare", "tmpfs", 0, "mode=0700") == -1) errExit("unshare"); FILE* fp = fopen("/tmp/unshare/test", "w"); fprintf(fp, "This file should not be seen by other processes right?\n"); fclose(fp); // Pause printf("Now open another shell. As the root user, verify the file /tmp/unshare/test is not seen\n.Press enter end finish\n"); char c = getchar(); if (umount("/tmp/unshare") == -1) errExit("umount"); }
我应该指出,mount manpage建议这应该有效.特别标记为"每个进程名称空间"的部分.
即
A process can obtain a private mount namespace if ... it calls unshare(2) with the CLONE_NEWNS flag, which causes the caller's mount namespace to obtain a private copy of the namespace that it was previously sharing with other processes, so that future mounts and unmounts by the caller are invisible to other pro? cesses (except child processes that the caller subsequently creates) and vice versa.
如果您使用unshare terminal命令,它可以工作.但这也要求另一个过程.但是手册页建议在使用unshare系统调用时不需要fork或clone.我在这做错了什么?
运行strace后,我找到了答案.
\> strace unmount -m true ... unshare(CLONE_NEWNS) = 0 mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) = 0 execve("/home/matt/.nvm/versions/node/v6.9.1/bin/true", ["true"], [/* 29 vars */]) = -1 ENOENT (No such file or directory) ...
请注意取消共享后的挂载.此挂载调用似乎递归地将对挂载的所有后续更改标记为私有.看看这个沙盒代码:https://github.com/swetland/mkbox 作者也在这样做.
所以这是工作版本.
/* Run this program as root. As mount and unshare requires higher privileges. */ #define _GNU_SOURCE #include#include #include #include #include #include #include #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { // Create a temporary directory at /tmp/unshare mkdir("/tmp/unshare", S_IRWXG); if (unshare(CLONE_NEWNS | CLONE_FS | CLONE_THREAD) == -1) errExit("unshare"); /* ensure that changes to our mount namespace do not "leak" to * outside namespaces (what mount --make-rprivate / does) */ if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) == -1) errExit("mount1"); if (mount("none", "/tmp/unshare", "tmpfs", 0, NULL) == -1) errExit("mount2"); // if (mount("none", "/tmp/unshare", NULL, MS_PRIVATE, NULL) == -1) // errExit("mount2"); FILE* fp = fopen("/tmp/unshare/test", "w"); fprintf(fp, "This file should not be seen\n"); fclose(fp); // Pause printf("Now open another shell. As the root user, verify the file /tmp/unshare/test is not seen\n.Press enter end finish\n"); char c = getchar(); if (umount("/tmp/unshare") == -1) errExit("umount"); }