Skip to content

Stop embedding a boot script in the EFI binaries - #7

Merged
mastacontrola merged 1 commit into
masterfrom
embedless-efi
Aug 18, 2026
Merged

Stop embedding a boot script in the EFI binaries#7
mastacontrola merged 1 commit into
masterfrom
embedless-efi

Conversation

@mastacontrola

Copy link
Copy Markdown
Member

Every EFI target is now built without EMBED=, so it downloads autoexec.ipxe and executes it. autoexec/ — the opt-in duplicate tree that used to be the only place an EMBED-less binary lived — is gone, because the root now is that build. 10secdelay/ keeps its BIOS files and loses its EFI ones.

Why

An embedded script is compiled into 15 binaries, so changing FOG's boot logic meant a toolchain and a 20-minute rebuild. That is why the EMBED-less variant was added (GH-957) — and then left as an opt-in nobody opted into, because opting in meant knowing the difference existed and editing DHCP.

It is also the only shape that works under Secure Boot: efi_autoexec.c is FILE_SECBOOT ( PERMITTED ) and an embedded script is not.

Why the root could not simply gain an autoexec.ipxe before

efi_probe() calls efi_autoexec_load() unconditionally, so an EMBED-marked binary still downloads the script — it just never runs it, because first_image() returns the embedded one ahead of it. Nothing then unregisters it, and at boot initrd_load_all() concatenates every registered non-hidden image into the ramdisk in registration order. autoexec.ipxe registered first, so the kernel gets 2 KB of iPXE script where init.xz's compression magic should be, and panics:

VFS: Unable to mount root fs on "/dev/ram0" or unknown-block(1,0)

(forums #18213). And efi_autoexec_network() falls back to /autoexec.ipxe when the binary's own directory has none — so one embedded EFI binary anywhere in the tree was enough to poison every client that fell back to the root. Hence the quarantine under autoexec/, and hence the installer deleting any autoexec.ipxe it found at the root.

Removing EMBED= from every EFI target removes the constraint instead of working around it. An EMBED-less binary executes the script, and image_exec() unregisters it for the duration, so it is gone before boot runs.

The 10-second delay

10secdelay/ existed because the delay was two lines — an echo and a sleep — compiled in. On EFI that is now an edit to autoexec.ipxe, which fogproject's installer makes via a new --boot-delay. Legacy BIOS has no efi_autoexec_load() and therefore no script to edit, which is why 10secdelay/ survives with BIOS files only.

src-efi/ipxescript and src-efi/ipxescript10sec are deleted — nothing reads them now. src/ipxescript stays; the BIOS binaries still embed it.

Verified

  • strings(1) on the built EFI binaries finds no Checking net0 for DHCP, while finding 15 other iPXE strings — so the absence is real, not an artefact of compression.
  • BIOS still carries two distinct embedded scripts: undionly.kkpxe 102977 bytes vs 10secdelay/undionly.kkpxe 103060.
  • tools/check-linked-objects.sh passes unchanged on all three baselines (340/341/338 objects). Dropping EMBED= changes which script bytes land in embedded.o, not which objects the linker pulls in, so no option drifted.

Breaking

A DHCP filename beginning autoexec/ stops resolving. The replacement is the same name without that prefix. FOG's own generated dhcpd.conf/Kea config never used those paths, so only hand-written configs are affected; fogproject's installer removes the stale directory and prints the mapping.

Pairs with FOGProject/fogproject#TBD.

Every EFI target is now built without EMBED=, so it downloads autoexec.ipxe
and executes it. autoexec/ -- the opt-in duplicate tree that used to be the
only place an EMBED-less binary lived -- is gone, because the root now IS
that build. 10secdelay/ keeps its BIOS files and loses its EFI ones.

WHY

An embedded script is compiled into 15 binaries. Changing FOG's boot logic
therefore meant a toolchain and a 20-minute rebuild, which is why the
EMBED-less variant was added in the first place (GH-957) -- and then left as
an opt-in nobody opted into, because opting in meant knowing the difference
and editing DHCP.

It is also the only shape that works under Secure Boot: efi_autoexec.c is
FILE_SECBOOT ( PERMITTED ) and an embedded script is not.

WHY THE ROOT COULD NOT SIMPLY GAIN autoexec.ipxe BEFORE

efi_probe() calls efi_autoexec_load() unconditionally, so an EMBED-marked
binary still DOWNLOADS the script -- it just never runs it, because
first_image() returns the embedded one ahead of it. Nothing then unregisters
it, and at boot initrd_load_all() concatenates every registered non-hidden
image into the ramdisk in registration order. autoexec.ipxe registered first,
so the kernel gets 2 KB of iPXE script where init.xz's compression magic
should be and panics:

    VFS: Unable to mount root fs on "/dev/ram0" or unknown-block(1,0)

(forums #18213). And efi_autoexec_network() falls back to /autoexec.ipxe when
the binary's own directory has none -- so ONE embedded EFI binary anywhere in
the tree was enough to poison every client that fell back to the root. That
is why the EMBED-less binaries had to be quarantined under autoexec/ and why
the installer deleted any autoexec.ipxe it found at the root.

Removing EMBED from every EFI target removes the constraint rather than
working around it. An EMBED-less binary EXECUTES the script, and image_exec()
unregisters it for the duration, so it is gone before boot runs.

THE 10-SECOND DELAY

10secdelay/ existed because the delay was two lines -- an echo and a sleep --
compiled in. On EFI that is now an edit to autoexec.ipxe, which fogproject's
installer makes via --boot-delay. Legacy BIOS has no efi_autoexec_load() and
so has no script to edit, which is why 10secdelay/ survives with BIOS files
only.

src-efi/ipxescript and src-efi/ipxescript10sec are deleted: nothing reads them
now. src/ipxescript stays -- the BIOS binaries still embed it.

VERIFIED

  - strings(1) on the built EFI binaries finds no "Checking net0 for DHCP",
    while finding 15 other iPXE strings, so the absence is real and not an
    artefact of compression.
  - BIOS still carries two distinct embedded scripts: undionly.kkpxe 102977
    bytes vs 10secdelay/undionly.kkpxe 103060.
  - tools/check-linked-objects.sh passes unchanged on all three baselines
    (340/341/338 objects). Dropping EMBED changes which script bytes land in
    embedded.o, not which objects the linker pulls in, so no option drifted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant