LamBoot v0.16.5
Product page · Install · Documentation · by Lamco Development LLC
First public release since v0.15.2. This release brings the public tree current
with development versions v0.16.0 through v0.16.5; the per-version changes below
are reproduced verbatim from the project CHANGELOG. The release is GPG-signed
(see "Verifying this release" at the end).
[0.16.5] — Dependency pins: lamfat 0.4.2 + lamzfs 0.1.1
A dependency-sourcing patch with no change to boot behavior. The native FAT and
ZFS readers move to freshly republished crate versions.
Changed
FatRonow consumeslamfat=0.4.2— a republish of the read-only
FAT reader without thefscommondependency. Read behavior is byte-for-byte
identical; this trims a transitive dependency from the FAT-backend layer.lamzfspinned to=0.1.1, which moves its LZ4 block decompressor from
lz4_flex0.11 to 0.13. The ZFS boot-pool reader decodes the same blocks;
this is a dependency refresh with no behavior change.
Infrastructure
- SBAT version string aligned to
0.16.5(generation column unchanged at1:
human-facing string only, no revocation).
[0.16.4] — Kernel-upgrade BLS entries fixed on XFS /boot (kernel hook)
A kernel upgrade on an XFS /boot (RHEL/Rocky/Alma/CentOS — surfaced by a RHEL
9.7 → 9.8 upgrade) produced an unbootable, red-X BLS entry for the new
kernel: lamboot-kernel-hook (the incremental writer invoked by
kernel-install / the Debian kernel hooks) had two bugs that only bit XFS and
kernel-install-driven distros. The bootloader binary is unchanged; this is a
host-side tooling fix.
Fixed
lamboot-kernel-hooknow writes XFS/bootentries in place, not on the
ESP. Itsresolve_bls_dirplacement set wasvfat|ext2|ext3|ext4|btrfs—
missingxfs, so it never picked uplamboot-install's v0.16.0 "xfs →
boot_in_place" change and wrote the new kernel's entry to the ESP instead of
the XFS/boot.- The
linuxpath now references the/bootkernel copy, not kernel-install's
source image. On Fedora/RHEL/CentOS,kernel-install addpasses
/lib/modules/<version>/vmlinuz(the package staging path); the hook copied
that into the BLSlinuxfield (mangled to//lib/modules/...) instead of the
bootable/boot/vmlinuz-<version>copy → LamBoot couldn't find the kernel
(preflight red X). It now prefers a/boot-located image, else
/boot/vmlinuz-<version>;bls_pathis hardened against the//double-slash. - Placement parity is now build-enforced.
tools/check-fs-coverage-parity.py
additionally asserts the hook's in-place set equals
is_filesystem_natively_coveredminus zfs (the lamzfs read-in-place deferral).
The hook can no longer silently drift from the installer — the exact regression
class behind this fix. (zfs stays ESP-placed in both, by design.)
[0.16.3] — Robust partition discovery (MBR) + bootloader NVRAM self-install
Robustness work surfaced by the first RHEL-family validation (RHEL 9.7, a BIOS
install converted to UEFI). LamBoot now discovers and boots a Linux install whose
/boot is a plain filesystem on a legacy-MBR disk — the canonical layout of
a BIOS-installed RHEL/Rocky/Alma/CentOS — and manages its own persistent UEFI
boot entry directly from the firmware environment.
Added
- Bootloader-side NVRAM self-install of the
LamBootboot entry. LamBoot now
ensures a labeledBoot####entry pointing at\EFI\LamBoot\lambootx64.efi
exists, creating it (and front-loadingBootOrder) from the UEFI environment
if absent. This is the OS-independent pathway for the persistent entry: no
efibootmgr, no OS, and on SELinux-enforcing distros no confined-service block
in the way (Boot####/BootOrderare non-authenticated, so no Secure Boot
keys are involved). Idempotent — it keys on the exactLamBootdescription, so
it never duplicates or churns NVRAM and coexists with the OS-sideefibootmgr
pathway. New moduleboot_entry(UEFI I/O) overboot_entry_pure(the
byte-exactEFI_LOAD_OPTION/BootOrdercodecs, host-tested). [boot-entry] self_installpolicy gate (default on; setfalseto
opt out for operators who manage firmware boot order externally).
Fixed
- Partition discovery now covers MBR and BlockIO-only partitions, not just
GPT.scan_discoverable_partitionspreviously consumed only GPT entries from
thePartitionInfoprotocol, so a BIOS-installed disk with anmsdostable
(e.g. RHEL's XFS/bootas a primary partition) yielded zero discovered
partitions and its/bootwas never mounted — LamBoot showed no entries and
fell into the fallback self-loop. It is now a three-source enumerator,
de-duplicated by handle: GPT viaPartitionInfo, MBR via
PartitionInfo.mbr_partition_record()(classified by a host-testedos_type
predicate), and BlockIO-only logical partitions for firmware that installs
PartitionInfoon the ESP alone. Every native FS backend (lamxfs/ext4/btrfs/
exfat/zfs/LVM/media) picks them up unchanged. - The fallback self-loop guard now actually fires. The old guard compared the
on-disk\EFI\BOOT\BOOTX64.EFIagainst the in-memory, firmware-relocated
running image — hashes that never match — so a no-entries boot would offer and
auto-select the fallback, chainloading LamBoot into itself. Replaced with a
reliable path check: if LamBoot was launched from the removable fallback path,
that synthetic is suppressed and the recovery menu shows instead. - First-boot NVRAM service no longer retries forever. A persistently-blocked
write (e.g. a mislabeled binary on enforcing SELinux) now fails non-fatally
after a bounded number of attempts with an actionable message, instead of
re-running every boot. - Installer relabels its files for SELinux (
restorecon). A hand-deployed
(non-rpm) install copied through/tmpleaves files labeleduser_tmp_t,
whichinit_tmay not execute — so the first-boot service's exec of
lamboot-install(a symlink into/usr/share/lamboot) was denied on enforcing
RHEL.lamboot-installnow runsrestoreconon its installed files +
payload dir when SELinux is enabled (idempotent no-op on rpm/non-SELinux).
This is the correct fix; no custom SELinux policy module is shipped.
[0.16.2] — Fix: installer misclassified its own old fallback as systemd-boot
A point fix for the upgrade path on systems whose firmware boots LamBoot via the
removable-media fallback \EFI\BOOT\BOOTX64.EFI (e.g. a Proxmox VM whose ESP
lives on a disk not in the VM's boot: order, where named NVRAM entries don't
persist). On those systems lamboot-install --update --fallback aborted and the
upgrade never reached the binary the firmware actually loads.
Fixed
identify_bootloadernow detects LamBoot before systemd-boot. LamBoot's
own binary embeds the stringsystemd-boot(its SecurityOverride mirrors
systemd-boot's ShimLock dance), and the loader-classifier grepped for
systemd-bootbefore the LamBoot self-check — so an existing LamBoot
fallback was misclassified as a foreign systemd-boot, andinstall_fallback
refused to refresh it without--replace-fallback. The LamBoot check now runs
first; an old LamBoot fallback is correctly recognized as our own and updated
in place on--update --fallback. Covered by a new
tools/tests/installer/identify_bootloader.batsregression suite.
Added
- Install-time warning when the ESP is on a separate disk from the OS root.
On a hypervisor whose firmware only boot-indexes the disks in the VM'sboot:
order (Proxmox/QEMU OVMF), a named LamBoot NVRAM entry pointing at a
non-boot-indexed disk is pruned on reboot — so an upgrade silently reverts to
booting the fallback.lamboot-installnow detects this (ESP parent disk ≠ OS
root disk undersystemd-detect-virt) inwarn_if_esp_on_separate_disk()and
warns with the actionableqm set --bootfix (or--fallback), plus an
esp_on_separate_disktrust event. Tested by
tools/tests/installer/warn_esp_disk.bats.
[0.16.1] — Fix: goblin 0.9.3 could not boot Linux kernels (native PE loader)
A hotfix for a boot regression introduced in 0.16.0. The goblin PE-parser pin was
moved =0.10.5 → =0.9.3 to align with the Debian archive, but goblin 0.9.3's
Header::parse rejects the Linux EFI-stub layout — the kernel omits the MSVC DOS
stub (e_lfanew == 0x40), and 0.9.3's DosStub::parse fails the end_offset <= start_offset check (0.10.5 relaxed it to <). Every native-PE Linux-kernel load
therefore failed with pe_parse_failed, dead-ending the boot — observed as the VM
powering off on kernel selection. SB-off, directly-signed, and MOK kernels booted via
the native loader are all affected; a default-config Linux boot does not complete.
Fixed
- Native PE loader no longer depends on
goblin. The singlegoblin::Header::parse
call is replaced by a hand-rolledno_stdPE/COFF reader that reads only the
load-bearing COFF + PE32+ optional-header fields from their fixed offsets and never
parses the MSVC DOS stub or Rich header — the structures goblin 0.9.3 mis-validated.
number_of_rva_and_sizesbounds the data-directory accessors (Linux kernels ship
fewer than the full 16). PE32 (0x10b) is rejected cleanly.goblin— and its
transitiveplain/scrolldeps — leave the dependency tree entirely, which is what
the Debian archive needs. Verified end-to-end: the exact kernel 0.16.0 rejected now
loads withimage_loaded_native … SUCCESS. boot_linuxgains a native → firmwareBS->LoadImagefallback. A native-PE
parse/load failure on a Linux kernel is no longer terminal — it degrades to a firmware
boot (logged askernel_native_load_fallback) instead of an unbootable system. The ISO
path already had this; it now covers BLS kernels too.
Changed
- Installer native-filesystem coverage synced with the runtime.
xfs/zfsare now
native (lamxfs/lamzfs), solamboot-installno longer installs their legacy GPLv3
drivers; a separate XFS/bootbecomes read-in-place. ZFS/bootstays ESP-staged
untillamzfsis field-soaked across pool topologies (the driver-skip still applies).
The--capabilitiesJSON movesxfs/zfstonative. A new
tools/check-fs-coverage-parity.py(pre-commit + CI) pins the installer's list to
lamboot-core/src/drivers.rsso the two cannot silently drift again.
[0.16.0] — Native XFS / exFAT / ZFS readers + Boot-from-ISO + the lamfold media stack
The biggest de-bundling release since the native ext4/btrfs readers landed. LamBoot
now reads four more on-disk formats natively and read-only — XFS, exFAT, ZFS, and a
six-filesystem read-only media stack (EROFS, ISO 9660, SquashFS, cramfs, romfs, UDF) —
without leaning on a firmware filesystem driver or a GPLv3 EfiFs *.efi for any of them.
Together these close the last large gaps in the de-bundling map: XFS is the default
/boot and / across the RHEL family, ZFS covers the Ubuntu/Debian root-on-ZFS bpool
pattern, exFAT covers >4 GiB removable boot media, and the media stack covers immutable
and live-media images. A new, opt-in boot-from-ISO capability lets an operator boot a
distribution directly from an .iso on a mounted volume or from a physical optical disc.
Every new backend is read-only by construction — there is no write path and the ESP
writer only ever targets the FAT backend — and nothing in this release changes a
default-config boot: both boot-from-ISO gates default off.
Added
- Native read-only XFS backend (
lamxfs). A clean-roomno_stdXFS reader replaces
the GPLv3 EfiFsxfs_x64.efidriver path (which cannot be Microsoft-signed and trips
shim 15.8'sShimLockuninstall). It mounts a whole XFS partition and — via the
source-generic dispatcher — an XFS filesystem on an LVM logical volume (the default RHEL
root layout) or inside an.isoloopback region. It derives its UUID and label from the
mounted superblock, decodes real on-disk POSIX modes, follows leaf symlinks, caps
up-front allocations against a hostile inode size, and turns structural and CRC failures
into stable error tokens. XFS is the only one of the three new whole-partition readers
that exposes a real filesystem UUID/label and decodes on-disk modes. Read-only by
construction. - Native read-only exFAT backend (
lamexfat). Ano_stdexFAT reader for
removable/utility boot media — a kernel+initrd or a boot image on an exFAT-formatted USB
stick or SD card, including the >4 GiB payloads FAT32 cannot hold. exFAT is never the
ESP and never a Linux root, so it does not overlap the ext4/btrfs/xfs/FAT backends; it
mounts only whole partitions identified by theEXFATboot-sector magic and is
intentionally not wired into the LV/.isodispatcher. The reader handles both
FAT-chained and contiguous (NoFatChain) files, up-case-table case-insensitive lookup,
and entry-set checksums, and caps allocations against a hostileDataLength. exFAT
carries no 128-bit UUID or POSIX modes, so metadata is synthesized read-only and
uuid()returnsNone. Read-only by construction. - Native read-only ZFS boot-pool backend (
lamzfs). LamBoot can now read kernels and
initrds directly from an unencrypted ZFS boot pool (the Ubuntu/Debian root-on-ZFS
bpoolpattern) with no OpenZFS kernel module and no GPL UEFI filesystem driver. A pool
is imported once from its member partitions — grouped by pool GUID via
lamzfs::peek_pool_idbefore mount — and each dataset is presented as its own read-only
volume; reads, stats, ranged reads, existence checks, and directory enumeration are all
dataset-scoped. Supported vdev topologies are single disk, mirror, and (per spec)
single-parity RAIDZ1 with XOR degraded reconstruction; RAIDZ2/RAIDZ3, dRAID, multiple
top-level vdevs, allocation-class/special vdevs, and native encryption are rejected
cleanly with a typed error. All six OpenZFS block compressors (off, zle, lzjb, lz4,
gzip, zstd) decode, and a block whose checksum fails surfaces as an integrity error
rather than a generic parse failure. The backend isforbid(unsafe_code)and read-only
by construction. ZFS pools carry a 64-bit GUID rather than a 128-bit filesystem UUID, so
uuid()returnsNoneand datasets are identified by label and index; on-disk metadata
modes are synthesized read-only. Scope note: mirror healing and RAIDZ1 reconstruction
are supported per the lamzfs v0.1 spec; the live-boot validation in this release
exercised a single-vdev lz4 pool, so RAIDZ1/mirror-repair behavior should be treated as
spec-supported, not yet field-soaked. - Native read-only media filesystem stack (
lamfold): EROFS, ISO 9660, SquashFS,
cramfs, romfs, UDF. LamBoot now mounts six read-only media filesystems natively at
boot through the Lamco-authoredno_stdlamfold stack, without a firmware FS driver.
Each is identified by a superblock-magic probe (UDF via a targeted sector-256
Anchor-Volume-Descriptor read) and dispatched over the genericBlockSourceseam to a
singleLamfoldBackendadapter, so a standalone media-FS partition (an EROFS or
SquashFS root or/boot) is mounted as an ordinary read-only volume and scanned for
kernels/BLS entries. EROFS reads uncompressed, LZ4, and the compressed-COMPACT codec set
(deflate / zstd / MicroLZMA); SquashFS reads gzip/xz/zstd/lz4/lzo; ISO 9660 reads
zisofs. Every lamfold backend is read-only by construction (read_onlyis hardcoded
true and no write path exists). Media mounts are currently unverified (read-only, but
no integrity/trust-root verification of media content yet); a Merkle trust-root path is a
later pass. cpio is linked as a lamfold frontend but is deliberately not auto-probed or
wired into mount dispatch — it is not a usable boot filesystem in this release. - Boot a distribution ISO from disk or a physical optical drive (opt-in, off by
default). With[boot-from-iso] enabled, an operator can boot a Linux distribution
directly from an.isofile on a mounted volume (ext4/btrfs/xfs/FAT, including the ESP);
withoptical = true, from an inserted CD/DVD/BD. ISO discovery scans/isosand
/boot/isosfor*.iso; optical discovery enumerates 2048-byte-sectorBlockIO
handles carrying aCD001primary volume descriptor (a discriminator that structurally
excludes add'd isohybrid USB, so it is never double-listed). A file-hosted ISO is read
through aFileBlockSourceover the holding backend's already-open handle (so reading an
ISO off the ESP never disconnects the FAT driver); an optical disc is read through a
non-exclusive sharedBlockIOopen (an exclusive open isACCESS_DENIEDwhile the
firmware ISO9660 driver holds the discBY_DRIVER). The kernel and initrd are read off
the mounted ISO and handed off through the same measure/verify/initrd-register path as a
normal Linux boot. Because a distribution kernel is a Linux EFI-stub PE that LamBoot's
native loader cannot load, the ISO path falls back from the native loader to firmware
LoadImageon a load error. This is experimental and opt-in; only Arch 2026.05 and
Fedora 44 are live-ISO-validated end to end (see below). loopback.cfgresolution (Path A1) and a per-distro-family fallback table (Path A2).
For a file-hosted ISO, LamBoot first parses the distribution's own
/boot/grub/loopback.cfg, extracting the kernel, first initrd, and command line from the
first bootablemenuentryand substituting${iso_path}with the real path — so the
distribution's exact iso-find token (iso-scan/filename=,findiso=,root=live:) is
reused with no per-distro knowledge. When no usableloopback.cfgexists (and always for
a directly-booted optical disc, which has no${iso_path}), LamBoot fingerprints the
distro family by marker paths and applies a static recipe table covering six families —
arch, ubuntu-casper, debian-live, fedora, opensuse, alpine — each transitively covering
its derivatives (Mint, Pop!_OS, EndeavourOS, Manjaro, CachyOS, RHEL, Rocky, Alma, Nobara,
and more). Each recipe carries amedia_cmdline({label}, disc self-locates by volume
label) and afile_cmdline({iso}, loop-booted from a file). Kernel resolution takes the
first candidate that resolves (with trailing-*prefix-glob support for version-stamped
names); initrd resolution concatenates every candidate that resolves, microcode first.
The fedora recipe is keyed on/LiveOS/squashfs.imgso it survives the Fedora 44 layout
change. NixOS and Gentoo are intentionally excluded. Validation status: only Arch 2026.05
and Fedora 44 are live-booted end to end (A2 live-VM matrix pass 1); the other four
families and all derivatives are recipe/table-validated and host-unit-tested, not yet
live-booted. El Torito chainload (Path B) is not yet wired.
Changed
FatRobackend now consumes the publishedlamfatcrate. The native read-only FAT
backend (for non-ESP FAT volumes the firmware refuses to serve) previously depended on a
git-pinned commit ofrust-fatfs; it now depends onlamfat = "=0.4.0"from crates.io —
Lamco's republish of exactly that commit — imported under the local namefatfs
(package = "lamfat") so the backend code is byte-for-byte unchanged. Behavior is
identical; this removes the last git-pinned dependency from the filesystem-backend layer
and brings the FAT reader under the same exact-pin drift discipline as the other readers.
Still read-only by construction — theFatRotag is rejected by the ESP writer.- Stable Rust toolchain (nightly pin dropped).
rust-toolchain.tomlswitches its
channel fromnightlytostable:lamboot-core, the diagnostic modules, and both the
x86_64-unknown-uefiandaarch64-unknown-uefitargets compile with zero nightly
feature gates (verified on rustc 1.96.0). The UEFI crates still build
core/alloc/compiler_builtinsfrom source via the per-crate-Z build-stdflags;
those unstable cargo flags are unlocked on a stable compiler throughRUSTC_BOOTSTRAP=1
rather than a nightly toolchain. This is what makes a from-source build on a distribution's
archive rustc possible. - Dependency pins aligned to the Debian archive. The build now pins
goblin =0.9.3
(down from 0.10.5 — the PE loader uses onlyHeader::parseand thedata_directories
getters and bypasses goblin's full parser, so 0.9 suffices and avoids a 0.10 transition
that breaks seven archive rdeps),lambutter =0.3.1,lamlvm =0.1.1, andsha2 =0.10.9.
Read behavior is identical; this is a provenance/buildability change so the same source
compiles unmodified against Debian's library set.
Fixed
- Native ZFS backend not reached at boot (driver shadowing + slot-0 uberblock probe).
A live OVMF/QEMU boot against a real ZFS pool exposed two runtime-only bugs that
prevented the native ZFS backend from ever mounting. First, the bundled GPL EfiFs
filesystem drivers were loaded for any filesystem not marked natively covered; ZFS and
XFS were missing from that list, so the legacy EfiFs driver attached to the partition
BY_DRIVERand exposed it as a genericSimpleFileSystem, shadowing the native backend
— and the native probe's exclusive open is then refused on firmware that will not
force-disconnect the driver. The fix markszfs_/xfs_driver filenames as natively
covered so those drivers are skipped (exFAT ships no legacy driver and needs no entry).
Second, the ZFS superblock probe only inspected slot 0 of the 128 KiB uberblock array,
but the active uberblock rotates bytxg % slot_countand the on-disk txg starts at 4,
so a freshly created pool leaves slot 0 zeroed and the probe missed the pool entirely;
the probe now scans the whole array at the 1 KiB minimum-slot stride and accepts the
uberblock magic in either endianness (also fixing a prior big-endianu32read that
never matched a little-endian x86 pool). After both fixes a live boot probes the pool and
mounts its root,BOOT, andBOOT/testdatasets end to end. - Graceful abort instead of panic on UEFI-helpers init failure. The entry point and the
four diagnostic modules now returnStatus::ABORTEDwhenuefi::helpers::init()fails,
instead of panicking via.expect(...). On firmware where helper init cannot complete
this surfaces a clean UEFI error status rather than an unwinding panic. Part of a wider
lint cleanup that also resolved advisoryunwrap_used/expect_usedsites and removed
three dead functions; no functional change beyond the init path.
Infrastructure
- Filesystem readers unified on one
BlockSourceseam. The storage layer was
refactored onto a single block-source abstraction with no change to boot or read
behavior.block_source.rsintroduces theBlockSourcetrait (Seam A) and one generic
SourceReader<S>adapter (Seam B) whose singlefill_atloop implements both
ext4-view'sExt4Readandlambutter'sBlockRead, replacing two byte-for-byte
duplicated LV adapters. Seam C then folds the three near-identical UEFIBlockIOreaders
into oneBlockIoSource, with the block-alignment math (compute_aligned_read) moved
verbatim and still fuzzed (71.5M execs, 0 crashes). Whole-partition ext4/btrfs now mount
overSourceReader<BlockIoSource>. A source-genericdispatch_fs_over_source/
probe_source_superblockAPI also lands; it is the plumbing the new XFS/media/boot-from-ISO
paths dispatch through. 168 host tests pass. - Lint-clean across UEFI and host crates.
lamboot-coreand thelamboot-fs-tests
host suite build clean of clippy and compiler warnings: unused goblin imports removed,
dead functions deleted, infallible-conversion and acronym lints suppressed with
documented#[expect(...)]reasons. No behavior change. - Pre-commit hook brought into lockstep with CI. The placeholder-marker scan
(XX/FIXME/PLACEHOLDER/YYYY) now also covers the sharedlib/shell
libraries, and the pre-commit hook now runs the stricter acyclic module-graph check
(check-layers.py --graph) plus the same placeholder scan CI runs. This closes a gap
where ablock_source⇄fs_backend_lvm_dispatchimport cycle could pass the local hook
but fail CI.
Verifying this release
# Import the signing key (Lamco Development LLC release key)
gpg --recv-keys CA11F781516743D5D9A1A12F17B95B68A50CD3A7
# Verify the detached signature and the checksum
gpg --verify lamboot-0.16.5-x86_64.tar.gz.asc lamboot-0.16.5-x86_64.tar.gz
sha256sum -c lamboot-0.16.5-x86_64.tar.gz.sha256License: MIT OR Apache-2.0. © Lamco Development LLC.