unshare mount命名空间无法按预期工作

时间:2017-01-10 04:26:38

标签: c linux

当我调用Linux系统函数unshare(CLONE_NEWNS)时,它返回0表示成功。但是,它似乎并没有像我期待的那样发挥作用。 特别是当我然后添加一个新的挂载(如tmpfs)时,它是全局可见的。因此,它实际上不是预期的私有安装命名空间。

以下是演示此问题的示例程序。编译它并在一个终端中运行它。然后打开另一个终端并检查示例程序写入的路径是否可见。它不应该是,但是。它表现得好像取消共享呼叫没有做任何事情。我所期待的是,从那一刻起,该程序执行的任何后续安装将不会被其他进程看到。

/* Run this program as root.  As mount and unshare requires higher privileges. */

#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <stdio.h>

#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");
}

我应该指出挂载联机帮助页建议这应该有效。特别是标有&#34; Per-process命名空间&#34;。

的部分

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。我在这里做错了什么?

1 个答案:

答案 0 :(得分:6)

跑完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 <sched.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <stdio.h>

#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");
}