Skip to contentSkip to Braille Studio
ALB Wiki

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:

PackageVersion (measured)Job
busybox1.37.0The initramfs's entire userspace — one statically linked binary
cpio2.15Packs the initramfs (newc format is the kernel's own archive)
squashfs-tools4.7Compresses the whole root filesystem into the live image
xorriso1.5.6.pl02Writes ISO9660/El Torito — also grub-mkrescue's engine
mtools4.0.43Builds the FAT ESP image grub embeds for UEFI boot
dosfstools4.2mkfs.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 xstat declarations. make CFLAGS='-O2 -std=gnu11'.
  • squashfs-tools 4.7: LZO_SUPPORT/LZ4_SUPPORT default 1 in the Makefile — passing only your wanted compressors still compiles LZO/LZ4 code and dies on missing headers. Pass explicit LZO_SUPPORT=0 LZ4_SUPPORT=0. Its make install then fails after installing all binaries, generating manpages with a non-builtin echo error — harmless.
  • xorriso: xorriso-1.5.6.pl02.tar.gz extracts to xorriso-1.5.6/ — the .pl02 is absent from the directory name.
  • GRUB needs FreeType for fonts: grub-mkrescue fails on a missing unicode.pf2 unless 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 -8 at /init → BINFMT_SCRIPT=m, or CRLF/BOM in the script — check bytes before suspecting the kernel.
  • Live boot fine, zero modules inside → an initramfs insmod ran first and LoadPin pinned the wrong filesystem. The initramfs must load nothing.
  • old-api-denied → busybox insmod uses init_module(2); LoadPin demands finit_module(2).
  • Excluded paths "missing" in the live env → you are in the RAM overlay; nothing was deleted.

Exercises

  1. Boot the image with console=ttyS0 on the kernel line and identify the exact line where switch_root retires the initramfs — then the line where LoadPin pins its first filesystem.
  2. Remove BLK_DEV_LOOP from the builtin set, rebuild, and watch where the init script fails. Predict the failure line first.
  3. Add a file to the live env, reboot, confirm it vanished — then explain why the squashfs itself never saw it.
  4. Extract filesystem.squashfs from the ISO with xorriso -osirrox and unsquashfs one directory of it, without booting anything.

Timeline

  • 1971 — the initrd concept's ancestor: loaders staging ramdisks on minicomputers
  • 1994 — initrd enters Linux proper (1.1.x era), for modular SCSI boot
  • 2002 — initramfs/tmpfs rootfs 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-mkrescue consumes
  • BLFS — where the six toolchain packages live
  • Linux Security — LoadPin, IMA appraisal, and why pinning exists
  • Inside a Linux System — switch_root hands off to what this article describes
This page was last edited 2026-11-02 14:19:57 UTC by ALB Team. What links here