unshare -m 未创建挂载命名空间

unshare -m 未创建挂载命名空间

我跑了

unshare -mfp sh -c 'mount -tproc none /proc ; ls /proc'

正如预期的那样,它打印了一个仅包含 PID 1 和 PID 3 目录的 /proc,然后退出,让我回到根命名空间中的旧提示符。

然后我就这么做了

ls /proc

我得到的列表没有任何 PID 目录。我原本以为 /proc 中会充满进程。我不得不再次挂载 proc 来修复这个问题。

为什么会发生这种情况?我该如何修复这个问题,以便我在 PID 命名空间内挂载的 /proc 保持在本地?

我尝试将 --mount-private 传递给 mount,但似乎没有任何效果。

我使用的是带有 util-linux 2.23.2 的 Amazon Linux 2016.03。

答案1

要么是 unshare(1) 坏了,要么就是我太蠢了。

我修改了代码http://crosbymichael.com/creating-containers-part-1.html所以它对我来说确实有效。必须使用 来延迟卸载 /proc umount2,并使用linux/sched.h而不是sched.h

要编译,请执行以下操作gcc foo.c -ofoo

您会注意到,运行后,./foo ls /proc主机系统上的 /proc 不会被清除。

//
// This compiles and works on Amazon Linux 2016.03 (kernel 4.4.5-15.26.amzn1.x86_64)
//

#include <stdio.h>
#include <stdlib.h>
// was <sched.h>, but wouldn't compile on Amazon Linux
#include <linux/sched.h>
// for umount2()
#include <sys/mount.h>
#include <sys/wait.h>
#include <errno.h>

#define STACKSIZE (1024*1024)
static char child_stack[STACKSIZE];

struct clone_args {
        char **argv;
};

static int child_exec(void *stuff) {
        struct clone_args *args = (struct clone_args *)stuff;

        // the fprintf()s crash. Not sure why.

        // changed from umount(), lazy umount succeeds
        if (umount2("/proc", MNT_DETACH) != 0) {
                fprintf(stderr, "failed to unmount /proc: %s\n", strerror(errno));
                exit(-1);
        }

        if (mount("proc", "/proc", "proc", 0, "") != 0) {
                fprintf(stderr, "failed to mount /proc: %s\n", strerror(errno));
                exit(-1);
        }

        if (execvp(args->argv[0], args->argv) != 0) {
                fprintf(stderr, "failed to execvp arguments: %s\n", strerror(errno));
                exit(-1);
        }

        // unreachable
        exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
        struct clone_args args;
        args.argv = &argv[1];

        int clone_flags = CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
        pid_t pid = clone(child_exec, child_stack + STACKSIZE, clone_flags, &args);

        if (pid < 0) {
                fprintf(stderr, "clone failed: %s\n", strerror(errno));
                exit(EXIT_FAILURE);
        }

        if (waitpid(pid, NULL, 0) == -1) {
                fprintf(stderr, "failed to wait pid %d\n", pid);
                exit(EXIT_FAILURE);
        }

        exit(EXIT_SUCCESS);
}

答案2

挂载传播已启用(可能是由 systemd 启用),而您使用的旧版本确实unshare会改变传播状态,因此新挂载命名空间中的所有挂载操作都会反映在原始命名空间中。

相关内容