Skip to content

Provisional SNP measurement profile

AMD SEV-SNP hardware reports a fingerprint (a measurement) of what a protected VM booted. This page explains how the owner can predict that fingerprint offline from the exact firmware, kernel and boot files, and records a review of the firmware source showing what that fingerprint does and does not cover. It is for engineers preparing hardware tests; no real hardware report has matched a prediction yet.

The offline predictor derives a candidate digest from owner-selected bytes. It does not approve firmware, authenticate a report or establish application identity. No matching genuine SNP report has been validated for this profile.

The restricted firmware candidate provides an exact-source patch and build procedure for the named-blob and fallback gates identified below. Source controls are not firmware or hardware acceptance.

For partner execution, begin with the read-only host preflight and validation packet.

Source review and coverage contract

This bounded source review uses edk2 edk2-stable202608, commit 2970e5699ba6267f3384ffab20f96647578aebc8, and QEMU v10.1.0, commit f8b2f64e2336a28bf0d50b6ef8a7d8c013e9bcf3. These are review references, not approved production releases or a vulnerability assessment.

Boundary Source behavior and required evidence
QEMU launch snp_launch_update_kernel_hashes copies the hash table into a NORMAL measured page when kernel-hashes=on; otherwise it uses a ZERO page. The launch must explicitly enable the property.
Hash table build_kernel_loader_hashes in that source emits SHA-256 entries for command line, initrd and kernel, including kernel setup bytes. All three entries are required. The command line includes its terminating NUL.
Firmware library selection AmdSevX64.dsc selects BlobVerifierLibSevHashes. A filename such as OVMF.fd or metadata GUID alone does not establish this selection.
Blob verification VerifyBlob dead-loops on fetch failure or a mismatched recognized hash. Missing table/wrong hash size returns access denied. An absent blob GUID returns success. Consequently, partial hash tables cannot establish this profile.
Boot alternatives The DSC has a GRUB prebuild and optional shell support. The platform boot manager contains additional boot-option handling after attempting the QEMU kernel. A production build still needs a reviewed configuration and executable failure tests proving alternate paths cannot run unapproved code.

The kernel-loader filesystem driver propagates errors from the verifier. Its named-blob path bypasses VerifyBlob for names other than kernel, initrd and cmdline. The production review must establish which consumers can execute or interpret those other blobs; the three-entry hash table does not cover them.

The predictor requires exactly one 4 KiB SNP kernel-hashes metadata section containing the whole 176-byte table. It independently constructs the complete table and compares bytes with the external predictor. This verifies a software encoding and metadata relationship; it does not execute QEMU or firmware.

Configuration supplied through opt/wcm/config is not one of these three measured blobs. Its effective digest is computed by the approved broker and bound into fresh provisioning evidence, as described in the deployment identity guide. This only has meaning once measured code identity is established.

Offline prediction

On a trusted owner build host, obtain VirTEE's tool at exactly 8f2b337e38bc83f87cd30f3253cdfe8e3e12cc3a. Preserve LF source bytes:

git -c core.autocrlf=false clone https://github.com/virtee/sev-snp-measure.git measurement-tool
git -C measurement-tool checkout 8f2b337e38bc83f87cd30f3253cdfe8e3e12cc3a
python -I -B python/boot/predict_measurement.py \
  --tool-source measurement-tool \
  --firmware owner-build/OVMF.fd --kernel owner-build/bzImage \
  --initrd owner-build/initrd.cpio --command-line owner-build/cmdline.txt \
  --vcpus 1 --vcpu-type EPYC-v4 --guest-features 0x1 > prediction.json

The vCPU/features above illustrate explicit inputs; select values matching the reviewed launch. Neither TCG's max CPU nor an implicit feature default is accepted. Run from a fresh Python 3.11+ process. The prediction path needs only the standard library; the tool is not installed in the broker or added as a runtime dependency. Exact upstream package source hashes are committed in python/boot/measurement-tool.json; changed or extra package files, including bytecode caches, fail before import.

Inputs are snapshotted into temporary files before hashing and prediction. The firmware must be page-aligned and 1..16 MiB; this rejects upstream's 4 KiB suffix fixtures but does not prove that a larger file is genuine firmware. Kernel and initrd must be nonempty. Command-line files contain printable ASCII with no trailing newline, NUL or encoding normalization. The predictor adds the one terminating NUL required by the hash-table format. No precalculated OVMF-hash override, report-derived expectation or guest-supplied digest is used.

Retain the JSON, exact input bytes, tool lock/source and interpreter/build environment. Check the recorded artifact hashes and launch parameters against the deployment approval. Feed expected_measurement_hex into the existing approval-generation procedure, pin the resulting approval independently, and perform the separate initramfs containment comparison. measurement_tool in the approval should identify the retained tool/environment bundle; the source lock alone does not identify a Python distribution or the whole build system.

The JSON always reports provisional: true, hardware_validated: false and firmware_enforcement_validated: false. It cannot close issue #144.

Software evidence and limits

test_measurement_prediction.py compares a published upstream launch-digest vector and independently encodes one SNP PAGE_INFO update and the complete QEMU hash table. Seven substitutions change the predicted digest: firmware, kernel, initrd, command line, vCPU count, CPU signature and guest features. Negative cases cover incomplete metadata, source changes, unsupported launch inputs, empty artifacts and suffix-only firmware.

