Skip to main content
  1. Index/

dm-verity

dm-verity is a Linux device mapper target, available since kernel 3.4, that provides transparent read-only integrity verification for block devices. When a block device is mapped through dm-verity, every data block read from the underlying device is verified against a pre-computed Merkle tree of cryptographic hashes before being returned to the caller — any modification to any block, whether from corruption, bit rot, or deliberate tampering, produces a hash mismatch that dm-verity detects and handles according to its configured error mode. The verification is transparent to the filesystem and applications mounted above it: they read from the dm-verity device as if it were a normal block device, with no awareness that every read is being hash-checked. The security guarantee is that the integrity of the entire block device is committed to by a single root hash — a 32-byte SHA-256 value that covers the entire Merkle tree and therefore the entire data volume. If the root hash is known to be correct (because it was measured into a TPM PCR, embedded in a UKI, or signed by a Secure Boot key), then any verified read from the dm-verity device is guaranteed to return exactly the data that was present when the Merkle tree was computed.

The Merkle tree structure makes verification efficient. The data blocks are divided into fixed-size chunks (4096 bytes by default, matching the typical filesystem block size); each chunk’s SHA-256 hash forms a leaf node. Leaf hashes are concatenated in groups and hashed again to form the next tree level, continuing until a single root hash remains. The hash tree itself is stored in a separate contiguous region on the same device (or on a separate device), and dm-verity caches recently verified hash blocks in memory, so the amortised cost of verification is dominated by a small number of tree-level hash reads per data block access rather than a full tree traversal. The veritysetup format command (from cryptsetup) computes the hash tree and returns the root hash; veritysetup create establishes the dm-verity device mapping with the root hash as a parameter that the kernel verifies at mount time against the stored tree. Once established, the dm-verity mapping is read-only and the root hash is fixed — any attempt to write through it is rejected. Error handling offers three modes: ignore (pass the corrupted data to the caller and log), restart (trigger a kernel panic and reboot, used in production Android and Chrome OS), and panic (immediate kernel panic). Production deployments universally use restart or panic because ignore defeats the security model.

dm-verity is the block-level integrity primitive that enables verified, immutable OS deployments at scale. In Android Verified Boot, the system and vendor partitions are dm-verity protected with root hashes stored in the boot partition and measured into the boot attestation chain — modifying a system file produces a hash mismatch that causes the device to refuse to boot into a verified state. In Chrome OS, all OS partitions are dm-verity protected, with the root hash embedded in the read-only firmware; updates replace the entire partition and recompute the tree. In bootc-based image Linux deployments, dm-verity complements composefs: dm-verity protects the block device layer where the OSTree object store lives, while composefs provides the file-level verified overlay on top. The key difference between dm-verity and fs-verity is their layer of operation: dm-verity operates below the filesystem, protecting arbitrary block devices, and cannot share data between images (two dm-verity volumes containing the same file use separate, non-shared blocks); fs-verity operates at the individual file level within a filesystem, enabling the per-file content addressing and sharing that composefs uses. dm-verity’s performance cost is minimal on sequential reads (hash tree levels are cached) but is more noticeable on random small-block I/O workloads where cache miss rates are higher — SSD-backed deployments typically see less than 5% overhead; spinning-disk deployments can see 10–20% on random workloads.

Related

fs-verity

fs-verity is a Linux kernel filesystem feature, merged in kernel 5.4, that provides read-only, content-addressable integrity verification at the individual file level. When fs-verity is enabled on a file (via the FS_IOC_ENABLE_VERITY ioctl), the kernel builds a Merkle tree of the file’s content blocks and stores it in a filesystem-specific location (in an ext4 or f2fs Merkle tree block range, or in a separate xattr-adjacent structure on btrfs). From that point, the file becomes immutable — writes are rejected — and every page read from the file is verified against the Merkle tree before being returned to userspace. The file’s fs-verity digest is the SHA-256 (or SHA-512) root hash of the Merkle tree, computable without reading the file at all once the tree is built: fsverity digest file returns this digest. A file’s fs-verity digest is a stable, content-derived identity: two files with the same content have the same digest, and any byte-level modification produces a different digest that verification will detect and reject with EIO. The kernel caches verified Merkle tree nodes in the page cache alongside file data, so the amortised verification overhead is low for sequentially-read files.

IMA (Integrity Measurement Architecture)

IMA (Integrity Measurement Architecture) is a Linux kernel subsystem, merged in kernel 2.6.30, that hooks into the kernel’s file access paths — execve(), mmap(), open() — and computes a cryptographic hash of each file’s contents before it is accessed, according to a configurable policy. It is the runtime half of the Linux integrity story: where TPM PCR measurements and Secure Boot cover what was loaded during the boot sequence, IMA covers what happens after the OS is running, hashing executables, libraries, kernel modules, firmware, and configuration files as they are opened, creating a continuously updated record of everything the system has actually used.

LUKS (Linux Unified Key Setup)

LUKS (Linux Unified Key Setup) is the standard specification for block device encryption on Linux, created by Clemens Fruhwirth in 2004. It sits above the kernel’s dm-crypt subsystem — which performs the actual AES sector-by-sector encryption via the device mapper — and adds a structured, on-disk header that decouples key management from the encryption itself. Any block device can be a LUKS container: a partition, a logical volume, a loop device; anything that sits beneath it (filesystem, swap, LVM) is encrypted transparently, with no changes required to the software using it. The managed cryptsetup tool and the libcryptsetup library provide userspace access to LUKS volumes, and are the canonical interface for all operations on them.