Summary
In ed25519 signed mode, admission pins a long-term release public key, not a specific artifact hash, so any artifact signed by that key is accepted (this is what enables "re-sign, reboot" roll-forward). An actor who controls the serving endpoint(s)/mirrors -- but does NOT hold the private key -- cannot forge a payload, but CAN mix and match knowledge of previously-signed artifacts. Filing to track; this is a design decision, not a code bug.
What an endpoint controller can do (no forgery)
- Rollback / downgrade. Serve an OLD but validly-signed payload (e.g. a previous stage2 / UKI with a since-patched vulnerability). The pinned key still verifies it, and there is no version or monotonic counter, so the downgrade is invisible to admission.
- Mix-and-match. The payload and its signed args (
args_url / args_sig_url) are signed INDEPENDENTLY with no binding between them. Serve the payload from release A with the signed args from release B -- both signatures verify, but the combination was never intended.
- Strip. Depending on config, drop optional signed inputs (the actor controls what each URL returns), reverting to inline / default behavior. (Note: outright omitting a required
args_url fetch fails closed; the concern is serving a stale-but-signed value.)
Scope
Applies to both stages: stage0 _stage1 (UKI + optional args) and stage1 _stage2 (payload + optional args). Threat actor = the endpoint/mirror controller, not a payload forger.
Not mitigated by PCR 14: measurement records what actually ran, so a relying party pinning an exact hash detects a rollback -- but the "trust the key, roll forward" model deliberately does not pin hashes, which is exactly where this bites.
Directions to consider (for later)
- Sign a single manifest binding {payload hash, args hash, version/counter} so the pieces cannot be recombined and the version is authenticated.
- A monotonic version / min-version in the signed data plus a persisted floor for anti-rollback (needs trusted storage, e.g. a TPM NV counter -- non-trivial).
- Bind args to the payload (sign args together with the payload hash).
Related: the set_load_options silent-drop of a malformed signed directive (stage0 review finding #3) is part of this same args-integrity question.
Summary
In ed25519 signed mode, admission pins a long-term release public key, not a specific artifact hash, so any artifact signed by that key is accepted (this is what enables "re-sign, reboot" roll-forward). An actor who controls the serving endpoint(s)/mirrors -- but does NOT hold the private key -- cannot forge a payload, but CAN mix and match knowledge of previously-signed artifacts. Filing to track; this is a design decision, not a code bug.
What an endpoint controller can do (no forgery)
args_url/args_sig_url) are signed INDEPENDENTLY with no binding between them. Serve the payload from release A with the signed args from release B -- both signatures verify, but the combination was never intended.args_urlfetch fails closed; the concern is serving a stale-but-signed value.)Scope
Applies to both stages: stage0
_stage1(UKI + optional args) and stage1_stage2(payload + optional args). Threat actor = the endpoint/mirror controller, not a payload forger.Not mitigated by PCR 14: measurement records what actually ran, so a relying party pinning an exact hash detects a rollback -- but the "trust the key, roll forward" model deliberately does not pin hashes, which is exactly where this bites.
Directions to consider (for later)
Related: the
set_load_optionssilent-drop of a malformed signed directive (stage0 review finding #3) is part of this same args-integrity question.