The integration vectors use a synthetic zero-padded firmware suffix to exercise the CLI. They are not bootable firmware. The published vector comes from the same upstream predictor project, so it is a compatibility check, not an independent hardware oracle. The hash-table encoder and PAGE_INFO check are independent implementations; the complete VMSA/launch-digest calculation still relies on VirTEE. CI runs the pinned tool in a dedicated job.

The firmware-vm job also runs python/boot/prediction_controls.py against the actual production-candidate OVMF.fd, built kernel and broker initramfs from that workflow. It repeats the baseline prediction in fresh isolated processes and requires seven substitutions to change the digest: firmware, kernel, initramfs, command line, vCPU count, CPU signature and guest features. Each receipt retains artifact hashes, parameters and the resulting digest; a changed receipt with an unchanged digest fails. The built-launch-prediction artifact contains the baseline, controls and exact command line.

CI selects EPYC-v4, one vCPU and features 0x1 as a reproducible candidate profile. These parameters are not inferred from the cloud reports or approved for a deployment. Byte substitutions test predictor sensitivity and need not be bootable. Firmware enforcement and the independently authenticated hardware match remain separate acceptance requirements. This control shares the pinned predictor with the baseline and cannot detect a consistent predictor error.

Existing Azure paired-release and PCR 23 validation packs describe a different vTPM-backed deployment. They do not retain the exact OVMF/kernel/initrd/vCPU inputs for this profile and cannot validate its prediction. Genuine signatures on unrelated launch measurements are insufficient.

Matching hardware acceptance

Before an authorized native-SNP run, retain a reviewed, reproducible firmware build with resolved library selections, all boot payloads/options, compiler and linker inputs. Pin the QEMU binary/build, host and guest kernels, machine type, CPU signature, VMSA features and exact command line. Check that the actual QEMU launch enables kernel-hashes=on and uses the same full firmware.

Derive and approve the expected digest before collecting evidence. Supply AMD trust roots and policy independently. Use the existing owner provisioning client with the pinned approval to authenticate a fresh native report and its transport-key/configuration/policy binding; never compare a raw parsed measurement and call that report authentication.

Retain sanitized results for:

  • Baseline prediction equal to the authenticated report's 48-byte measurement.
  • Each launch-input substitution rejected against the original owner pin.
  • Kernel hashes disabled, missing/partial tables, substituted fw_cfg blobs and alternate boot attempts denied before provisioning.
  • Changed effective configuration rejected under the original policy.
  • The separate post-appraisal mutation, debug/admin/device/key-export and protected-restart tests in issue #144.

A predictor/report match alone does not test these enforcement paths. Keep the firmware, application-identity and installation claims provisional until the relevant acceptance evidence exists.

Managed-cloud hardware diagnostics

The restricted OVMF profile requires control of the firmware and direct boot inputs. A managed confidential VM's genuine attestation does not establish that it launched this candidate. Google documents its provider-managed firmware and signed launch endorsements. Azure's vTPM architecture uses a separate freshness path from native guest-controlled SNP REPORT_DATA.

python/tools/azure_attestation_controls.py tests the Azure adapter on an isolated disposable confidential VM. Supply an independently retrieved AMD root and two distinct owner-generated nonces. The tool changes application-owned PCR23; do not run it against a shared application relying on that PCR.

python python/tools/azure_attestation_controls.py \
  --root amd-root.pem --nonce "$OWNER_NONCE" --second-nonce "$SECOND_OWNER_NONCE" \
  --output /tmp/wcm-azure-diagnostic

The September 18, 2026 run on a DC2as_v5 guest passed one positive and six rejection controls: wrong nonce, transport key and workload digest, modified TPM signature and SNP body, and an untrusted root. It also reproduced a counterexample: after changing a nonsecret application probe file, asking the provider to quote the old caller-supplied digest still produces an accepted fresh quote. PCR23 authenticates that supplied value; this API does not establish file immutability or bind the running broker to a precomputed application image.

The tested guest exposed /dev/tpmrm0, but neither /dev/sev-guest, /dev/sev nor /dev/kvm. A native provisioning-report request failed without software fallback. This host therefore did not validate native-SNP provisioning or the custom OVMF launch. Preserve those unsupported results rather than relabeling the vTPM quote as native evidence. Raw bundles contain device identifiers and remain private; the committed summary contains hashes and bounded outcomes.

The same day's GCP N2D SEV-SNP diagnostic used a pinned Ubuntu 24.04 image, Secure Boot, no service account and SDK commit af5468e. The owner machine verified two fresh reports against owner-generated nonces, a supplied transport binding and an independently fetched, pinned AMD Milan root. Five substitutions were rejected: wrong nonce, wrong transport binding, modified signed measurement, modified signature and an untrusted root. A separate native SevSnpProvider.provisioning_report() request returned a valid signed report with the exact caller-selected 64-byte binding; a different binding did not match. This exercised the collector, not protected broker provisioning or key custody.

After the diagnostic changed a nonsecret application file, the second fresh report retained the first report's launch measurement. That measurement was observed, not independently predicted or approved. It did not identify the installed application. The guest exposed /dev/sev-guest and /dev/tpmrm0, but neither /dev/sev nor /dev/kvm; the restricted OVMF was not launched. The report carried policy 0x30000, VMPL 0 and PLATFORM_INFO 0x25. This run verified report bindings, not satisfaction of a production platform policy. Certificate revocation was not checked; the VCEK produced a cryptography deprecation warning for its nonpositive serial number. The temporary VM and boot disk were deleted and absence confirmed. The sanitized receipt is gcp-native-snp-2026-09-18/summary.json.