From: Brian Ashworth <bosrsf04@xxxxxxxxx> add/remove: 0/0 grow/shrink: 1/0 up/down: 4/0 (4) function old new delta sys_pivot_root 610 614 +4 Total: Before=1899573, After=1899577, chg +0.00% Signed-off-by Brian Ashworth <bosrsf04@xxxxxxxxx> --- fs/Makefile | 2 +- fs/namespace.c | 123 ----------------------------------------------------- fs/pivot_root.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 124 deletions(-) create mode 100644 fs/pivot_root.c diff --git a/fs/Makefile b/fs/Makefile index 7bbaca9c67b1..34cb58c4127d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o fs_pin.o nsfs.o + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o pivot_root.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o diff --git a/fs/namespace.c b/fs/namespace.c index d49d615e30a1..36e4faf4c6e6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3043,129 +3043,6 @@ bool path_is_under(const struct path *path1, const struct path *path2) } EXPORT_SYMBOL(path_is_under); -/* - * pivot_root Semantics: - * Moves the root file system of the current process to the directory put_old, - * makes new_root as the new root file system of the current process, and sets - * root/cwd of all processes which had them on the current root to new_root. - * - * Restrictions: - * The new_root and put_old must be directories, and must not be on the - * same file system as the current process root. The put_old must be - * underneath new_root, i.e. adding a non-zero number of /.. to the string - * pointed to by put_old must yield the same directory as new_root. No other - * file system may be mounted on put_old. After all, new_root is a mountpoint. - * - * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem. - * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives - * in this situation. - * - * Notes: - * - we don't move root/cwd if they are not at the root (reason: if something - * cared enough to change them, it's probably wrong to force them elsewhere) - * - it's okay to pick a root that isn't the root of a file system, e.g. - * /nfs/my_root where /nfs is the mount point. It must be a mountpoint, - * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root - * first. - */ -SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, - const char __user *, put_old) -{ - struct path new, old, parent_path, root_parent, root; - struct mount *new_mnt, *root_mnt, *old_mnt; - struct mountpoint *old_mp, *root_mp; - int error; - - if (!may_mount()) - return -EPERM; - - error = user_path_dir(new_root, &new); - if (error) - goto out0; - - error = user_path_dir(put_old, &old); - if (error) - goto out1; - - error = security_sb_pivotroot(&old, &new); - if (error) - goto out2; - - get_fs_root(current->fs, &root); - old_mp = lock_mount(&old); - error = PTR_ERR(old_mp); - if (IS_ERR(old_mp)) - goto out3; - - error = -EINVAL; - new_mnt = real_mount(new.mnt); - root_mnt = real_mount(root.mnt); - old_mnt = real_mount(old.mnt); - if (IS_MNT_SHARED(old_mnt) || - IS_MNT_SHARED(new_mnt->mnt_parent) || - IS_MNT_SHARED(root_mnt->mnt_parent)) - goto out4; - if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) - goto out4; - if (new_mnt->mnt.mnt_flags & MNT_LOCKED) - goto out4; - error = -ENOENT; - if (d_unlinked(new.dentry)) - goto out4; - error = -EBUSY; - if (new_mnt == root_mnt || old_mnt == root_mnt) - goto out4; /* loop, on the same file system */ - error = -EINVAL; - if (root.mnt->mnt_root != root.dentry) - goto out4; /* not a mountpoint */ - if (!mnt_has_parent(root_mnt)) - goto out4; /* not attached */ - root_mp = root_mnt->mnt_mp; - if (new.mnt->mnt_root != new.dentry) - goto out4; /* not a mountpoint */ - if (!mnt_has_parent(new_mnt)) - goto out4; /* not attached */ - /* make sure we can reach put_old from new_root */ - if (!is_path_reachable(old_mnt, old.dentry, &new)) - goto out4; - /* make certain new is below the root */ - if (!is_path_reachable(new_mnt, new.dentry, &root)) - goto out4; - root_mp->m_count++; /* pin it so it won't go away */ - lock_mount_hash(); - detach_mnt(new_mnt, &parent_path); - detach_mnt(root_mnt, &root_parent); - if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { - new_mnt->mnt.mnt_flags |= MNT_LOCKED; - root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; - } - /* mount old root on put_old */ - attach_mnt(root_mnt, old_mnt, old_mp); - /* mount new_root on / */ - attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); - touch_mnt_namespace(current->nsproxy->mnt_ns); - /* A moved mount should not expire automatically */ - list_del_init(&new_mnt->mnt_expire); - put_mountpoint(root_mp); - unlock_mount_hash(); - chroot_fs_refs(&root, &new); - error = 0; -out4: - unlock_mount(old_mp); - if (!error) { - path_put(&root_parent); - path_put(&parent_path); - } -out3: - path_put(&root); -out2: - path_put(&old); -out1: - path_put(&new); -out0: - return error; -} - static void __init init_mount_tree(void) { struct vfsmount *mnt; diff --git a/fs/pivot_root.c b/fs/pivot_root.c new file mode 100644 index 000000000000..a609b21a1438 --- /dev/null +++ b/fs/pivot_root.c @@ -0,0 +1,129 @@ +#include <linux/syscalls.h> +#include <linux/security.h> +#include <linux/namei.h> +#include <linux/fs_struct.h> +#include "pnode.h" +#include "internal.h" + +/* + * pivot_root Semantics: + * Moves the root file system of the current process to the directory put_old, + * makes new_root as the new root file system of the current process, and sets + * root/cwd of all processes which had them on the current root to new_root. + * + * Restrictions: + * The new_root and put_old must be directories, and must not be on the + * same file system as the current process root. The put_old must be + * underneath new_root, i.e. adding a non-zero number of /.. to the string + * pointed to by put_old must yield the same directory as new_root. No other + * file system may be mounted on put_old. After all, new_root is a mountpoint. + * + * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem. + * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives + * in this situation. + * + * Notes: + * - we don't move root/cwd if they are not at the root (reason: if something + * cared enough to change them, it's probably wrong to force them elsewhere) + * - it's okay to pick a root that isn't the root of a file system, e.g. + * /nfs/my_root where /nfs is the mount point. It must be a mountpoint, + * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root + * first. + */ +SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, + const char __user *, put_old) +{ + struct path new, old, parent_path, root_parent, root; + struct mount *new_mnt, *root_mnt, *old_mnt; + struct mountpoint *old_mp, *root_mp; + int error; + + if (!may_mount()) + return -EPERM; + + error = user_path_dir(new_root, &new); + if (error) + goto out0; + + error = user_path_dir(put_old, &old); + if (error) + goto out1; + + error = security_sb_pivotroot(&old, &new); + if (error) + goto out2; + + get_fs_root(current->fs, &root); + old_mp = lock_mount(&old); + error = PTR_ERR(old_mp); + if (IS_ERR(old_mp)) + goto out3; + + error = -EINVAL; + new_mnt = real_mount(new.mnt); + root_mnt = real_mount(root.mnt); + old_mnt = real_mount(old.mnt); + if (IS_MNT_SHARED(old_mnt) || + IS_MNT_SHARED(new_mnt->mnt_parent) || + IS_MNT_SHARED(root_mnt->mnt_parent)) + goto out4; + if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) + goto out4; + if (new_mnt->mnt.mnt_flags & MNT_LOCKED) + goto out4; + error = -ENOENT; + if (d_unlinked(new.dentry)) + goto out4; + error = -EBUSY; + if (new_mnt == root_mnt || old_mnt == root_mnt) + goto out4; /* loop, on the same file system */ + error = -EINVAL; + if (root.mnt->mnt_root != root.dentry) + goto out4; /* not a mountpoint */ + if (!mnt_has_parent(root_mnt)) + goto out4; /* not attached */ + root_mp = root_mnt->mnt_mp; + if (new.mnt->mnt_root != new.dentry) + goto out4; /* not a mountpoint */ + if (!mnt_has_parent(new_mnt)) + goto out4; /* not attached */ + /* make sure we can reach put_old from new_root */ + if (!is_path_reachable(old_mnt, old.dentry, &new)) + goto out4; + /* make certain new is below the root */ + if (!is_path_reachable(new_mnt, new.dentry, &root)) + goto out4; + root_mp->m_count++; /* pin it so it won't go away */ + lock_mount_hash(); + detach_mnt(new_mnt, &parent_path); + detach_mnt(root_mnt, &root_parent); + if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { + new_mnt->mnt.mnt_flags |= MNT_LOCKED; + root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; + } + /* mount old root on put_old */ + attach_mnt(root_mnt, old_mnt, old_mp); + /* mount new_root on / */ + attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); + touch_mnt_namespace(current->nsproxy->mnt_ns); + /* A moved mount should not expire automatically */ + list_del_init(&new_mnt->mnt_expire); + put_mountpoint(root_mp); + unlock_mount_hash(); + chroot_fs_refs(&root, &new); + error = 0; +out4: + unlock_mount(old_mp); + if (!error) { + path_put(&root_parent); + path_put(&parent_path); + } +out3: + path_put(&root); +out2: + path_put(&old); +out1: + path_put(&new); +out0: + return error; +} -- 2.11.1