Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs: add init_pivot_root()

We will soon be able to pivot_root() with the introduction of the
immutable rootfs. Add a wrapper for kernel internal usage.

Link: https://patch.msgid.link/20260112-work-immutable-rootfs-v2-2-88dd1c34a204@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

+91 -65
+17
fs/init.c
··· 13 13 #include <linux/security.h> 14 14 #include "internal.h" 15 15 16 + int __init init_pivot_root(const char *new_root, const char *put_old) 17 + { 18 + struct path new_path __free(path_put) = {}; 19 + struct path old_path __free(path_put) = {}; 20 + int ret; 21 + 22 + ret = kern_path(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new_path); 23 + if (ret) 24 + return ret; 25 + 26 + ret = kern_path(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_path); 27 + if (ret) 28 + return ret; 29 + 30 + return path_pivot_root(&new_path, &old_path); 31 + } 32 + 16 33 int __init init_mount(const char *dev_name, const char *dir_name, 17 34 const char *type_page, unsigned long flags, void *data_page) 18 35 {
+1
fs/internal.h
··· 90 90 int path_mount(const char *dev_name, const struct path *path, 91 91 const char *type_page, unsigned long flags, void *data_page); 92 92 int path_umount(const struct path *path, int flags); 93 + int path_pivot_root(struct path *new, struct path *old); 93 94 94 95 int show_path(struct seq_file *m, struct dentry *root); 95 96
+72 -65
fs/namespace.c
··· 4498 4498 } 4499 4499 EXPORT_SYMBOL(path_is_under); 4500 4500 4501 + int path_pivot_root(struct path *new, struct path *old) 4502 + { 4503 + struct path root __free(path_put) = {}; 4504 + struct mount *new_mnt, *root_mnt, *old_mnt, *root_parent, *ex_parent; 4505 + int error; 4506 + 4507 + if (!may_mount()) 4508 + return -EPERM; 4509 + 4510 + error = security_sb_pivotroot(old, new); 4511 + if (error) 4512 + return error; 4513 + 4514 + get_fs_root(current->fs, &root); 4515 + 4516 + LOCK_MOUNT(old_mp, old); 4517 + old_mnt = old_mp.parent; 4518 + if (IS_ERR(old_mnt)) 4519 + return PTR_ERR(old_mnt); 4520 + 4521 + new_mnt = real_mount(new->mnt); 4522 + root_mnt = real_mount(root.mnt); 4523 + ex_parent = new_mnt->mnt_parent; 4524 + root_parent = root_mnt->mnt_parent; 4525 + if (IS_MNT_SHARED(old_mnt) || 4526 + IS_MNT_SHARED(ex_parent) || 4527 + IS_MNT_SHARED(root_parent)) 4528 + return -EINVAL; 4529 + if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) 4530 + return -EINVAL; 4531 + if (new_mnt->mnt.mnt_flags & MNT_LOCKED) 4532 + return -EINVAL; 4533 + if (d_unlinked(new->dentry)) 4534 + return -ENOENT; 4535 + if (new_mnt == root_mnt || old_mnt == root_mnt) 4536 + return -EBUSY; /* loop, on the same file system */ 4537 + if (!path_mounted(&root)) 4538 + return -EINVAL; /* not a mountpoint */ 4539 + if (!mnt_has_parent(root_mnt)) 4540 + return -EINVAL; /* absolute root */ 4541 + if (!path_mounted(new)) 4542 + return -EINVAL; /* not a mountpoint */ 4543 + if (!mnt_has_parent(new_mnt)) 4544 + return -EINVAL; /* absolute root */ 4545 + /* make sure we can reach put_old from new_root */ 4546 + if (!is_path_reachable(old_mnt, old_mp.mp->m_dentry, new)) 4547 + return -EINVAL; 4548 + /* make certain new is below the root */ 4549 + if (!is_path_reachable(new_mnt, new->dentry, &root)) 4550 + return -EINVAL; 4551 + lock_mount_hash(); 4552 + umount_mnt(new_mnt); 4553 + if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { 4554 + new_mnt->mnt.mnt_flags |= MNT_LOCKED; 4555 + root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; 4556 + } 4557 + /* mount new_root on / */ 4558 + attach_mnt(new_mnt, root_parent, root_mnt->mnt_mp); 4559 + umount_mnt(root_mnt); 4560 + /* mount old root on put_old */ 4561 + attach_mnt(root_mnt, old_mnt, old_mp.mp); 4562 + touch_mnt_namespace(current->nsproxy->mnt_ns); 4563 + /* A moved mount should not expire automatically */ 4564 + list_del_init(&new_mnt->mnt_expire); 4565 + unlock_mount_hash(); 4566 + mnt_notify_add(root_mnt); 4567 + mnt_notify_add(new_mnt); 4568 + chroot_fs_refs(&root, new); 4569 + return 0; 4570 + } 4571 + 4501 4572 /* 4502 4573 * pivot_root Semantics: 4503 4574 * Moves the root file system of the current process to the directory put_old, ··· 4599 4528 { 4600 4529 struct path new __free(path_put) = {}; 4601 4530 struct path old __free(path_put) = {}; 4602 - struct path root __free(path_put) = {}; 4603 - struct mount *new_mnt, *root_mnt, *old_mnt, *root_parent, *ex_parent; 4604 4531 int error; 4605 - 4606 - if (!may_mount()) 4607 - return -EPERM; 4608 4532 4609 4533 error = user_path_at(AT_FDCWD, new_root, 4610 4534 LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new); ··· 4611 4545 if (error) 4612 4546 return error; 4613 4547 4614 - error = security_sb_pivotroot(&old, &new); 4615 - if (error) 4616 - return error; 4617 - 4618 - get_fs_root(current->fs, &root); 4619 - 4620 - LOCK_MOUNT(old_mp, &old); 4621 - old_mnt = old_mp.parent; 4622 - if (IS_ERR(old_mnt)) 4623 - return PTR_ERR(old_mnt); 4624 - 4625 - new_mnt = real_mount(new.mnt); 4626 - root_mnt = real_mount(root.mnt); 4627 - ex_parent = new_mnt->mnt_parent; 4628 - root_parent = root_mnt->mnt_parent; 4629 - if (IS_MNT_SHARED(old_mnt) || 4630 - IS_MNT_SHARED(ex_parent) || 4631 - IS_MNT_SHARED(root_parent)) 4632 - return -EINVAL; 4633 - if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) 4634 - return -EINVAL; 4635 - if (new_mnt->mnt.mnt_flags & MNT_LOCKED) 4636 - return -EINVAL; 4637 - if (d_unlinked(new.dentry)) 4638 - return -ENOENT; 4639 - if (new_mnt == root_mnt || old_mnt == root_mnt) 4640 - return -EBUSY; /* loop, on the same file system */ 4641 - if (!path_mounted(&root)) 4642 - return -EINVAL; /* not a mountpoint */ 4643 - if (!mnt_has_parent(root_mnt)) 4644 - return -EINVAL; /* absolute root */ 4645 - if (!path_mounted(&new)) 4646 - return -EINVAL; /* not a mountpoint */ 4647 - if (!mnt_has_parent(new_mnt)) 4648 - return -EINVAL; /* absolute root */ 4649 - /* make sure we can reach put_old from new_root */ 4650 - if (!is_path_reachable(old_mnt, old_mp.mp->m_dentry, &new)) 4651 - return -EINVAL; 4652 - /* make certain new is below the root */ 4653 - if (!is_path_reachable(new_mnt, new.dentry, &root)) 4654 - return -EINVAL; 4655 - lock_mount_hash(); 4656 - umount_mnt(new_mnt); 4657 - if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { 4658 - new_mnt->mnt.mnt_flags |= MNT_LOCKED; 4659 - root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; 4660 - } 4661 - /* mount new_root on / */ 4662 - attach_mnt(new_mnt, root_parent, root_mnt->mnt_mp); 4663 - umount_mnt(root_mnt); 4664 - /* mount old root on put_old */ 4665 - attach_mnt(root_mnt, old_mnt, old_mp.mp); 4666 - touch_mnt_namespace(current->nsproxy->mnt_ns); 4667 - /* A moved mount should not expire automatically */ 4668 - list_del_init(&new_mnt->mnt_expire); 4669 - unlock_mount_hash(); 4670 - mnt_notify_add(root_mnt); 4671 - mnt_notify_add(new_mnt); 4672 - chroot_fs_refs(&root, &new); 4673 - return 0; 4548 + return path_pivot_root(&new, &old); 4674 4549 } 4675 4550 4676 4551 static unsigned int recalc_flags(struct mount_kattr *kattr, struct mount *mnt)
+1
include/linux/init_syscalls.h
··· 17 17 int __init init_rmdir(const char *pathname); 18 18 int __init init_utimes(char *filename, struct timespec64 *ts); 19 19 int __init init_dup(struct file *file); 20 + int __init init_pivot_root(const char *new_root, const char *put_old);