Skip to content

vms-ff5: sign the OVMX kernel modules — clears TAINT_UNSIGNED_MODULE (E/bit 13) - #539

Merged
baron-3dl merged 2 commits into
mainfrom
work/vms-ff5
Aug 14, 2026
Merged

baron-3dl merged 2 commits into
mainfrom
work/vms-ff5

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

Signs the in-tree OVMX kernel modules (vms.ko/vmsfs.ko) so loading them no longer sets TAINT_UNSIGNED_MODULE (bit 13 / 'E'). Owns-kernel pole (vms-19e), rel-0.5. Builds directly on vms-934 (in-tree modules, PR #533).

What changed

  • distro/kernel/ovmx-x86_64.config: CONFIG_MODULE_SIG=y + CONFIG_MODULE_SIG_ALL=y + CONFIG_MODULE_SIG_SHA256=y, with CONFIG_MODULE_SIG_KEY="ovmx-module-signing-key.pem". CONFIG_MODULE_SIG_FORCE deliberately left off (deferred — sign-but-don't-force, no boot-brick risk).
  • distro/kernel/ovmx-module-signing-key.pem: committed self-signed module-signing key (priv+cert PEM). Its cert is embedded in the kernel's built-in trusted keyring so the kernel auto-verifies the signature at load.
  • distro/Dockerfile.bootable (kernel-build stage): copies the key into the tree before config/build; signs the harvested vms.ko/vmsfs.ko with it (guarded against double-signing); hard-gates CONFIG_MODULE_SIG=y + the pinned SIG_KEY + SIG_FORCE still off; the shipped-.ko re-check now also asserts a signature is present.
  • tests/qemu/test_signed_modules.sh + CI step + boot path filter: the real-boot taint proof.

Why a committed key, not the item's "ephemeral to start"

The ephemeral key the item suggested is incompatible with vms-d73's cut-release-reproducible gate, which runs on this PR (it touches Dockerfile.bootable) and byte-compares two --no-cache builds of vmlinuz + initramfs. An ephemeral key regenerates randomly per build → the keyring cert in vmlinuz and the module signatures in the initramfs differ → gate RED. A committed deterministic key keeps every signed byte identical. Since SIG_FORCE is off, the key gates nothing at load — it only lets the kernel verify the signature; a public checked-in key is the correct, necessary choice here. (This promotes the item's "persisted-key follow-up" into this PR.)

Proof (Rule 9 / real boot, no userspace fake)

test_signed_modules.sh mirrors test_intree_modules.sh:

  • STATIC: modinfo -F signer/sig_id/sig_hashalgo on the vms.ko/vmsfs.ko extracted from the actual boot initramfs.
  • BOOT-TIME: boots at loglevel=7, asserts the modules load (%OVMX-I-EXEC, %OVMX-I-MOUNTED) AND no module verification failed / signature and/or required key missing notice → bit 13 not set on the real boot.
  • vms-934's intree=Y / no-out-of-tree-taint assertions stay green.

The standalone src/kernel OOT build + tests/qemu OOT harness are untouched (no fork).

rd: vms-ff5 (parent vms-19e, blocks vms-566).

🤖 Generated with Claude Code

baron-3dl and others added 2 commits August 14, 2026 15:42
…(bit 13/'E')

Enable CONFIG_MODULE_SIG=y + CONFIG_MODULE_SIG_ALL=y in the bootable kernel
config, embed a committed OVMX signing cert in the built-in trusted keyring
(CONFIG_MODULE_SIG_KEY), and sign vms.ko/vmsfs.ko so finit_module() verifies
them at load and does NOT set TAINT_UNSIGNED_MODULE. Builds on vms-934's
in-tree modules (parent vms-19e "owns-kernel").

CONFIG_MODULE_SIG_FORCE is DELIBERATELY NOT set (vms-ff5 decision): signing is
proven first without enforcement so a pipeline slip can never brick the boot.
The Dockerfile hard-gates that SIG_FORCE stays off and that SIG/SIG_KEY are on.

Key provenance — committed, not ephemeral: the item's "build-ephemeral key is
fine to start" is INCOMPATIBLE with vms-d73's cut-release-reproducible gate,
which runs on this PR (it touches distro/Dockerfile.bootable) and byte-compares
two --no-cache builds of vmlinuz + initramfs. An ephemeral key regenerates
randomly per build, changing both the keyring cert in vmlinuz and the module
signatures in the initramfs. A committed deterministic key
(distro/kernel/ovmx-module-signing-key.pem) keeps every signed byte identical
build-to-build. Since SIG_FORCE is off, the key gates nothing at load — it only
lets the kernel verify the signature; a public checked-in key is correct here.

Proof (Rule 9, real boot): tests/qemu/test_signed_modules.sh mirrors
test_intree_modules.sh — static modinfo signature check on the shipped
vms.ko/vmsfs.ko, plus a loglevel=7 boot asserting no "module verification
failed / signature and/or required key missing" notice (i.e. bit 13 not set),
with the vms-934 intree=Y assertions kept green. Wired as its own CI step +
boot path filter. The standalone src/kernel OOT build + tests/qemu OOT harness
are untouched (no fork).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h misparse)

merge_config.sh extracts the symbol name from any fragment line beginning
'# CONFIG_...', so comment lines that started with '# CONFIG_MODULE_SIG...'
were misread as directives and printed a spurious 'redefined by fragment'
warning. The merged .config was already correct (the Dockerfile gate proved it),
but reword so no comment line begins with '# CONFIG_' -- prose refs go mid-line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@baron-3dl
baron-3dl merged commit 621ee80 into main Aug 14, 2026
81 checks passed
baron-3dl added a commit that referenced this pull request Aug 14, 2026
…s a build secret (#559)

GitHub secret-scanning flagged distro/kernel/ovmx-module-signing-key.pem: a
real PEM private key (+ self-signed cert) committed on origin/main via #539
(vms-ff5). It was committed deliberately, to keep module-signature bytes
reproducible (vms-d73) — but a committed private key is PUBLIC. Anyone with
read access can sign a module the OVMX kernel keyring trusts, which defeats the
entire purpose of the signing work (and is the exact "reports-verified but
anyone-can-forge" LARP class the authenticity invariants exist to kill).

Fix — the key is never committed; it is a build input, held fixed only when
determinism is needed:
  - Dockerfile.bootable: the key arrives as the `ovmx_module_signing_key`
    BuildKit secret; with no secret, an ephemeral key is minted in-stage
    (the kernel does NOT auto-generate at a custom CONFIG_MODULE_SIG_KEY path).
    Modules stay signed + verifiable either way; SIG_FORCE stays off.
  - cut-release.sh: passes OVMX_MODULE_SIGNING_KEY through as --secret when set.
  - ci.yml cut-release-reproducible: mints ONE job-scoped ephemeral key and
    feeds it to both cuts, so they stay byte-identical (vms-d73) with no key in
    git. This is what keeps the reproducibility gate green.
  - git rm the key; .gitignore it; correct the config/doc comments that called
    it "committed".

The leaked key must be treated as compromised: every future OVMX artifact is
signed by a different key, so the leaked one signs nothing we ship (revoked in
effect). Purging the dead blob from git history + force-push, and provisioning
a persistent secret for third-party-reproducible signed RELEASES, are operator
calls left to follow-up.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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