Skip to content

Signed-mode admission is malleable: rollback + mix-and-match of independently-signed artifacts #2

Description

@HarryR

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)

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions