Skip to content

linux: make canister_build work against the current kernel - #29

Open
dcasota wants to merge 1 commit into
fix/kernel-shared-canister-configfrom
fix/canister-build-against-current-kernel
Open

dcasota wants to merge 1 commit into
fix/kernel-shared-canister-configfrom
fix/canister-build-against-current-kernel

Conversation

@dcasota

@dcasota dcasota commented Sep 1, 2026 •

Copy link
Copy Markdown
Owner

Problem

Two defects keep canister_build=1 from producing a usable canister for the 6.12 kernels (SPECS/92/linux 6.12.113, subrelease 92 and later; SPECS/91/linux 6.12.111, subrelease 91), and a third lets the FIPS certification modes run where they cannot work.

1. The canister patch series does not apply. In pkcs1pad_verify() upstream dropped the WARN_ON() around !digest_size; that line is context for canister-creation patches 1004 and 1010. At 6.12.111 upstream also inserted a gcc workaround (CFLAGS_ecc.o, under CONFIG_ARM, CONFIG_KASAN_STACK and GCC) between the curve25519 and ecdh_generic lines of crypto/Makefile, the context of the last hunk of patch 1000. At --fuzz=0:

1000-FIPS-canister-creation.patch: 1 out of 9 hunks FAILED -- saving rejects to file crypto/Makefile.rej
1004-Move-__bug_table-...patch:    1 out of 2 hunks FAILED -- saving rejects to file crypto/rsa-pkcs1pad.c.rej
1010-rsa-pkcs1pad-...patch:        1 out of 5 hunks FAILED -- saving rejects to file crypto/rsa-pkcs1pad.c.rej

6.12.113 also rewrote the overflow checks in drbg_healthcheck_sanity(): the two drbg_generate() results now go to ret and are checked with BUG_ON(ret == 0) instead of BUG_ON(0 < len), which is the context of the crypto/drbg.c hunk of 1004:

1004-Move-__bug_table-...patch:    1 out of 8 hunks FAILED -- saving rejects to file crypto/drbg.c.rej

so no canister_build=1 build gets through %prep.

2. A canister that does build is rejected at boot.

FIPS(fips_integrity_init): processing 8 sections, 687696 bytes
Kernel panic - not syncing: FIPS canister verification failed!

gen_canister_relocs gives each section an ondx, which fips_integrity_init() uses to index its si[] array when reversing a relocation. si[] is built from canister_sections[], which holds only sections carrying both begin and end markers. .bss carries only a begin marker (it is not measured; it is listed so relocations can resolve against it) but still consumes an ondx. Every section laid out after .bss is numbered one too high, its relocations are reversed against the wrong section, and the reconstructed image does not match the recorded HMAC. This stays invisible only while the compiler happens to emit .bss after every measured section.

3. acvp_build and kat_build use x86_64 inputs on other architectures. The build system injects both toggles for every architecture. On aarch64, the 6.12 linux.spec sets fips back to 1 after its architecture block and pulls in the prebuilt canister, which cannot work there: the canister is arch/x86 crypto and its tooling handles only R_X86_64_* relocations. In the 6.12 specs and SPECS/90/linux/linux.spec alike, acvp_build adds config_x86_64_acvp, the only ACVP config, to an arm64 build, which then fails late for a reason that names neither toggle.

Change

The same change is made in SPECS/92/linux and SPECS/91/linux; the generator and patches 1000 and 1010 are byte-identical in both trees, and 1004 differs only in the crypto/drbg.c hunk, which follows each tree's kernel:

  • Patches 1000, 1004, 1010 (canister_builder/patches) are refreshed to apply to the current source. In 1000 the lines added to crypto/Makefile (ecc.o, drbg.o, $(ecdh_generic-y)) are unchanged; only context and offsets move, and every other file in the patch is byte-identical. In 1004 the WARN_ON(req->dst) -> fcw_warn_on(req->dst) conversion is kept, because WARN_ON emits a __bug_table entry and keeping __bug_table out of the canister is the purpose of that patch; 1010's context follows. In SPECS/92/linux the crypto/drbg.c hunk of 1004 is refreshed for the 6.12.113 lines and converts the same two BUG_ON() calls to fcw_bug_on().
  • gen_canister_relocs.c: only a section with an end marker (a measured section) consumes an ondx; others get -1. .bss is NOBITS and holds no relocations, so the sentinel is never dereferenced; should a relocation ever target a section without a valid index (the sentinel, or one beyond the unsigned char the interpreter reads), the generator stops with the section name instead of emitting a wrapped index. The measured set, the generated linker script and the canister HMAC are unchanged; only the numbering handed to the interpreter changes.
  • linux.spec: the acvp_build -> fips 1 override is confined to x86_64, and acvp_build / kat_build on any other architecture stop the parse with %{error:acvp_build and kat_build are x86_64-only; refusing to build for %{_target_cpu}}. They are refused rather than undefined because Photon's SpecParser.py cannot undefine an injected macro and would still compute an .acvp Release that rpm does not build. canister_build stays allowed on aarch64, where it is ignored. This shares the %changelog entry linux, linux-esx: share the canister/.config logic via canister_config.inc #24 adds (6.12.114-2 in SPECS/92/linux, 6.12.111-4 in SPECS/91/linux).
  • SPECS/90/linux/linux.spec (6.1.190, subrelease 90): the same refusal block; its aarch64 block already sets fips to 0 after the acvp_build override, so only the refusal is needed. 6.1.190-2 -> 6.1.190-3, one %changelog entry. The canister patches and the generator concern only the 6.12 trees.

