History

fs: add immutable rootfs

Currently pivot_root() doesn't work on the real rootfs because it cannot be unmounted. Userspace has to do a recursive removal of the initramfs contents manually before continuing the boot. Really all we want from the real rootfs is to serve as the parent mount for anything that is actually useful such as the tmpfs or ramfs for initramfs unpacking or the rootfs itself. There's no need for the real rootfs to actually be anything meaningful or useful. Add a immutable rootfs called "nullfs" that can be selected via the "nullfs_rootfs" kernel command line option. The kernel will mount a tmpfs/ramfs on top of it, unpack the initramfs and fire up userspace which mounts the rootfs and can then just do: chdir(rootfs); pivot_root(".", "."); umount2(".", MNT_DETACH); and be done with it. (Ofc, userspace can also choose to retain the initramfs contents by using something like pivot_root(".", "/initramfs") without unmounting it.) Technically this also means that the rootfs mount in unprivileged namespaces doesn't need to become MNT_LOCKED anymore as it's guaranteed that the immutable rootfs remains permanently empty so there cannot be anything revealed by unmounting the covering mount. In the future this will also allow us to create completely empty mount namespaces without risking to leak anything. systemd already handles this all correctly as it tries to pivot_root() first and falls back to MS_MOVE only when that fails. This goes back to various discussion in previous years and a LPC 2024 presentation about this very topic.

Christian Brauner committed 10 months ago

Commit 576ee5d1 parent 3c1b73f7 files · +159 −12Browse files

Showing the changes to init (2 of 7 files). Show all

Unified · Split

2 files
  1. init/do_mounts.c +14 −0
  2. init/do_mounts.h +1 −0
init/do_mounts.c+14−0
@@ -492,6 +492,20 @@ void __init prepare_namespace(void) · 491 unmodified lines
492 mount_root(saved_root_name);492 mount_root(saved_root_name);
493out:493out:
494 devtmpfs_mount();494 devtmpfs_mount();
495
496 if (nullfs_rootfs) {
497 if (init_pivot_root(".", ".")) {
498 pr_err("VFS: Failed to pivot into new rootfs\n");
499 return;
500 }
501 if (init_umount(".", MNT_DETACH)) {
502 pr_err("VFS: Failed to unmount old rootfs\n");
503 return;
504 }
505 pr_info("VFS: Pivoted into new rootfs\n");
506 return;
507 }
508
495 init_mount(".", "/", NULL, MS_MOVE, NULL);509 init_mount(".", "/", NULL, MS_MOVE, NULL);
496 init_chroot(".");510 init_chroot(".");
497}511}
init/do_mounts.h+1−0
@@ -15,6 +15,7 @@ · 14 unmodified lines
15void mount_root_generic(char *name, char *pretty_name, int flags);15void mount_root_generic(char *name, char *pretty_name, int flags);
16void mount_root(char *root_device_name);16void mount_root(char *root_device_name);
17extern int root_mountflags;17extern int root_mountflags;
18extern bool nullfs_rootfs;
18 19
19static inline __init int create_dev(char *name, dev_t dev)20static inline __init int create_dev(char *name, dev_t dev)
20{21{