fix(verifier): check the image manifest with one strict sha256sum grammar, in-process - #1251
Merged
Merged
Conversation
This was referenced Sep 20, 2026
kvinwang
force-pushed
the
fix/verifier-measurement-fidelity
branch
from
September 23, 2026 04:56
fabe6d5 to
9589a1d
Compare
This was referenced Sep 23, 2026
Merged
kvinwang
force-pushed
the
fix/verifier-measurement-fidelity
branch
from
September 23, 2026 06:54
9589a1d to
2b9e074
Compare
kvinwang
force-pushed
the
fix/verifier-measurement-fidelity
branch
from
September 24, 2026 02:34
2b9e074 to
13589f5
Compare
kvinwang
added this pull request to stack #1342
September 24, 2026 02:37
sha256sum.txt is what os_image_hash commits to, and it was read by two different grammars. sha256sum_entry_hash split on whitespace and matched the second token, so `<hash> name junk` matched a name GNU sha256sum resolves as `name junk`, while `<hash> *name` -- valid binary-mode syntax naming `name` -- matched nothing and made the entry look missing. We generate the file ourselves with `sha256sum <files>` in os/image/assemble.sh, so accept only that output: newline-terminated `<lowercase sha256> <name>` lines, no blank lines, no duplicates, and names made of [A-Za-z0-9._-] starting with an alphanumeric. The parser lives in its own dstack_types::sha256sum module.
kvinwang
force-pushed
the
fix/verifier-measurement-fidelity
branch
from
September 24, 2026 02:54
13589f5 to
348ce13
Compare
…g sha256sum -c
The whole content binding for a downloaded OS image was `sha256sum -c
sha256sum.txt` plus its exit status. GNU coreutils skips an improperly
formatted line with a warning and still exits 0:
5891b5... a.txt
0000...0000 b.txt <- one space
$ sha256sum -c sha256sum.txt
a.txt: OK
sha256sum: WARNING: 1 line is improperly formatted
exit=0
validate_image_manifest_paths split on whitespace, so it accepted that line,
and prune_unlisted_image_files did too, so b.txt survived the prune. bzImage,
ovmf.fd and the initrd were then measured with no content check at all.
`<hash> *bzImage` went wrong the other way: coreutils checks `bzImage`, the
whitespace split sees `*bzImage`, and the file that was checked is the one
that gets pruned.
Parse the manifest once with dstack_types::sha256sum::parse and hash each
listed file here. One parser, one grammar, and a missing or mismatched file
is an error rather than a warning on someone else's stderr.
kvinwang
force-pushed
the
fix/verifier-measurement-fidelity
branch
from
September 24, 2026 03:03
348ce13 to
41467d5
Compare
This was referenced Sep 24, 2026
kvinwang
added a commit
that referenced
this pull request
Sep 25, 2026
The verifier now retries a transient image download failure (#1388), so a two-second download timeout expires before the download error is reported. Give the one-shot rows enough time to observe the retries, and assert that a refused connection is retried, a 404 is not, and a 503 recovers. Also assert the in-process manifest digest check on a tampered archive (#1251, #1337) and that the removed debug request field is ignored and the debug response fields are gone (#1332). Signed-off-by: Kevin Wang <wy721@qq.com>
kvinwang
added a commit
that referenced
this pull request
Sep 25, 2026
…bounds #1251 renamed the manifest confinement test the image-download case ran by name. Run its replacement plus the tests that pin the sha256sum grammar, the end-to-end image binding (#1337) and the truncated-download retry (#1388), and extend the measurement cache case with shape-only keying (#1334) and the bounded cache directory (#1369). Signed-off-by: Kevin Wang <wy721@qq.com>
kvinwang
added a commit
that referenced
this pull request
Sep 25, 2026
#1251 replaced image_paths_must_be_confined_and_manifest_paths_must_be_flat with every_manifest_entry_is_checked_before_the_image_is_accepted, so the evidence compatibility matrix no longer found its image-manifest row. Signed-off-by: Kevin Wang <wy721@qq.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The downloaded image's entire content binding is
sha256sum -c sha256sum.txtplus its exit status. Reproduced against coreutils 9.4:b.txtis never checked and the command succeeds.validate_image_manifest_pathsusessplit_whitespace(), so it accepts the single-space line, andprune_unlisted_image_filesalso usessplit_whitespace().nth(1), so it treatsb.txtas listed and keeps it. The file is then measured —bzImage,ovmf.fd,initrd— with no content check at all.More divergences between the two grammars, all reproduced:
<hash> *bzImagemakes GNU checkbzImage(binary-mode marker) while the whitespace split sees*bzImage, so the file that is checked is the one that gets pruned;<hash> name junkand\<hash> namediverge; CRLF and uppercase hex are accepted by GNU whilestr::lines()strips the\r.And a third grammar over the same file:
dstack_types::sha256sum_entry_hashmatched the second whitespace token and ignored the rest, so trailing tokens were dropped and near-duplicates evaded its duplicate-entry check.Unified into one grammar rather than just adding
--strict. We generate the file ourselves withsha256sum <files>(os/image/assemble.sh), so the newdstack_types::sha256summodule accepts only that output: newline-terminated<lowercase sha256> <name>lines, no blank lines, no duplicates, names from[A-Za-z0-9._-]starting with an alphanumeric.sha256sum::entry_hashgoes through the same parser. The verifier now hashes each listed file in-process instead of shelling out, which removes the subprocess and the parse differential.Verification
cargo test -p dstack-verifier -p dstack-types -p dstack-mr -p dstack-attest -p dstack-kms -p dstack-vmmgreen; clippy clean under the CI invocation. All 43 meta-dstack release manifests from v0.5.1 on parse; the older./namemanifests stay rejected, as they already are onnext.The other verifier fixes originally bundled here were split out into #1332, #1333, #1334 and #1335.