Linux dm-verity: Verify Read-Only Block Images from a Trusted Root Hash
Build read-only Linux block mappings with dm-verity, anchor the root hash in a trusted boot chain, and diagnose integrity failures without weakening checks.
dm-verity verifies a block device through a cryptographic hash tree and exposes it as a read-only Device Mapper mapping. It is designed for immutable images such as a system root, appliance image, or verified update artifact. It is not encryption, a writable-filesystem checksum option, or a signature by itself. The security boundary is the root hash supplied when the mapping is created and the trusted process that supplied it.
That distinction separates dm-verity from nearby Linux features. fs-verity verifies read-only file contents against a per-file Merkle tree; authenticating the publisher still requires trusting the file digest or a signature through another mechanism. dm-integrity stores per-sector tags and has different journal, write, and recovery behavior. A verified block image is useful when the complete image is published and replaced as a unit, rather than when applications need to update files independently.
Follow the hash path from a block to the trust anchor
The data device is divided into fixed-size blocks. A leaf hash represents each data block, and higher levels hash groups of child hashes until the tree reaches its root. The tree is stored on a hash device, which can be separate from the data device or share storage with it under carefully defined offsets. If both occupy one device, the hash area must sit outside the range exposed by the verity mapping.
When a block is read through the mapping, the kernel checks its digest and the required path through the tree. If that path cannot be verified up to the configured root hash, the read fails. This is an on-demand property: the image is not necessarily scanned in full when the mapping is opened. A successful mount or an initial status report therefore does not prove that every block has already been read and checked.
The kernel documentation identifies format version 1 as the current on-disk hash format for new devices. A verity table also depends on parameters including data and hash block sizes, the number of protected data blocks, the hash-tree start block, hash algorithm, salt, and root digest. Treat those values as part of the image format. Changing protected data causes affected reads to fail verification when checked, unless a less-strict corruption policy is configured. Parameter mismatches must also be treated as an invalid image configuration, but they do not all have the same symptom: num_data_blocks defines the protected range, and device blocks beyond that configured range are inaccessible. A smaller value can therefore expose a truncated mapping rather than cause a read-time verification failure. Validate the complete parameter set against the image manifest before activation.
The root hash must arrive through a trusted path
The root hash authenticates the hash tree above it. The kernel documentation is explicit that this digest must itself be trusted: there is no further authenticity layer beyond it. If an attacker can replace the data, the hash tree, and the root hash supplied to activation, the tree alone cannot identify the publisher’s intended image.
Release systems should therefore bind the exact root hash to a trust mechanism outside the replaceable image, such as signed release metadata verified by the boot or update process. The kernel can also verify a PKCS#7 signature for a root hash when root-hash signature support is enabled and the signing certificate is in the applicable trusted kernel keyring. Merely storing a signature beside an image does not make the kernel validate it; both the kernel configuration and activation path must use that feature.
There is another trust boundary in the metadata. The kernel verity target does not parse or verify the on-disk verity header; the kernel documentation expects a userspace tool to validate that header. A design that omits the header instead needs to provide the target parameters through a separately trusted chain, for example a verified boot command line. Do not assume that a valid data-block tree also proves that untrusted metadata selected the intended device, offsets, or algorithm.
Format an immutable artifact, then verify and activate it
The upstream veritysetup utility separates preparation from activation. format calculates and stores hash data based on the data device and can write the resulting root hash to a file. The release pipeline must preserve and authenticate that generated value independently. verify can check an image in userspace without creating a kernel mapping; open creates the active mapping; status reports that mapping; and close removes it. Keep generation and consumption as separate stages: formatting writes the hash area, while verification and activation must use the exact immutable data/hash artifact pair covered by the authenticated root hash.
The following is a lab outline, not a command to run against an identified production disk. The first block is for a disposable image-building stage. Set its paths only to test images, confirm their resolved paths and mount state, and ensure the hash target contains no needed data before formatting it:
DATA_DEVICE=/path/to/disposable-rootfs.img
HASH_DEVICE=/path/to/disposable-rootfs.verity
ROOT_HASH_FILE=/path/to/generated-root-hash.txt
# Build stage only: format writes the verity header and hash tree to HASH_DEVICE.
# Capture this generated root hash, authenticate it, and publish it with this exact pair.
sudo veritysetup format --root-hash-file "$ROOT_HASH_FILE" "$DATA_DEVICE" "$HASH_DEVICE"
After the data image, hash image, and root hash have been frozen as a release artifact, authenticate the root hash through the release trust path and compare it with the captured generated value. The next commands belong to a separate verification/activation stage. They must use that exact artifact pair; do not run format again on the published hash image before using its authenticated root hash:
DATA_DEVICE=/path/to/published-rootfs.img
HASH_DEVICE=/path/to/published-rootfs.verity
TRUSTED_ROOT_HASH='<hex root hash independently authenticated from the release manifest>'
# Verify the published pair against the authenticated hash before activation.
sudo veritysetup verify "$DATA_DEVICE" "$HASH_DEVICE" "$TRUSTED_ROOT_HASH"
# Activate a read-only mapping using that trusted value, then inspect and close it.
sudo veritysetup open "$DATA_DEVICE" vroot "$HASH_DEVICE" "$TRUSTED_ROOT_HASH"
sudo veritysetup status vroot
sudo veritysetup close vroot
The argument forms follow the current veritysetup manual. In an automated build, capture the generated digest as structured release output, sign or otherwise authenticate it, and make activation consume the authenticated value rather than blindly trusting output from the same mutable directory as the image. Keep both images fixed after formatting. If any protected byte changes, regenerate the hash tree and publish a new root hash as a new artifact.
For early root activation, the kernel documentation describes both an initramfs that creates the mapping before switching to the real root and early device creation through dm-mod.create=. The latter places table parameters on the kernel command line, so that command line must be within the trust chain. Boot integration also has to discover the data and hash devices before creating the mapping; systems with asynchronously probed devices may need explicit ordering or a wait policy. Test the actual firmware, bootloader, initramfs, kernel, and storage combination rather than treating a successful manual mapping as proof that early boot will work.
Choose a corruption response that fails safely
By default, a verification failure causes the affected I/O operation to fail. The target also offers policies such as logging and continuing, restarting, or panicking. ignore_corruption is particularly easy to misuse: it logs a corrupt block but allows reads to proceed, so it is not an acceptable generic way to keep a verified root online. Restart or panic policies need a recovery design that avoids reboot loops and preserves diagnostics.
check_at_most_once trades protection for performance by verifying a data block only on its first read from the data device. The kernel documentation warns that this detects offline tampering, not online modification after the first check. It is therefore a deliberate threat-model choice, not a default tuning flag for a device that may be modified behind the mapping.
Optional forward-error correction can recover some damaged blocks, but the corrected data is still checked against the expected hash before use. It can improve availability for specific image-storage failures; it does not remove the need for trustworthy hashes, backups, or a tested replacement path. Recovery also has performance and storage costs, so evaluate it against the failure modes of the actual medium.
Diagnose the image and mapping without disabling verification
When a protected read fails, record the kernel and Device Mapper messages, the active mapping name, the data and hash device identities, the root hash source, and the image release identifier. Use veritysetup status NAME to inspect an active mapping and veritysetup dump HASH_DEVICE to inspect verity parameters stored with the hash data. These commands help distinguish a parameter mismatch or wrong artifact from a failing device, but they do not establish that the root hash was trusted.
Test negative cases only with disposable copies: alter a data block, alter a hash-tree block, supply a wrong root hash, and exercise deliberately mismatched format parameters. For content or root-hash mismatches, confirm that reads of affected blocks fail under the production policy. For parameter mismatches, test whether activation rejects the combination or verify the mapping it actually creates; for example, a smaller num_data_blocks creates a truncated mapping, not necessarily a read-time verification failure. Confirm that monitoring records enough context to select the correct signed replacement. Do not “repair” an image by accepting a newly computed root hash from the suspect image; that would bless whatever bytes are currently present.
Finally, integrity is not freshness. A correctly authenticated older root hash can still identify an older valid image. If rollback to a vulnerable release is unacceptable, enforce version and rollback policy in the trusted boot or update system. dm-verity supplies read-only, on-demand block integrity; image confidentiality, publisher identity, anti-rollback, availability, and update atomicity remain separate design responsibilities.
Related:
- fs-verity on Linux: Per-File Integrity with Merkle Trees
- Linux dm-integrity: Journal, Bitmap, and Authenticated Storage Trade-offs
Sources: