}
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.rst 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)
+int path_pivot_root(struct path *new, struct path *old)
{
- struct path new __free(path_put) = {};
- struct path old __free(path_put) = {};
struct path root __free(path_put) = {};
struct mount *new_mnt, *root_mnt, *old_mnt, *root_parent, *ex_parent;
int error;
if (!may_mount())
return -EPERM;
- error = user_path_at(AT_FDCWD, new_root,
- LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new);
- if (error)
- return error;
-
- error = user_path_at(AT_FDCWD, put_old,
- LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old);
- if (error)
- return error;
-
- error = security_sb_pivotroot(&old, &new);
+ error = security_sb_pivotroot(old, new);
if (error)
return error;
get_fs_root(current->fs, &root);
- LOCK_MOUNT(old_mp, &old);
+ LOCK_MOUNT(old_mp, old);
old_mnt = old_mp.parent;
if (IS_ERR(old_mnt))
return PTR_ERR(old_mnt);
- new_mnt = real_mount(new.mnt);
+ new_mnt = real_mount(new->mnt);
root_mnt = real_mount(root.mnt);
ex_parent = new_mnt->mnt_parent;
root_parent = root_mnt->mnt_parent;
return -EINVAL;
if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
return -EINVAL;
- if (d_unlinked(new.dentry))
+ if (d_unlinked(new->dentry))
return -ENOENT;
if (new_mnt == root_mnt || old_mnt == root_mnt)
return -EBUSY; /* loop, on the same file system */
return -EINVAL; /* not a mountpoint */
if (!mnt_has_parent(root_mnt))
return -EINVAL; /* absolute root */
- if (!path_mounted(&new))
+ if (!path_mounted(new))
return -EINVAL; /* not a mountpoint */
if (!mnt_has_parent(new_mnt))
return -EINVAL; /* absolute root */
/* make sure we can reach put_old from new_root */
- if (!is_path_reachable(old_mnt, old_mp.mp->m_dentry, &new))
+ if (!is_path_reachable(old_mnt, old_mp.mp->m_dentry, new))
return -EINVAL;
/* make certain new is below the root */
- if (!is_path_reachable(new_mnt, new.dentry, &root))
+ if (!is_path_reachable(new_mnt, new->dentry, &root))
return -EINVAL;
lock_mount_hash();
umount_mnt(new_mnt);
unlock_mount_hash();
mnt_notify_add(root_mnt);
mnt_notify_add(new_mnt);
- chroot_fs_refs(&root, &new);
+ chroot_fs_refs(&root, new);
return 0;
}
+/*
+ * 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.rst 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 __free(path_put) = {};
+ struct path old __free(path_put) = {};
+ int error;
+
+ error = user_path_at(AT_FDCWD, new_root,
+ LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new);
+ if (error)
+ return error;
+
+ error = user_path_at(AT_FDCWD, put_old,
+ LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old);
+ if (error)
+ return error;
+
+ return path_pivot_root(&new, &old);
+}
+
static unsigned int recalc_flags(struct mount_kattr *kattr, struct mount *mnt)
{
unsigned int flags = mnt->mnt.mnt_flags;