Skip to content

fix(uki): harden reassembly, add stub-258 CI coverage, patch embedded kernel ImageBase - #138

Merged
imlk0 merged 6 commits into
masterfrom
review-uki-section-fix
Sep 21, 2026
Merged

imlk0 merged 6 commits into
masterfrom
review-uki-section-fix

Conversation

@imlk0

@imlk0 imlk0 commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #137 (fix(uki): correct malformed section layout in UKIs generated by legacy dracut). Three concerns: harden uki_reassemble, add --uki-stub-version 258 CI coverage, and patch the kernel embedded in the UKI so systemd stub 258/259 can boot older kernels.

1. uki_reassembly robustness (review feedback on #137)

  • Fail fast on missing binutils — objcopy/objdump are checked at the start of the UKI block, before dracut spends minutes building the UKI.
  • Guarantee scratch cleanup on early exit — a RETURN trap releases the mktemp dir and any half-written .relayout on every exit path (including set -e aborts); cp/mv are guarded.
  • Audit .sbat drops — when the stub and dracut both ship .sbat with the same size, emit a NOTE so operators can audit which revocation version survives.
  • Drop redundant --image-base — the reassembly objcopy takes a byte copy of the stub as input and inherits its ImageBase from the PE optional header; pinning --image-base to the same value is a no-op (verified on binutils 2.35: outputs are byte-identical). The post-reassembly SizeOfImage sanity check still catches any regression.

2. --uki-stub-version 258 CI coverage + boot matrix

CI never passed uki_stub_version, so every UKI job used the distro stub (ImageBase=0, no SizeOfImage hole) and the reassembly fix was never exercised against a real pinned stub. This PR plumbs --uki-stub-version through tests/test-convert.sh + the Makefile, and adds two CI include rows (uki/noenc/disk on alinux3 and alinux4) carrying uki_stub_version=258 + boot_matrix="2:4G 4:8G 4:16G". The baseline 24 jobs drop the boot matrix (single boot, distro stub) to keep cost down; make imports the two vars from the step env (no inline bash -c quoting). The 2:4G entry surfaces the SizeOfImage hole on a real pinned stub at low RAM; the reassembly fix should make it boot. The boot test now also detects UEFI StartImage "Load Error" fast (instead of timing out).

3. Patch the UKI's embedded kernel ImageBase for systemd stub 258/259

systemd stub >= 258 and < 260 computes each inner kernel section's load offset as (VirtualAddress - ImageBase) and rejects the image when that underflows, printing Section would write outside of memory (systemd #40342, regression from PR #37372, fixed in systemd >= 260 by PR #40429). Kernels v5.7..v6.6 are built with ImageBase = CONFIG_PHYSICAL_START (default 0x1000000) while their section RVAs (~0x4000) are below it, so a pinned 258/259 stub cannot boot them (e.g. alinux3 5.10); alinux4 (6.6) backported the mainline v6.7 revert to ImageBase=0, so it boots.

For a pinned stub in the buggy range (< 260), uki_reassemble is followed by objcopy --dump-section .linux → patch the kernel PE OptionalHeader.ImageBase to 0 → --update-section .linux back (mirroring the existing .cmdline patching). Only the kernel embedded in the UKI is touched; /boot/vmlinuz is left byte-for-byte unchanged. Safe per the PE spec: ImageBase is the preferred load address, not used by the position-independent kernel at runtime (the stub loads it into its own base-0 buffer). No-op when ImageBase is already 0 (>= v6.7 kernels / alinux4). Caveat: changes the kernel hash, so re-sign and re-measure.

Verification

  • bash -n on cryptpilot-convert.sh and tests/test-convert.sh; cargo fmt --check; cargo build.
  • End-to-end (stub-258 + alinux3): the convert patches the UKI's .linux (PATCHED .linux.bin: PE ImageBase 0x1000000 -> 0x0); the output image's /boot/vmlinuz stays byte-identical to the source kernel; the UKI boots at 4G/8G/16G. Verified locally and in CI — the uki/noenc/disk/alinux3 stub-258 job now passes (it previously failed with Load Error).
  • All test-convert CI jobs green.

Note

The build-and-push (Docker image) job on the latest run failed on a transient mirrors.aliyun.com repo-metadata timeout (Curl error (28)), unrelated to this change — re-runnable.

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@imlk0
imlk0 force-pushed the review-uki-section-fix branch from 9378f11 to 24b8e03 Compare September 21, 2026 02:07
@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

uki_reassemble only checked for objdump after dracut had already spent
minutes building the UKI. Hoist a pre-check for both objcopy and objdump
to the start of the UKI block so a missing binutils fails fast, before
any dracut work.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
cp and mv were unguarded, and under set -e a failure (ENOSPC, EBUSY)
aborted the function before reaching 'rm -rf $dumpdir', leaking
/tmp/cryptpilot-uki-XXXXXX across runs. Add a RETURN trap that releases
the scratch dir and any half-written .relayout on every exit path, and
guard cp/mv with explicit error messages.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
When the stub and dracut both carry .sbat with identical sizes, the
stub's version is kept and dracut's is dropped. SBAT is a revocation
list, so emit a NOTE so operators can audit which version survives.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
The reassembly objcopy takes build_stub (a byte copy of the stub) as input
and inherits its ImageBase from the PE optional header; the pipeline never
modifies ImageBase. Passing --image-base=<same value> is therefore a no-op
(verified on binutils 2.35: outputs are byte-identical with and without
it), and on binutils lacking the flag it cannot be passed anyway. Remove
the flag and its feature-detection case; the post-reassembly SizeOfImage
sanity check still catches any regression.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
…stub 258/259

For a pinned systemd stub with major version < 260 (systemd fixed it in
>= 260, PR #40429), the stub's SizeOfImage math yields a wrong RVA and
the UKI fails to boot at low RAM. Zero the kernel's PE
OptionalHeader.ImageBase so the buggy stub's math yields the correct RVA.

Patch the UKI assembly path: after uki_reassemble, dump the .linux
section, patch its ImageBase to 0, and update-section it back (mirroring
the existing .cmdline patching). Only the kernel embedded in the UKI is
touched; /boot/vmlinuz is left byte-for-byte unchanged. Safe per the PE
spec: ImageBase is the preferred load address, not used by the
position-independent kernel at runtime (the stub loads it into its own
base-0 buffer regardless).

Define patch_kernel_image_base_zero inside the chroot heredoc (where
objcopy/python3 live, alongside uki_reassemble). No-op when ImageBase is
already 0 (>= v6.7 kernels / alinux4). Robust: validates MZ + PE
signature + optional-header magic (PE32+/PE32), checks for truncation,
writes + fsync + re-reads to verify. Caveat: changes the kernel hash,
so re-sign and re-measure.

Verified end-to-end: stub-258+alinux3 convert patches the UKI's .linux
(log: "PATCHED .linux.bin: PE ImageBase 0x1000000 -> 0x0"); the output
image's /boot/vmlinuz stays byte-identical to the source; the UKI boots
at 4G/8G/16G.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
…4:8G/4:16G) with --uki-stub-version 258 coverage

The convert step is the expensive part; previously the CI pinned a single
QEMU_RAM=4G per job. Replace --ram with a --boot-matrix option taking
space-separated cpu:ram tokens; the script reuses the single converted
output.qcow2 (each boot layers a fresh COW on the read-only base) and
boots every combo, so convert runs once and only the cheap boot repeats.

The matrix is scoped to two targeted rows (uki/noenc/disk on alinux3 and
alinux4) carrying uki_stub_version=258 + boot_matrix="2:4G 4:8G 4:16G".
GitHub-hosted ubuntu-latest has 4 vCPU and no nested KVM, so vCPU is
capped at <=4 (= host nproc); the RAM dimension (4/8/16 G — the one that
surfaces the UKI SizeOfImage hole) is kept. The 2:4G entry surfaces the
hole on a pinned stub at low RAM. The baseline 24 jobs no longer carry a
boot matrix (single boot, distro stub), cutting CI cost. --uki-stub-version
is plumbed through test-convert.sh + the Makefile; the two vars reach make
via the step env + docker exec --env (make imports them from the
environment), avoiding inline quoting through bash -c. zstd is installed in
the test container for the host-side Arch-Archive stub extraction.

Robustness: bump the per-boot timeout 360 s -> 540 s for headroom on a
loaded runner (TCG has no hardware acceleration on GitHub-hosted runners),
retry each failed combo once before declaring the matrix broken, and add
'failed to start Boot ...: Load Error' + 'UEFI Interactive Shell' as
failure markers so the boot test fails fast (in ~10s) when OVMF's StartImage
returns Load Error instead of waiting the full 900s.

Assisted-by: Claude:glm-5.2
Signed-off-by: Kun Lai <laikun@linux.alibaba.com>
@imlk0
imlk0 force-pushed the review-uki-section-fix branch from 24b8e03 to 0601fab Compare September 21, 2026 03:46
@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@imlk0 imlk0 changed the title fix(uki): apply review feedback + add QEMU boot vCPU/RAM matrix to CI fix(uki): harden reassembly, add stub-258 CI coverage, patch embedded kernel ImageBase Sep 21, 2026
@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

@imlk0
imlk0 merged commit 0601fab into master Sep 21, 2026
41 of 42 checks passed
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.

2 participants