Re: [RFC PATCH 0/2] init: boot image-based systems without an initramfs (rootimage=)
Christian Brauner <[email protected]> Mon, 27 Jul 2026 10:55:02 +0200
| Newsgroups | dev.linux.lists.fsverity,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <20260727-gepaukt-eislauf-waran-7c03f0e47609@brauner> |
On 2026-07-18 20:15 +0100, Eric Curtin wrote: > Image-based Linux systems (bootc-style OS updaters, ChromeOS/Android-like > A/B schemes, embedded appliances) keep one or more immutable root > filesystem images as sealed files on a writable filesystem and pick one > at boot. Booting such a system today always requires an initramfs, even > when that initramfs has nothing else to do; its only jobs are to parse > the kernel command line, mount the state filesystem, verify the image, > loop-mount it and switch_root into it. > > This series teaches the kernel to do all of that directly: > > root=PARTUUID=... rootimage=/deploy/a/root.erofs rootimagefstype=erofs \ > rootimageverity=sha256:a9548f4c... rootimagesrcdir=/var/state > > Patch 1 adds rootimage= (plus rootimagefstype=/rootimageflags=/ > rootimagesrcdir=): root= then merely names the "carrier" filesystem. > The image file on it is mounted read-only through the filesystem's > file-backed mount support (available in erofs since v6.12), so no loop > device is involved, and it becomes the root that prepare_namespace() > pivots into. The carrier mount is detached by default, or moved to > rootimagesrcdir= inside the new root, which image-based systems > practically always want since the carrier holds their writable state. > > Patch 2 adds rootimageverity=, which requires the image to carry a > specific fsverity file digest, reusing the fsverity_get_digest() > interface that IMA and overlayfs already use for digest pinning. With > a signed or measured command line (e.g. a unified kernel image), the > chain of trust extends to every byte of the root filesystem with no > userspace boot stage: the pinned digest authenticates the image's > Merkle tree root, and fsverity keeps verifying reads against it at > runtime, so later tampering with the carrier is caught as well. > > This is the file-backed analogue of dm-mod.create= (CONFIG_DM_INIT), > which moved the equivalent block-device setup out of the initramfs for > verity-partition layouts back in v5.1. For file-based deployment > layouts nothing similar exists, so distributions ship a dracut stack > whose only purpose is the five steps above, and which remains the > largest and most failure-prone moving part of an otherwise fully > image-defined boot. So I have several structual and design issues with this. In the first pach the filp_open() and subsequent fput() are unused. And that claim "the image cannot change between this open and the mount below" is resting on very weak assumptions. The second patch then checks the digest on the struct file from its own filp_open(). But the mount goes through init_mount() with the path... so erofs does a third lookup via filp_open(fc->source)... Nothing guarantees that there's a relationship between the verified inode and the path the superblock is created from. The only guarantee is that no userspace yet exists but which can't really be enforced. To support this properly we need new infrastructure such that you can actually hand an already opened file as the source. I know that erofs is intended to merge support for this at least but this should be generic infra available to any fs. Note also that the default detach mode creates a zombie superblock and the image superblocks source string (/root/deploy/...) dangles after the pivot. /proc/self/mounts names a path that doesn't exist in the final namespace. And unlike loop there's no /sys/block/loopX/loop/backing_file to recover which file backs the root. The other claim is that the digest sufficiently guarantees the integrity of the root filesystem. That's not correct per se... An erofs multi-device filesystem blows this apart and rootimageflags=device= would also add more. So that digest only cover the primary image. The bigger flaw is that the untrusted "carrier" (LLMs do pick the worst terms for things...) is fully parsed before anything is verified. In other words, mounting the carrier means running the ext4 (or whatever) parsers and infra over attacker-writable data, and the fsverity descriptor are themselves read from that untrusted fs. So basically you're hosed before you ever got to the fsverity part. This is also now the third fsverity-digest-pinning mechanism (IMA appraisal, the IPE LSM and now rootimageverity=). With the least expressive policy language of the three. No signature or keyring option either and so the boot entry must be regenerated per image update. You're embedding a whole deployment topology into the core code here as well... There are _five_ interacting __setup parameters. Every real deployment immediately wants a sixth knob: A/B fallback inside the mechanism. Because in your current model every failure is a panic(). But that also means image selection must live in the bootloader anyway: composefs/overlay stacking, LUKS-encrypted state partitions as command lines can't do crypto secrets, fsck of the carrier, directory-based deployments yadayadayada. This is just turning do_mounts.c into policy it shouldn't be involved in. We just refused pushing the bootloader spec into the initramfs for the same reasons - and that one I'm much more sympathetic to since I was involved in creating it. I'd love to see parts of that in the kernel but I refuse it because I believe fundamentally the kernel is in the business of keeping complexity in userspace not the other way around. Also the users the cover letter touches on such as distro kernels ship erofs and its decompressors, the block drivers, and the fs stack as modules. Afaict, rootimage= needs all of it builtin: - bootc/ostree: composefs — multi-mount + overlay + external objects. inexpressible here and partially unverifiable - ChromeOS/Android-style A/B: dm-verity partitions already served by dm-mod.create= and a fallback story. - embedded squashfs appliances: no file-backed mount support in squashfs What remains are single-erofs-filesystems with fully-builtin kernels. That's kinda what CONFIG_INITRAMFS_SOURCE embeds a five-line static /init into the same signed/measured kernel image with identical trust properties and full policy freedom. UKI users likewise already sign and measure their initrd as part of the PE. The series only really makes sense if you get rid of that.