取消共享安装名称空间无法按预期工作 [英] unshare mount namespace not working as expected

查看:55
本文介绍了取消共享安装名称空间无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我调用Linux系统函数unshare(CLONE_NEWNS)时,它返回0表示成功.但是,它似乎不像我期望的那样工作. 具体来说,当我随后添加一个新的挂载(例如tmpfs挂载)时,该挂载是全局可见的.因此,它实际上不是预期的私有安装名称空间.

When I call the Linux system function unshare(CLONE_NEWNS), it returns 0 indicating success. But, it doesn't seem to work as I was expecting. Specifically when I then add a new mount such as a tmpfs one, it is globally visible. Therefore it is in fact not a private mount namespace as expected.

这是演示该问题的示例程序.编译并在一个终端中运行它.然后打开另一个终端,并检查示例程序编写的路径是否可见.它不应该,但是应该.似乎取消共享呼叫没有执行任何操作.我期望从那时起,该程序执行的任何后续挂载将对其他进程不可见.

Here is an example program that demonstrates the issue. Compile this up and run it in one terminal. Then open another terminal and check if the path written by the example program is visible. It shouldn't be but is. It is behaving as though the unshare call did nothing. What I was expecting was that from that moment on, any subsequent mounts performed by this program will not be visible to other processes.

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

我应该指出,挂载手册指出这应该可行.专门标记为按进程命名空间"的部分.

I should point out that the mount manpage suggests this should work. Specifically section labeled "Per-process namespaces".

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系统调用时无需进行派生或克隆.我在这里做什么错了?

If you use the unshare terminal command, it works. But that also forks another process. But the man page suggests there is no need to fork or clone when using the unshare system call. What am I doing wrong here?

推荐答案

运行strace之后,我找到了答案.

After running strace I found the answer.

\> 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 作者也在这样做.

Note the mount following the unshare. This mount call would appear to recursively mark all subsequent changes to mounts as private. And looking at this sandbox code: https://github.com/swetland/mkbox The author is doing just that also.

这是工作版本.

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

这篇关于取消共享安装名称空间无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