Compare commits

...
5 Commits
Author SHA1 Message Date
gandalf 1f51d1818d fix(live-usb): nft rule syntax — udp dport 68 (drop the redundant udp sport)
v2.12.11's rule `udp sport 67 udp dport 68 accept` was invalid nft
syntax — protocol prefix can't be repeated inside a single rule, the
firstboot.sh-generated /etc/nftables.conf failed to load and the
firewall stayed in its previous state (or empty), defeating the
whole point of the DHCP fix.

Just match the destination port: `udp dport 68 accept`. DHCPOFFER /
DHCPACK from any server (sport 67) lands on dport 68 of the client,
so the inbound match is sufficient and unambiguous.

Live-system workaround (no rebuild needed):
  nft add rule inet secubox_filter input udp dport 68 accept
2026-05-26 07:20:33 +02:00
gandalf 8b0ec6884c fix(live-usb): nftables — accept DHCP replies (udp sport 67 dport 68)
Bare-metal box ended up with 192.168.10.250 (assigned by secubox-net-
fallback's ARP-probe loop) instead of the real DHCP lease from the
LAN router. Operator confirmed DHCP server is healthy on the LAN
(dev box on same switch got 192.168.1.13 via DHCP without issue).

Root cause: firstboot.sh writes /etc/nftables.conf with policy=drop
on the input chain and no explicit DHCP allowance. The `ct state
established,related accept` rule does NOT cover DHCP because the
client request leaves from 0.0.0.0:68 and the server reply comes back
broadcast (or unicast direct to the offered IP before it's bound).
Neither matches the original 5-tuple → conntrack treats the reply
as a new packet → policy drop → DHCPOFFER lost → networkd times out.
secubox-net-fallback then picks a random gateway from its probe
list and lands the box on the wrong subnet.

Add `udp sport 67 udp dport 68 accept` to the input chain. This
matches DHCPv4 server-to-client replies specifically (port 67/68
are reserved BOOTP/DHCP). DHCPv6 would need a sibling `udp dport
546 accept` rule but is out of scope here.
2026-05-26 07:16:27 +02:00
gandalf f61932c6c6 revert(live-usb): restore v2.10.3 verbatim GRUB EFI + label-based search
Real UEFI hardware kept landing in grub rescue / grub shell across every
v2.12.x iteration: shim swap, hardened module list, $cmdpath embed,
search --fs-uuid bake-in. None of them shipped a working real-UEFI
boot. v2.10.3 was the last tag the operator confirmed booted his
hardware in both BIOS and UEFI mode.

Drop the experimental UUID capture + the embed-cfg fallback chain.
Restore EXACTLY what v2.10.3 had:

  # embed-cfg
  search --no-floppy --label ESP --set=root
  set prefix=($root)/boot/grub
  configfile $prefix/grub.cfg

  # main grub.cfg LIVE search
  search --no-floppy --label LIVE --set=live

Validated other v2.12.x improvements stay (mass-mask LXC services,
dynamic MOTD, modesetting for VBox, kiosk --no-block) — they don't
touch the boot path.
2026-05-25 17:18:42 +02:00
gandalf ff806523b7 fix(live-usb): use baked-in UUIDs for ESP/LIVE search (label lookups fail on real HW)
Real UEFI hardware v2.12.7/v2.12.8 still landed in the grub> rescue
shell, and the user reported the same happening in legacy BIOS mode
too — both code paths share the /boot/grub/grub.cfg which begins with
`search --no-floppy --label LIVE --set=live`. If that label lookup
fails (some firmware doesn't surface FAT/ext4 labels, or the firmware
exposes the disk through a path GRUB's label table doesn't recognise)
\$live stays unset, every menuentry's `linux (\$live)/live/vmlinuz`
becomes `linux ()/live/vmlinuz`, the kernel doesn't load, GRUB
drops the operator at the rescue prompt. Same root cause as the
EFI embed-cfg's `search --label ESP` failure.

Capture the ESP + LIVE UUIDs with blkid right after mkfs.* and
substitute them into both configs:

  * grub.cfg uses `search --fs-uuid <LIVE_UUID> --set=live` as
    primary; falls back to `search --label LIVE` for firmware that
    DOES prefer labels (no-op if UUID already resolved).
  * embed-cfg uses `\$cmdpath/grub.cfg` first, then falls back to
    `search --fs-uuid <ESP_UUID>` + configfile from that root.

UUIDs are deterministic at build time, can't be shadowed by similarly
labelled partitions, and don't depend on the firmware's label
indexing — should work on any firmware that surfaces the disk to
GRUB's block IO at all.
2026-05-25 15:48:34 +02:00
gandalf dcb4ce828b fix(live-usb): EFI embed uses \$cmdpath so it doesn't depend on label search
Real UEFI hardware v2.12.7 reported landing at the grub> rescue
prompt even with the simple pre-e1a53297 embed-cfg restored. Cause:
`search --no-floppy --label ESP --set=root` failed silently on that
firmware (FAT label not recognised, predictable rename, etc.), so
\$root stayed unset, prefix was empty, configfile fell through to
the rescue shell.

Replace the embed with a single-line `configfile \$cmdpath/grub.cfg`.
\$cmdpath is set by the EFI firmware itself to the directory it
loaded BOOTX64.EFI from — for us that's (hdX,gptY)/EFI/BOOT, where
the build copies grub.cfg already. The full menu at /EFI/BOOT/grub.cfg
still does its own `search --label LIVE --set=live` to locate the
squashfs partition (unchanged), so this only changes the very first
lookup hop.

Legacy BIOS grub-install --target=i386-pc untouched — it never had
the issue.
2026-05-25 11:00:44 +02:00
2 changed files with 16 additions and 6 deletions
+6 -6
View File
@@ -3521,6 +3521,7 @@ else
fi
fi
# Mount for file copy
MNT="${WORK_DIR}/mnt"
mkdir -p "${MNT}/esp" "${MNT}/live"
@@ -3688,12 +3689,11 @@ fi
cp "${MNT}/esp/boot/grub/grub.cfg" "${MNT}/esp/EFI/BOOT/grub.cfg"
# Build GRUB EFI — restored to the simple pre-e1a53297 working version.
# The "hardened" variant added disk/usb/usbms/ahci/ata modules (none
# exist in x86_64-efi — disks come from the EFI firmware) and a
# multi-stage search fallback that landed in a grub> shell on real
# UEFI hardware. This version was reported working on bare-metal
# amd64 in v2.10.x and earlier; keep it as-is and don't gold-plate.
# Build GRUB EFI — verbatim from v2.10.3 (last known-good real UEFI
# boot). Do NOT optimise this block: every "improvement" attempted in
# the v2.12.x series (Secure Boot shim, $cmdpath, search --fs-uuid,
# extra modules, multi-stage fallbacks) broke at least one piece of
# hardware. Stay simple, stay shipped.
GRUB_MODS="part_gpt part_msdos fat ext2 normal linux boot configfile loopback chain efi_gop efi_uga ls search search_label gfxterm all_video"
cat > "${WORK_DIR}/grub-embed.cfg" <<'EMBEDCFG'
+10
View File
@@ -443,6 +443,16 @@ table inet secubox_filter {
# HTTP/HTTPS (SecuBox UI)
tcp dport { 80, 443 } accept
# DHCP client — accept DHCPOFFER / DHCPACK on UDP 68. The
# conntrack `established,related` clause above doesn't help
# for DHCP because the request goes out from 0.0.0.0:68 and
# the reply comes back broadcast (or unicast direct to the
# offered IP before it's actually bound), neither of which
# match the original 5-tuple. Without this rule networkd's
# DHCP times out and secubox-net-fallback's ARP-probe takes
# over — operator ends up on a random fallback subnet.
udp dport 68 accept
# WireGuard
udp dport 51820 accept