Skip to content

SNP: make SINGLE_SOCKET an owner-policy flag - #235

Merged
wallscaler merged 1 commit into
mainfrom
feature/snp-single-socket-owner-policy
Sep 8, 2026
Merged

wallscaler merged 1 commit into
mainfrom
feature/snp-single-socket-owner-policy

Conversation

@wallscaler

@wallscaler wallscaler commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Closes #234.

Why

A Linux KVM host cannot satisfy AMD guest policy bit 20 on a machine with more than one socket populated. AMD 56860 section 8.10 makes SNP_ACTIVATE return POLICY_FAILURE for such a guest, and KVM never issues SNP_ACTIVATE_EX (arch/x86/kvm/svm/sev.c:2274). A dual-socket operator therefore cannot present a single-socket guest at all, however honest they are.

SN39 UID 68 is that case today. The machine passes signed evidence, fleet, SAT, and full VCEK verification against the AMD chain, and is then refused at snp_single_socket_required (snp_production.py:362). Its axon is on chain and its incentive is zero, gated only on this.

What changes

cathedral_amd_sev_snp_policy_v1 gains an optional top-level boolean require_single_socket.

  • Absent means true. Every policy file written before this key existed keeps exactly its previous behaviour and, because the digest is taken over the file bytes, its previous digest. Verified by test.
  • load_snp_policy validates the key strictly: a non-boolean is refused, and unknown keys are still refused.
  • SnpProductionVerifier.verify consults it at the point that returns snp_single_socket_required today.
  • Machine rows gain guest_policy_hex and single_socket, so telemetry shows what was admitted rather than only what was refused.
  • The dev preview keeps its hard requirement. It writes nothing.

Nothing else about admission moves. VCEK signature and chain, MaskChipKey off, non-zero CHIP_ID, VMPL 0, debug off, migration agent off, generation, measurement allowlist, componentwise TCB floor, report-data binding and same-channel SAT are all unchanged.

Why this does not let one host farm many miners

Every SNP command on a Linux host executes on the master PSP, chosen by lowest PCI address and fixed at boot (drivers/crypto/ccp/sev-dev.c:846-849, sp-pci.c:181-216). So every guest on a host reports the same CHIP_ID, and duplicate_hardware_indexes (multicompute.py:165-186) zeroes every row whose hardware identity appears more than once.

That was the one open fact in #234, and it is now measured rather than assumed. On 2026-09-08 the operator started a second SNP guest on the same dual-socket host. Both guests return the identical chip pseudonym 5a8e82885be3a995, identical measurement, guest policy 0x30000 and reported TCB. Both bundles return chain_verified: true, VERIFIED, chip_id_match: true through the pinned verifier, so both reports are signed by the same physical chip's VCEK. Full result in #234.

Caveat kept in the record: n=1 host, and the socket placement of the two guests is unknown, so this establishes same-host CHIP_ID collision rather than the cross-socket routing claim specifically. The operational consequence is the same.

What we give up

The firmware-enforced guarantee that a guest's identity cannot change over its lifetime. On Linux the master-PSP routing gives the same property. On a hypervisor that routes each guest request to the PSP of the socket its vCPUs are on, it does not, and such a guest could present one identity per socket it spans. Nobody we know runs one.

Tests

The production gate had no unit test before this. Added:

  • a multi-socket guest is refused when the policy requires one socket, with snp_single_socket_required and no machine id
  • the same guest is admitted when the policy relaxes the bit
  • relaxing this bit does not widen debug or migration-agent
  • a single-socket guest is admitted under either policy
  • absent key keeps today's behaviour and digest
  • the key is strictly typed, changes the digest, and unknown keys are still refused

Both directions were mutation-checked: restoring the unconditional gate fails the relaxed test, and defaulting the flag to false fails the back-compat test.

tests/thin: 2488 passed, 20 failed. The same 20 fail on an untouched origin/main on this machine (six files, all systemd paths that do not run on macOS), where the count is 2482 passed. No regressions; the delta is the six new tests.

Not in this PR

https://claude.ai/code/session_011bg88Y8YjVJ6abHcuMWsaw


Note

Medium Risk
Changes SNP hardware-identity admission policy and weakens a firmware-enforced identity guarantee when owners opt out, though duplicate-hardware dedup still limits credit farming on Linux KVM.

Overview
Production AMD SEV-SNP admission no longer always rejects guests without guest-policy bit 20 (SINGLE_SOCKET). Owner policy cathedral_amd_sev_snp_policy_v1 now accepts optional require_single_socket (missing means true, preserving legacy policy files and digests). When set to false, multi-socket KVM guests can pass the same gate that previously returned snp_single_socket_required; debug and migration-agent checks are unchanged.

SnpProductionVerifier reads the flag at verify time, returns guest_policy on pass/fail at that gate, and fleet_score machine rows expose guest_policy_hex and single_socket for telemetry. Dev preview docs still hard-require the bit; production behavior is documented with the duplicate-hardware caveat.

Tests cover refuse/admit paths, back-compat, strict JSON typing, and that relaxing single-socket does not widen other guest-policy bits.

Reviewed by Cursor Bugbot for commit fd5059c. Bugbot is set up for automated code reviews on this repo. Configure here.

A Linux KVM host cannot satisfy AMD guest policy bit 20 on a machine with
more than one socket populated: 56860 section 8.10 fails SNP_ACTIVATE for
such a guest and KVM never issues SNP_ACTIVATE_EX. Dual-socket operators
were therefore refused at snp_single_socket_required no matter how honest
their machine was, while passing every other admission check.

cathedral_amd_sev_snp_policy_v1 gains an optional top-level boolean
require_single_socket. Absent means true, so every existing policy file
keeps its behaviour and its digest.

Relaxing the bit does not let one host earn more than one machine's
credit. Every SNP command on a Linux host runs on the master PSP, so all
guests on a host report the same CHIP_ID and duplicate_hardware_indexes
zeroes them. Measured on a live dual-socket host on 2026-09-08: two
guests, one CHIP_ID, both VCEK-verified against the AMD chain.

The production gate had no unit test. Adds one, plus the relaxed and
strict cases, a check that relaxing this bit does not widen debug or
migration-agent, and loader coverage for the new key. Machine rows now
carry guest_policy_hex and single_socket so telemetry shows what was
admitted.

Claude-Session: https://claude.ai/code/session_011bg88Y8YjVJ6abHcuMWsaw
@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_47ca588d-c005-44d8-a2ac-8f68a10bf950)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-08T08:45:12.626909Z fd5059c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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.

SNP: move the SINGLE_SOCKET requirement from code to owner policy (dual-socket Linux hosts)

1 participant