我不明白输入挂载命名空间是如何工作的

我不明白输入挂载命名空间是如何工作的

如果您分叉到一个新的安装命名空间,或者输入一个现有的命名空间。

可以保存来自外部安装命名空间的文件描述符。您可以通过在外部挂载命名空间(例如 )中查找进程[kdevtmpfs]并打开 来非常轻松地演示这一点/proc/$PID/root。 (如果我更改到此目录并运行/bin/pwd,它似乎会打印令人敬畏的错误消息/usr/bin/pwd: couldn't find directory entry in ‘..’ with matching i-node,并strace显示getcwd()返回(unreachable)/)。

请定义当进入新的挂载命名空间时,进程持有的当前挂载命名空间(当前目录和当前根 (chroot))的现有引用会发生什么情况。

如果这些引用都没有被修改,那么输入新的挂载命名空间就没有多大意义。例如/path/to/file,如果进程的根仍然指向旧的安装命名空间,则打开文件将从旧的安装命名空间打开它。

再次,我想了解带有 CLONENEWNS 的 clone() 的情况(如命令unshare)和 setns() 的情况(如nsenter命令)。

答案1

当前工作目录和根目录都将重置为输入的安装命名空间的根文件系统。

例如,我测试过可以chroot通过运行来逃脱nsenter -m --target $$

(提醒:chroot当您仍然是 root 时很容易逃脱。 man chroot文档中介绍了执行此操作的众所周知的方法)。


来源

https://elixir.bootlin.com/linux/latest/source/fs/namespace.c?v=4.17#L3507

static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{
    struct fs_struct *fs = current->fs;

注意:current表示当前任务 - 当前线程/进程。

->fs将是该任务的文件系统数据 - 这是在同一进程内的线程任务之间共享的。例如,您将在下面看到更改工作目录是对->fs.

例如,更改工作目录会影响同一进程的所有线程。像这样的 POSIX 兼容线程是使用clone() 的 CLONE_FS 标志实现的。

    struct mnt_namespace *mnt_ns = to_mnt_ns(ns), *old_mnt_ns;
    struct path root;
    int err;

...

    /* Find the root */
    err = vfs_path_lookup(mnt_ns->root->mnt.mnt_root, &mnt_ns->root->mnt,
                "/", LOOKUP_DOWN, &root);

这是有问题的行:

    /* Update the pwd and root */
    set_fs_pwd(fs, &root);
    set_fs_root(fs, &root);

...

}

...

const struct proc_ns_operations mntns_operations = {
    .name       = "mnt",
    .type       = CLONE_NEWNS,
    .get        = mntns_get,
    .put        = mntns_put,
    .install    = mntns_install,
    .owner      = mntns_owner,
};

相关内容