Repository navigation
fix(dm-verity): stop substituting a flat file digest for a Merkle root - #105
Merged
srpatcha merged 1 commit intoSep 1, 2026
Merged
Conversation
Kartikey1306
force-pushed
the
fix/dmverity-no-fake-root-hash
branch
from
September 1, 2026 06:04
0d13498 to
218b9c9
Compare
Contributor
Author
|
Now stacked on #104 (which is on #102). Merge order: #102 → #104 → this. The two red checks were
Rebasing onto the chain rather than leaving it red, since neither is something this change can fix from where it sits. Once #104 merges this collapses back to the single file it actually changes. |
This was referenced Sep 1, 2026
eos_dmverity_create() has a fallback: if veritysetup is missing or fails, it
runs `sha256sum <image>` and stores the result in dv->root_hash.
A dm-verity root hash is the root of a Merkle tree over the image's blocks --
that structure is what lets the kernel check each block as it is read, at read
time. A flat digest of the whole file is a different thing that happens to be
the same length and shape, so the substitution is invisible in every printout
and comparison. What it is not is usable: eos_dmverity_generate_table() emits
that value into a dm-verity table the kernel will reject, and anything treating
root_hash as an integrity token holds a hash with none of dm-verity's
properties.
A hash device that could not be built is a failure. Reporting one is more
useful than inventing a hash that cannot verify anything. Fallback removed.
Second, in the same function:
dv->verified = (dv->root_hash[0] != '\0');
return dv->verified ? 0 : -1;
`verified` means an image was checked against a known-good root hash. Creating
a hash device is not that check -- it establishes the root hash, it does not
verify anything against it. Setting the flag here made every successful
create() indistinguishable from a completed verification to any caller reading
the field, including eos_dmverity_dump(). eos_dmverity_verify() already sets it
correctly from `veritysetup verify`'s exit status, and is now the only place
that sets it. create() returns the same 0/-1 as before, so its own callers are
unaffected.
eos_dmverity_init() memsets the struct, so verified starts false and stays
false until something actually verifies.
Verified: eos_linux_security builds clean; full Release suite 25/28 with the
three Not-Run being services/compat's pthread_mutex_timedlock/sem_timedwait gap
on macOS (embeddedos-org#96's subject, unrelated). Linux CI builds all 28.
Not addressed here, deliberately: this file drives veritysetup, cryptsetup and
friends through system()/popen() with paths interpolated into shell strings --
ten call sites. That is a real injection surface and a separate piece of work;
folding it into a correctness fix would bury both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Kartikey1306
force-pushed
the
fix/dmverity-no-fake-root-hash
branch
from
September 1, 2026 09:41
218b9c9 to
cf4f849
Compare
srpatcha
approved these changes
Sep 1, 2026
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.
eos_dmverity_create()has a fallback. Ifveritysetupis missing or fails, it runssha256sum <image>and stores the result indv->root_hash:A dm-verity root hash is the root of a Merkle tree over the image's blocks. That structure is the whole point — it is what lets the kernel check each block as it is read, lazily, at read time. A flat digest of the whole file is a different thing that happens to be the same length and the same shape, so the substitution is invisible in every printout and every string comparison.
What it is not is usable:
eos_dmverity_generate_table()emits that value into a dm-verity table the kernel will rejectroot_hashas an integrity token holds a hash with none of dm-verity's properties — no per-block verification, no detection of tampering after mountA hash device that could not be built is a failure. Reporting one is more useful than inventing a hash that cannot verify anything.
Second, in the same function
verifiedmeans an image was checked against a known-good root hash. Creating a hash device is not that check — it establishes the root hash, it does not verify anything against it. Setting the flag here made every successfulcreate()indistinguishable from a completed verification to any caller reading the field,eos_dmverity_dump()included.eos_dmverity_verify()already sets it correctly, fromveritysetup verify's exit status, and is now the only place that does.create()returns the same0/-1as before, so its own callers are unaffected.eos_dmverity_init()memsets the struct, soverifiedstarts false and stays false until something actually verifies.Verification
eos_linux_securityThe three
Not Runareservices/compat/src/os_adapter_posix.cneedingpthread_mutex_timedlock()/sem_timedwait(), which macOS does not provide — #96's subject, unrelated to this change. Linux CI builds all 28.Deliberately not in this PR
This file drives
veritysetup,cryptsetupand friends throughsystem()/popen()with paths interpolated straight into shell strings — ten call sites. That is a real injection surface and its own piece of work; folding it into a correctness fix would bury both. Happy to take it as a follow-up.