Testing

  • %prep with canister_build=1 at subrelease 92 (x86_64) applies every patch at --fuzz=0 to the checksum-verified linux-6.12.113.tar.xz, all 16 canister patches (1000-1013, 1015, 1016) included; without this change 1000, 1004 and 1010 fail with the rejects shown above. At subrelease 90 the prepared trees of linux.spec (x86_64 default and canister_build, aarch64 default) are identical file for file with and without this change.
  • gen_canister_relocs.c passes gcc -fsyntax-only -Wall without diagnostics.
  • rpmspec -P of both specs for SPECS/90/linux (90), SPECS/91/linux (91) and SPECS/92/linux (92, 93), head against base, with no toggle, canister_build, acvp_build and kat_build: on x86_64 only the canister_build and kat_build cells differ, and only in the canister patches 1000, 1004 and 1010 and in gen_canister_relocs.c; on aarch64 acvp_build and kat_build stop with the error above (the base parses them) and every other cell is identical. No new warnings.
  • With canister_build=1 this stack builds a canister locally (linux-fips-canister 6.12.113-3), and linux and linux-esx are built against it. A kickstart install of the minimal ISO with fips=1 reports fips_enabled=1, the canister loaded and stamped as built from 6.12.113-3, and 0 failed units; a full-ISO install with the same kernels and without fips=1 boots with 0 failed units as well. It is a test build, not a CMVP-validated canister.
  • check_spec.py --mainline 93 (with spec-checker: check a spec as the subrelease being checked sees it #34) exits 0 for linux.spec, linux-esx.spec and linux-rt.spec in SPECS/90/linux at 90, for linux.spec and linux-esx.spec in SPECS/91/linux at 91 and in SPECS/92/linux at 92 and 93.

Dependencies

Stacked on #24 (canister_config.inc and the shared changelog entry), which merges first.

🤖 Generated with Claude Code

@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch 6 times, most recently from 3a0b9a5 to 2590191 Compare September 7, 2026 12:13
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch 4 times, most recently from 747f97e to 4440647 Compare September 11, 2026 19:25
dcasota pushed a commit to dcasota/photonos-scripts that referenced this pull request Sep 11, 2026
Upstream moved the kernel from 6.12.107 to 6.12.109, which resets Release to 1,
so the variant patch now leaves linux at -3 and linux-esx at -2 and the embedded
patch takes them to -4 and -3.

Regenerated with tools/regen-canister-equivalent.py rather than retargeted by
hand - the first use of that script for the job it was written for, one command
instead of the archaeology this took the previous four times.

Neither 6.12.108 nor 6.12.109 touches crypto/rsa-pkcs1pad.c (checked against
kernel.org's incremental patches), so the premise of the canister patch rebase
in dcasota/photon#29 is unchanged: the WARN_ON wrapper around !digest_size is
still absent and patches 1004 and 1010 still need the rebase to apply at
--fuzz=0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch 3 times, most recently from 632de3c to 2994258 Compare September 13, 2026 05:18
@dcasota
dcasota changed the base branch from 5.0 to fix/kernel-shared-canister-config September 13, 2026 05:18
@dcasota
dcasota changed the base branch from fix/kernel-shared-canister-config to 5.0 September 13, 2026 05:24
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 2994258 to 8419a4e Compare September 14, 2026 09:28
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch 7 times, most recently from c7f6ae1 to a62c1bb Compare September 19, 2026 11:44
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch 3 times, most recently from aa8a578 to 66284df Compare September 30, 2026 11:49
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 66284df to 5729a16 Compare October 7, 2026 11:07
@dcasota
dcasota changed the base branch from 5.0 to fix/kernel-shared-canister-config October 7, 2026 23:00
@dcasota dcasota changed the title linux, linux-esx: make canister_build work against the current kernel linux: make canister_build work against the current kernel Oct 8, 2026
@dcasota
dcasota force-pushed the fix/kernel-shared-canister-config branch from fd9f576 to 77b921b Compare October 9, 2026 07:23
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 5729a16 to 2b139b8 Compare October 9, 2026 07:24
@dcasota
dcasota force-pushed the fix/kernel-shared-canister-config branch from 77b921b to 35499a7 Compare October 22, 2026 18:23
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 2b139b8 to 754f4d0 Compare October 22, 2026 18:23
@dcasota
dcasota force-pushed the fix/kernel-shared-canister-config branch from 35499a7 to f384945 Compare October 24, 2026 16:16
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 754f4d0 to 92796a0 Compare October 24, 2026 16:16
Two defects keep canister_build=1 from producing a usable canister, and a
third lets the FIPS build modes run where they cannot work.

1. The patch series no longer applies. Upstream dropped the WARN_ON()
wrapper around !digest_size in pkcs1pad_verify(), and that single line is
shared context for canister-creation patches 1004 and 1010, so %prep
fails at --fuzz=0 with

	1 out of 2 hunks FAILED -- crypto/rsa-pkcs1pad.c.rej

Rebase both onto the 6.12 series. In 1004 the WARN_ON -> fcw_warn_on
conversion is load-bearing rather than cosmetic: WARN_ON emits a
__bug_table entry, and keeping __bug_table out of the canister is what
that patch exists to do.

6.12.111 then inserted a gcc workaround (CFLAGS_ecc.o, under CONFIG_ARM,
CONFIG_KASAN_STACK and GCC) between the curve25519 and ecdh_generic lines
of crypto/Makefile, which is the context of the last hunk of 1000:

	1 out of 9 hunks FAILED -- saving rejects to file crypto/Makefile.rej

Rebase 1000 onto it as well. The lines it adds there are unchanged -
canister += ecc.o, drbg.o and $(ecdh_generic-y) - only context and
offsets move, and every other file in the patch is byte-identical.

6.12.113 rewrote the overflow checks in drbg_healthcheck_sanity(): the
two drbg_generate() results now go to ret and are checked with
BUG_ON(ret == 0) instead of BUG_ON(0 < len), so the crypto/drbg.c hunk
of 1004 fails:
	1 out of 8 hunks FAILED -- saving rejects to file crypto/drbg.c.rej
Rebase that hunk onto the new lines. It converts the same two BUG_ON()
calls to fcw_bug_on() as before.

2. A canister that does build is rejected at boot:

	FIPS(fips_integrity_init): processing 8 sections, 687696 bytes
	Kernel panic - not syncing: FIPS canister verification failed!

gen_canister_relocs gives each section an "ondx", the number
fips_integrity_init() uses to index its si[] array when reversing a
relocation. si[] is built from canister_sections[], which holds only the
sections carrying both markers. .bss carries a begin marker only - it is
not measured, it is listed so relocations can resolve against it - yet it
still consumed an ondx, so every section laid out after .bss was numbered
one too high and its relocations were reversed against the wrong section.
Let only a measured section consume an index. .bss is NOBITS and cannot
hold relocations, so the sentinel is never dereferenced; should a
relocation ever target a section without a valid index (the sentinel, or
one beyond the unsigned char the interpreter reads), the generator now
stops with the section name instead of emitting a wrapped index. The
measured set, the generated linker script and the canister HMAC are
unchanged.

3. acvp_build and kat_build build x86_64 inputs on other architectures.
The build system injects both toggles for every architecture. On aarch64,
SPECS/linux/linux.spec re-enabled fips after its architecture block and
pulled in canister machinery that cannot work there: the canister is
arch/x86 crypto and its tooling handles only R_X86_64_* relocations.
Independently, in SPECS/linux/linux.spec and SPECS/90/linux/linux.spec
alike, acvp_build selects config_x86_64_acvp, the only ACVP config, for an
arm64 kernel, and the build fails late for a reason that names neither
toggle.

Confine the fips override to x86_64, and refuse acvp_build and kat_build
on any other architecture with the same block in both specs, so the build
stops at once and says why. They are refused rather than undefined because
Photon's SpecParser.py cannot undefine an injected macro, and would still
compute a .acvp Release that rpm no longer builds. canister_build stays
allowed on aarch64, where it is already ignored.

SPECS/91/linux, which builds subrelease 91 from its own copy of the 6.12.111
specs, carries the same patch series, generator and fips override, and gets
the identical change, with 1004 as it applies to 6.12.111. With it, %prep
applies every patch at --fuzz=0 to 6.12.111 (subrelease 91) and 6.12.113
(92), for linux and linux-esx, by default and with canister_build and
kat_build.

Change-Id: Ib5878beeec1dd79e2bcdfefc33639d2b40d69d14
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dcasota
dcasota force-pushed the fix/kernel-shared-canister-config branch from f384945 to c2c2a0a Compare October 31, 2026 06:31
@dcasota
dcasota force-pushed the fix/canister-build-against-current-kernel branch from 92796a0 to 39fc4e0 Compare October 31, 2026 06:31
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