c - 取消共享挂载命名空间未按预期工作

标签 c linux

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

这是一个演示该问题的示例程序。编译它并在一个终端中运行它。然后再打开一个终端,查看示例程序写入的路径是否可见。它不应该是但是是。它表现得好像 unshare 调用什么也没做。我所期望的是,从那一刻起,该程序执行的任何后续挂载都将对其他进程不可见。

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

我应该指出,mount 联机帮助页表明这应该可行。特别是标记为“每个进程 namespace ”的部分。

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 终端命令,它会起作用。但这也 fork 了另一个过程。但是手册页建议在使用 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)
...

注意取消共享后的挂载。此挂载调用似乎递归地将对挂载的所有后续更改标记为私有(private)。看看这个沙盒代码: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");
}

关于c - 取消共享挂载命名空间未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41561136/

相关文章:

c - 奇怪的 printf/pthread 错误?

c - 二叉树实现

python - 无法使用 termios.TIOCSTI 伪造终端输入

php - PHP 中显示零字节文件的消息

c - 如何将文件中的字符分配给 char 类型变量? (C)

c - 删除 BST 中的节点

c - 获取传递给 C 函数的数组长度

linux - Bash:电子邮件未触发

linux - 发回 Av-Pair attr 自由半径

python - 在 Linux 上伪造 IO 错误