Skip to content

linux, linux-esx: build every 5.0 subrelease from one spec - #1680

Open
dcasota wants to merge 3 commits into
vmware:5.0from
dcasota:fix/kernel-single-source
Open

dcasota wants to merge 3 commits into
vmware:5.0from
dcasota:fix/kernel-single-source

Conversation

@dcasota

@dcasota dcasota commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Photon 5.0 keeps three copies of each kernel spec: SPECS/90/linux/linux.spec and linux-esx.spec build kernel 6.1 for photon_subrelease 90 and below, SPECS/91/linux builds 6.12.111 for 91, and SPECS/92/linux builds 6.12.114 from 92. Every change that is not kernel-specific (dependencies, sections, the canister logic, the acvp/kat refusal) has to be made up to three times, and the copies drift.

Change

SPECS/92/linux/linux.spec and linux-esx.spec build every 5.0 subrelease, on x86_64 and aarch64. They replace SPECS/90/linux/linux.spec and linux-esx.spec and the SPECS/91/linux tree.

  • Version, Source0, the dependencies both kernels share, the acvp/kat refusal and every section are written once, with photon_subrelease conditionals where the kernels differ (Version is 6.1.190 at <= 90, 6.12.111 at 91 and 6.12.114 from 92).
  • Each kernel's preamble (Release, FIPS model, sources, patches) and changelog live in <flavour>-<kernel>.inc and <flavour>-<kernel>-changelog.inc (Source990-Source996); linux.spec also takes the subpackages whose descriptions differ from linux-<kernel>-packages.inc.
  • The 6.1 files move to SPECS/92/linux: included files to the top level, where SpecParser.py resolves includes, everything else under 6.1/. A file name that already exists for 6.12 with other content gets a -6.1 suffix (for example config_x86_64-6.1, fips_canister_wrapper-6.1.c), because Photon stages sources by file name; %prep copies such a source into the kernel tree under its original name. The 6.1 archives (linux-6.1.190.tar.xz, jitterentropy-3.4.1-4.tar.bz2, fips-canister-5.0.0-6.1.75-2.ph5-secure.tar.bz2) join SPECS/92/linux/config.yaml.
  • Subrelease 91 builds the 6.12 line at 6.12.111. SPECS/91/linux differs from SPECS/92/linux only in Version, Release, changelog, the CVE patches the later 6.12 kernels contain upstream and the patches refreshed for them; every other file is identical. Dropped: 52 CVE patches (five with 6.12.112 and 6.12.113, 47 more with 6.12.114). Refreshed: 17 patches (six for 6.12.112 and 6.12.113, canister patch 1004 for 6.12.113 in linux: make canister_build work against the current kernel #1675, and ten for 6.12.114: four CVE patches, aws 0011, 0015, 0185 and 0490, hcx 0008 and fips_canister_plugins 0001). Version and Release take a subrelease conditional, the 91 changelog moves to <flavour>-6.12.111-changelog.inc, kernel_cve_patches.inc keeps the dropped patches for 91 only (under 6.12.111/CVE/), and the 6.12.111 form of the refreshed patches moves under 6.12.111/ with a -6.12.111 suffix, its Patch line taking a subrelease conditional. Patches added to the 6.12 line after 6.12.111 apply from subrelease 92 on; those only 6.12.112 or 6.12.113 needed are gone. linux-6.12.111.tar.xz joins config.yaml.
  • Upstream's 92-only changes keep their scope: the aarch64 configs changed for 92 and the of-overlay patch dropped for 92 keep their 6.12.111 form for 91 (6.12.111/config_aarch64-6.12.111, config-esx_aarch64-6.12.111; Patch203 at 91 only); the CVE patches added after 6.12.111 that 6.12.114 still needs (16 between Patch3093 and Patch3121) and the linux-esx Intel TDX patches (Patch100-Patch106) apply from 92 on. The TDX %autopatch -m100 -M109 is limited to 92 and later, because at 90 the numbers 100 and 101 are the 6.1 kernel's apparmor and seccomp patches.
  • linux-rt stays in SPECS/90/linux with the files it uses.

Release and changelog of every kernel are unchanged (linux 6.1.190-3 / 6.12.111-4 / 6.12.114-2, linux-esx 6.1.190-2 / 6.12.111-4 / 6.12.114-2): what rpm builds is the same as with the separate specs.

Testing

  • rpm (rpmspec -P) reads linux.spec and linux-esx.spec at subreleases 90, 91, 92 and 93, on x86_64 and aarch64, with no toggle, canister_build, acvp_build and kat_build, as the separate specs of the base read: all 64 cells have the same packages and NEVRs (rpmspec -q), the same preamble and package headers, and the same %build, %install, scriptlets and file lists, and aarch64 acvp_build / kat_build of linux.spec are refused in both. Outside %prep, the only difference is at subrelease 90, where viomem-6.1.c is copied as viomem.c in %build. rpmspec -q gives linux 6.1.190-3 / 6.12.111-4 / 6.12.114-2 and linux-esx 6.1.190-2 / 6.12.111-4 / 6.12.114-2 at 90 / 91 / 92 and 93. Every Source and Patch a cell references, by number, is byte-identical to the one the separate spec references, apart from the -6.1 / -6.12.111 names above and the CVE include file itself, whose text merges the subreleases.
  • %prep applies, by number, byte-identical patches to those of the separate specs. At subrelease 90 it was compared file for file against the separate specs' trees on 6.1.190 (linux x86_64 default and canister_build, linux aarch64, linux-esx x86_64 and aarch64, every patch at --fuzz=0) before this base; on this base 90 differs from that only by the eight 6.1 CVE patches 5.0 added, which are the same files.
  • check_spec.py --mainline 92 with spec-checker: check a spec as the subrelease being checked sees it #1678 exits 0 for SPECS/92/linux/linux.spec and linux-esx.spec at subreleases 90, 91 and 92. Without spec-checker: check a spec as the subrelease being checked sees it #1678 it stops on the single specs with a TypeError in create_altered_spec while opening an included file.
  • linux and linux-esx 6.12.114-2 build from this stack, as does the equivalent-canister kernel 6.12.114-3, and ISOs built with them, together with the other fixes under test in the same permutation run, pass 28 of 28 autonomous kickstart install rows of a permutation matrix with 0 failed checks. The subrelease-91 kernels (6.12.111-4) and aarch64 are checked statically on this base.

Dependencies

🤖 Generated with Claude Code

dcasota added a commit to dcasota/photonos-scripts that referenced this pull request Sep 15, 2026
Upstream ee3c2b78b (92/linux CVE fixes) took linux and linux-esx to
6.12.109-2, the release the canister PR stack had used. The stack was
rebased: linux and linux-esx to -3, the canister_build fix to -4, and
the single-source specs regenerated on top.

Until the permutation rows pass, the variants cherry-pick the rebased
stack from the fork-only branch test/kernel-single-source-rebase-20260915
instead of fix/kernel-single-source, which still backs vmware/photon#1680.
The embedded canister-equivalent patch is regenerated against it and now
takes linux to 6.12.109-5 and linux-esx to -4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JW73JTCUGRcaNTUEQcAMtf
@dcasota
dcasota force-pushed the fix/kernel-single-source branch 5 times, most recently from c8ccbbb to a5448d8 Compare September 19, 2026 11:44
@dcasota
dcasota force-pushed the fix/kernel-single-source branch from a5448d8 to 7569770 Compare September 27, 2026 07:30
dcasota added a commit to dcasota/photonos-scripts that referenced this pull request Sep 29, 2026
branch-check compared each changed spec file with the same path on the
target. fix/kernel-single-source keeps the kernel changelogs in includes
(linux-6.12-changelog.inc) that 5.0 does not have, so its 6.12.111-2 passed
against vmware/5.0 although 5.0 had just published 6.12.111-2 in
SPECS/linux/linux.spec (vmware/photon#1680). When a path is absent on a side,
the check now reads every .spec and *changelog*.inc %changelog of the same
package directory name there (SPECS/<pkg>/ and SPECS/<subrelease>/<pkg>/).
Verified: old #1680 head fails as it should, the rebased branches and every
other open PR pass against dcasota and vmware 5.0. Test covers a changelog
moved into an include.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JW73JTCUGRcaNTUEQcAMtf
@dcasota
dcasota force-pushed the fix/kernel-single-source branch 2 times, most recently from d2a02c3 to 0427868 Compare September 30, 2026 11:49
@dcasota
dcasota force-pushed the fix/kernel-single-source branch 2 times, most recently from 3e91f03 to 1d6e318 Compare October 9, 2026 07:24
@dcasota
dcasota force-pushed the fix/kernel-single-source branch 2 times, most recently from d00b9df to 06861d0 Compare October 24, 2026 16:16
dcasota and others added 3 commits October 30, 2026 13:23
…g.inc

linux.spec and linux-esx.spec implemented the same canister Kconfig handling
in two different idioms, and they disagreed on one constellation.

linux-esx.spec used %if 0%{?fips} / %else, and its %else branch cleaned the
GCC_PLUGIN_{MATCH,PAD}_CANISTER_STRUCTS comments out of .config. linux.spec
instead used two independent %if canister_build / %if canister_usage blocks
with no %else, so when fips=0 nothing ran: the shipped .config kept the
"is not set" comments, make olddefconfig dropped them, and the
check_for_config_applicability.inc diff guard failed %prep. That is an
x86_64 kernel built without the canister: fips is set by %global inside
%ifarch, so it is 1 on x86_64 unless that line is edited to 0, and
config_x86_64 carries both "is not set" comments. The aarch64 configs
never carried them.

Move the three conditional blocks into SPECS/linux/canister_config.inc,
pulled in by both specs as Source5 + %include, the same mechanism both
already use for check_for_config_applicability.inc. Divergence between the
two flavours is now impossible by construction.

SPECS/91/linux, which builds subrelease 91 from its own copy of the 6.12.111
specs, carries the same defect and gets the same change.

linux-esx.spec additionally gains the derived-flag block linux.spec already
had (canister_build=0, canister_usage=fips), nested inside the existing
%if fips so it does not shadow -D. esx never builds a canister - it untars a
prebuilt one - so fips=1 implies canister_usage=1, reproducing the old
branch exactly.

Tested across 168 cells: SPECS/91/linux at subrelease 91 and SPECS/linux at
92 and 93 x 2 specs x {x86_64, aarch64} x 14 flag combinations of fips /
canister_build / canister_usage / acvp_build / kat_build. All x86_64 cells are byte-identical apart from the release string.
The aarch64 fips=0 cells gain the two deletions, which are no-ops there: no
aarch64 config carries the "is not set" comments. The esx aarch64
reordering is likewise a no-op: the canister and jitterentropy seds touch
disjoint symbols.

Change-Id: If4107c14d8f15752dff0c0f25c6b4dee504e3041
Signed-off-by: Daniel Casota <dcasota@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
SPECS/92/linux/linux.spec and linux-esx.spec now build kernel 6.1 for
photon_subrelease 90 and below, kernel 6.12.111 for 91 and kernel 6.12
from 92, on x86_64 and aarch64, replacing SPECS/90/linux/linux.spec and
linux-esx.spec and the SPECS/91/linux tree.

Each kernel's preamble (Release, FIPS model, sources, patches) and
changelog live in <flavour>-<kernel>.inc and <flavour>-<kernel>-changelog.inc;
linux.spec also takes the subpackages whose descriptions differ from
linux-<kernel>-packages.inc. Version, Source0, the dependencies both
kernels share, the acvp/kat refusal and every section are written once,
with photon_subrelease conditionals where the kernels differ.

The 6.1 files move to SPECS/92/linux: included files to the top level,
where SpecParser resolves includes, everything else under 6.1/. A name
that exists for 6.12 with other content gets a -6.1 suffix, because
Photon stages sources by file name; %prep copies such a source into the
kernel tree under its original name. The 6.1 archives join config.yaml.
linux-rt stays in SPECS/90/linux with the files it uses.

Subrelease 91 builds the 6.12 line at 6.12.111. SPECS/91/linux differed
from SPECS/92/linux only in Version, Release, changelog, five CVE patches
6.12.112 and 6.12.113 dropped and seven patches refreshed for them.
Version and Release take a subrelease conditional, the 91 changelog moves to
<flavour>-6.12.111-changelog.inc, kernel_cve_patches.inc keeps the
dropped patches for 91, and the 6.12.111 form of the refreshed patches
moves under 6.12.111/ with a -6.12.111 suffix. The 6.12.111 archive
joins config.yaml. Patches added to the 6.12 line after 6.12.111 apply
from subrelease 92 on; the aarch64 configs changed for 92 and the
of-overlay patch dropped for 92 keep their 6.12.111 form for 91.

rpm and Photon's SpecParser read both specs exactly as before for
subreleases 90, 91, 92 and 93, on x86_64 and aarch64, with and without
canister_build, acvp_build and kat_build, and every file %prep copies
lands under the same name. %prep applies every patch at --fuzz=0 to
6.1.190, 6.12.111 and 6.12.113. check_spec needs
fix/check-spec-subrelease-aware on the common branch to read a spec that
serves several subreleases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dcasota
dcasota force-pushed the fix/kernel-single-source branch from 06861d0 to a43292b Compare October 31, 2026 06:31

This branch has not been deployed

No deployments
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