LFS Live ISO
The book ends at a login prompt; the project ends at a disc. A booting LFS system is a filesystem on a partition — it runs only on the machine that contains it. The moment you want it on another machine — a VM, a test box, real hardware — you need the same trick every distribution uses: a live image. Bootable media that carries the whole system compressed, unpacks it into RAM at boot, and lets you run it — and install it — on hardware that has never met your disk. This chapter builds that image: the toolchain, the kernel config, the initramfs, the squashfs, the ISO itself. Every step was measured on a real build; the failure modes are documented because we hit them.
The toolchain — six packages beyond the book
LFS 12.4 stops short of image production. Six BLFS-side packages close the gap — all buildable inside the system you just made, no host tools required:
| Package | Version (measured) | Job | |
|---|---|---|---|
| busybox | 1.37.0 | The initramfs's entire userspace — one statically linked binary | |
| cpio | 2.15 | Packs the initramfs (newc format is the kernel's own archive) | |
| squashfs-tools | 4.7 | Compresses the whole root filesystem into the live image | |
| xorriso | 1.5.6.pl02 | Writes ISO9660/El Torito — also grub-mkrescue's engine | |
| mtools | 4.0.43 | Builds the FAT ESP image grub embeds for UEFI boot | |
| dosfstools | 4.2 | mkfs.fat — EFI system partitions, installer-side |
Busybox must be static. make defconfig, set CONFIG_STATIC=y, build — one ~1 MB ELF with no library dependencies. A dynamically linked busybox in an initramfs means carrying ld-linux and libc too; static means the initramfs is a binary, a script, and nothing else.
Build quirks measured (each cost real debugging time):
- cpio 2.15 vs GCC 15: the default C23 dialect rejects cpio's old K&R-style
xstatdeclarations.make CFLAGS='-O2 -std=gnu11'. - squashfs-tools 4.7:
LZO_SUPPORT/LZ4_SUPPORTdefault1in the Makefile — passing only your wanted compressors still compiles LZO/LZ4 code and dies on missing headers. Pass explicitLZO_SUPPORT=0 LZ4_SUPPORT=0. Itsmake installthen fails after installing all binaries, generating manpages with anon-builtin echoerror — harmless. - xorriso:
xorriso-1.5.6.pl02.tar.gzextracts toxorriso-1.5.6/— the.pl02is absent from the directory name. - GRUB needs FreeType for fonts:
grub-mkrescuefails on a missingunicode.pf2unless freetype was built first — or transplant the file from a same-version distro package (it is only a font).
The kernel for live media — three rules
The governing principle: an initramfs cannot use a =m feature until the module is loaded, but loading a module needs userspace, which needs the initramfs. Whatever the initramfs touches must be [*], not [M]. That axiom produced three measured rules.
Rule 1 — CONFIG_BINFMT_SCRIPT=y if /init is a script
Failed to execute /init (error -8) is ENOEXEC — the kernel read the file and could not parse it as a program. A #!/bin/busybox sh init needs the shebang interpreter binfmt handler in the kernel. An =m modularization sweep (allmodconfig-style) silently breaks every script-init initramfs in existence — and it cannot be insmodded, because init is the script. There is no module loader before init runs; that is the whole point of the chicken-and-egg.
Rule 2 — everything the initramfs touches is built-in (LoadPin makes this mandatory)
With CONFIG_SECURITY_LOADPIN=y, the kernel pins the filesystem the first module load comes from and refuses modules from anywhere else, forever. If your initramfs loads even one module, LoadPin pins the initramfs rootfs — and after switch_root, every udev load from the real /usr/lib/modules gets LoadPin: kernel-module denied. The system boots and can never load a module again (measured: 0 of 56 udev loads succeeded).
There is a second LoadPin trap: it requires finit_module(2) — the fd-based API that lets it verify the source filesystem. BusyBox insmod uses the legacy init_module(2) memory-buffer API → LoadPin: kernel-module old-api-denied. You can ship a twenty-line finit_module syscall helper — or simply load zero initramfs modules, which is what rule 2 already demands.
The built-in set that satisfied our initramfs (kernel 6.12.115):
CONFIG_BINFMT_SCRIPT=y CONFIG_BINFMT_MISC=y # exec a script init
CONFIG_BLK_DEV_SR=y CONFIG_CDROM=y # the optical device
CONFIG_ISO9660_FS=y # read the ISO itself
CONFIG_BLK_DEV_LOOP=y # loop-mount the squashfs
CONFIG_SQUASHFS=y # the live root
CONFIG_OVERLAY_FS=y # the writable layer
CONFIG_FAT_FS=y CONFIG_VFAT_FS=y # the ESP, future USB
CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y # iso9660/vfat charsets
CONFIG_VIRTIO_BLK=y # VM disks
# plus the storage controller family your hardware actually uses — =y
Verification: grep '=m\|not set' /boot/config-$(uname -r) against that list, or zcat /proc/config.gz on the running kernel.
Rule 3 — module signatures and IMA appraisal are different signatures
make modules_install signing produces module signatures. IMA_APPRAISE_REQUIRE_MODULE_SIGS demands file-level xattr signatures — which module signing does not produce. An allyesconfig kernel with that option set denied every modprobe with EPERM, signatures correct or not. Workaround: ima_appraise=off on the kernel command line; the real fix (IMA xattr signing, or dropping the requirement) is a security-pass decision, documented in Linux Security.
The initramfs — the smallest possible bootstrap
Contents: one static binary, one script, no modules:
#!/bin/busybox sh
/bin/busybox --install -s # applet symlinks
mount -t proc /proc /proc
mount -t sysfs /sys /sys
mount -t devtmpfs dev /dev # /dev/sr0 appears here
# poll for the optical device, then:
mount -t iso9660 -o ro /dev/sr0 /media
mount -o loop /media/live/filesystem.squashfs /squashfs
mount -t tmpfs /upper /upper # RAM disk for the writable layer
mount -t overlay overlay \
-o lowerdir=/squashfs,upperdir=/upper/u,workdir=/upper/w /newroot
exec switch_root /newroot /sbin/init
That is the entire live-CD trick: ISO9660 gives you the squashfs, loop gives you the rootfs, overlay gives you writability, switch_root retires the initramfs. The upper/work dirs live on tmpfs — writes land in RAM and die at shutdown, which is precisely correct for live media. Pack it find . | cpio -o -H newc | gzip > initramfs.img. Rebuild hygiene: rm -rf the staging dir first — stale .ko files from a previous kernel build fail insmod with Unknown symbol (vermagic mismatch) and send diagnosis in circles.
The squashfs — the system, compressed
Stage the running root with tar --one-file-system (never copy /proc, /sys, /dev, /run), excluding /sources, the build workdirs, /mnt, /media, /tmp, and /var/log/journal. Then mksquashfs stage filesystem.squashfs -comp gzip — our ~9.6 GB root compressed to ~2.8 GB.
The live-env trap (measured): booted into the live system, the excluded directories appear gone — they are absent from the squashfs, not deleted from your disk. The tell that you are in the live environment: df / shows overlay. Any make install or copy you run there writes only to the RAM overlay — a command that looks like it clobbered your real /boot clobbered nothing. Shut down, boot the disk, your work is intact.
The ISO — grub-mkrescue does both firmwares in one pass
The isotree is four files deep:
boot/vmlinuz boot/initramfs.img
boot/grub/grub.cfg live/filesystem.squashfs
grub-mkrescue -o alb-linux.iso isotree/ emits a hybrid image: an El Torito BIOS image assembled from the i386-pc modules, plus an embedded FAT ESP (built via mtools) holding EFI/BOOT/BOOTX64.EFI from the x86_64-efi modules. Both require GRUB compiled twice — --with-platform=pc and --with-platform=efi produce two module trees that coexist under /usr/lib/grub/; see GRUB for the build. The grub.cfg is minimal — linux /boot/vmlinuz ... + initrd /boot/initramfs.img in a menuentry.
The measured boot chain
Verified on VMware under both firmwares, kernel 6.12.115:
GRUB (El Torito i386-pc, or EFI/BOOT/BOOTX64.EFI)
→ kernel (every live-media driver built-in)
→ initramfs: busybox /init — zero module loads, so LoadPin's
first pin lands inside the live root, where it belongs
→ /dev/sr0 → iso9660 → squashfs loop → overlay on tmpfs
→ switch_root → systemd → login → DHCP → sshd
→ 56 modules via udev — zero LoadPin denials
What goes wrong — the field catalog
- initramfs drops to a shell with no devices → a needed driver is
=m; there is no loader to load it (rule 2). error -8at/init→BINFMT_SCRIPT=m, or CRLF/BOM in the script — check bytes before suspecting the kernel.- Live boot fine, zero modules inside → an initramfs
insmodran first and LoadPin pinned the wrong filesystem. The initramfs must load nothing. old-api-denied→ busyboxinsmodusesinit_module(2); LoadPin demandsfinit_module(2).- Excluded paths "missing" in the live env → you are in the RAM overlay; nothing was deleted.
Exercises
- Boot the image with
console=ttyS0on the kernel line and identify the exact line whereswitch_rootretires the initramfs — then the line where LoadPin pins its first filesystem. - Remove
BLK_DEV_LOOPfrom the builtin set, rebuild, and watch where the init script fails. Predict the failure line first. - Add a file to the live env, reboot, confirm it vanished — then explain why the squashfs itself never saw it.
- Extract
filesystem.squashfsfrom the ISO withxorriso -osirroxandunsquashfsone directory of it, without booting anything.
Timeline
- 1971 — the
initrdconcept's ancestor: loaders staging ramdisks on minicomputers - 1994 —
initrdenters Linux proper (1.1.x era), for modular SCSI boot - 2002 —
initramfs/tmpfsrootfs replaces block-device initrd (2.5.46) - 2009 — SquashFS merged into mainline (2.6.29), becomes the live-media standard
- 2014 — OverlayFS merged (3.18) — the modern writable-layer mechanism
- Present — every mainstream live image is some arrangement of exactly these parts
See also
- LFS Kernel and Boot — chapter 6, the system this image carries
- LFS Installing — the next chapter: the live env installs the system
- GRUB — the dual-platform builds
grub-mkrescueconsumes - BLFS — where the six toolchain packages live
- Linux Security — LoadPin, IMA appraisal, and why pinning exists
- Inside a Linux System —
switch_roothands off to what this article describes