Repository navigation
fix(sysext): stop merging extensions over the persistent partition - #5115
Conversation
|
Status check, 2026-10-02 04:20Z: This PR cannot show it fixes them: |
/usr/local is where COS_PERSISTENT is mounted, and 99_sysext.yaml named six paths under it in SYSTEMD_SYSEXT_HIERARCHIES. A successful sysext merge makes every hierarchy it covers read-only: merge_hierarchy() in systemd's src/sysext/sysext.c mounts the overlay and then calls bind_remount_recursive(..., MS_RDONLY, MS_RDONLY, ...). So any machine that merged one extension lost the writable half of its persistent partition for the rest of the boot. What that breaks is not only a test. Bundles install into /usr/local/bin, and the bundled cloud-configs write scripts there in stages that run after systemd-sysext: 00_home_dir_owner_fix.yaml in the network stage and 26_selinux.yaml in initramfs. Those writes fail, and per kairos-io#4780 they fail silently. Drop every /usr/local path from the three hierarchy lists the file declares, leaving the image-owned ones. A unit test reads the shipped config back and fails if one reappears. The two test extensions still carry their payload at /usr/local/bin/hello.sh, so hello.sh no longer reaches the host. They still merge through the usr/lib/extension-release.d entry they ship, and the two specs now assert on that file. Regenerating both images with the script at /usr/bin/hello.sh restores the stronger assertion; both READMEs say so. Fixes kairos-io#5076 Signed-off-by: Ettore Di Giacinto <mudler@kairos.io>
b89fa20 to
f175bb2
Compare
…r/bin The two fixtures carried hello.sh at /usr/local/bin/, which stopped being a merged hierarchy in the previous commit, so neither spec could run the script any more and both fell back to reading the extension-release file the image carries. That is a weaker assertion: it proves the overlay is up, not that a sysext-delivered binary is reachable. Rebuild both with the payload at /usr/bin/hello.sh, which is where a sysext-delivered binary belongs, and put the command assertion back in tests/sysext_live_media_test.go and tests/uki_test.go. The merge check moves to the /usr/bin hierarchy with it. work.sysext.raw for GRUB stays verity-only and work.sysext.raw for UKI stays verity + signed with tests/assets/keys/db.key, so each still matches the image policy its boot path enforces. The UKI image drops from 22M to 1.1M because it is now built with Minimize=best like the GRUB one. hello-broke.sysext.raw is untouched: the policy rejects it before a merge, so its payload path is irrelevant. Verified against the fixtures with immucore/pkg/state/verity_signature_internal_test.go, which reads both images and checks for the verity signature partition: 13 specs, all green. Both READMEs now carry the recipe that actually built these, and correct the claim that --seed makes the bytes reproducible: mkfs.erofs stamps a random filesystem UUID, so the verity root hash and the partition UUIDs derived from it change on every rebuild. Part of kairos-io#5076 Signed-off-by: Ettore Di Giacinto <mudler@kairos.io>
|
Correction to my last note: I could regenerate them after all, so the fixture is now at |
|
Since my 04:20Z note @mudler the fixture move you asked for is in |
|
@ci-robbot as a follow up Auroraboot should warn if seeing files that are not in the hierarchy listed here when creating extensions |
|
Filed as #5223. It is wider than |
|
Picking this up for QA. |
QA Result: PASSHead
Summary: The UKI drop-in behaves the same as the GRUB one. Under the master config a signed extension makes Not caused by this PR, seen the same on both arms: |
|
Status, 2026-10-06 00:00Z: This PR is approved, |
Fixes #5076
Fixes #5132
Summary
/usr/localis whereCOS_PERSISTENTis mounted, and99_sysext.yamlnamed six paths under it inSYSTEMD_SYSEXT_HIERARCHIES. A successful sysext merge makes everyhierarchy it covers read-only:
merge_hierarchy()in systemd'ssrc/sysext/sysext.cmounts the overlay and then callsbind_remount_recursive(..., MS_RDONLY, MS_RDONLY, ...). So any machinethat merged one extension lost the writable half of its persistent
partition for the rest of the boot.
That is not only a test problem:
/usr/local/bin.tests/install_test.gohas one,and that is what reddened
test-core / installandtest-core-fips / installon master from run36892451653
onwards, the first master run carrying test(sysext): restore the GRUB live media coverage on a verity-only extension #5110.
00_home_dir_owner_fix.yamlwrites/usr/local/bin/fix-home-dir-ownershipin the
networkstage, and26_selinux.yamlwrites three scripts into/usr/local/binininitramfs. Both run aftersystemd-sysext.not an error.
Two commits:
/usr/localpath from the three hierarchy lists the filedeclares (the UKI drop-in, the GRUB drop-in and the
profile.dsnippet), leaving the image-owned ones:
/usr/bin:/usr/share:/usr/lib:/usr/include:/usr/src:/usr/sbin.hello.shpayload at/usr/bin/instead of/usr/local/bin/, so both specs keep runningthe command rather than falling back to reading the extension-release
file. The GRUB image stays verity-only, the UKI image stays verity +
signed with
tests/assets/keys/db.key, so each still matches theimage policy its boot path enforces.
hello-broke.sysext.rawisuntouched.
This is the direction @mudler asked for in
#5115 (comment), and
it answers the question #5076 was opened to decide.
Behaviour change worth calling out: anyone shipping an extension that
puts binaries in
/usr/local/binhas to ship them in/usr/binafterthis. That is the convention anyway, and
/usr/localbelongs to themachine.
How it was tested
kairos-init/pkg/bundled/sysext_hierarchies_test.goreads theshipped
99_sysext.yamlback throughbundled.EmbeddedConfigs, andfails if any hierarchy is
/usr/localor under it, if one of theimage-owned ones goes missing, or if the three lists stop agreeing.
Verified it catches a regression: putting
/usr/local/binback at thehead of one list fails two of the four specs.
go test ./kairos-init/pkg/bundled/...green,gofmt -lclean,CGO_ENABLED=0 go vet ./...clean in thekairos-testsmodule.immucore/pkg/state/verity_signature_internal_test.go, which readsboth fixtures and asserts on the verity signature partition: 13 specs
green. Their GPT entries decode to the expected
root-x86-64/root-x86-64-verity/root-x86-64-verity-sigtypes,and the two partition UUIDs concatenate to the
rootHashin the UKIimage's signature blob.
merge_hierarchy()in systemd v255 to confirm both halves: theread-only remount, and that a hierarchy is merged when the extension's
copy of it is non-empty.
I cannot boot a VM here, so CI is the reproduction. The checks that matter
are
test-core / install,test-core-fips / install,test-core / sysextand the UKI cells.
AI disclosure
Written by an AI agent. No human has read the code yet.