#What is dm-verity?
dm-verity is a Linux device-mapper target that provides transparent, read-only integrity verification for block devices.
It uses a Merkle hash tree to verify each block whenever it is read. The final value at the top of the tree—the root hash—acts as the trust anchor. If a data block or hash-tree block is modified, verification fails.
dm-verity detects unauthorized or accidental changes, but it does not encrypt data.
#Prerequisites
Enable the required kernel options:
1CONFIG_BLK_DEV_DM=y
2CONFIG_DM_VERITY=y
3
4# Optional: create the mapping through dm-mod.create=
5CONFIG_DM_INIT=y
6
7# Optional: verify a signed root hash
8CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
Userspace requires veritysetup, provided by Cryptsetup 2.x or newer.
The protected filesystem must be used read-only. Common choices include:
- SquashFS
- EROFS
- ext4 mounted read-only
#Step 1: Create a read-only root filesystem
Create a SquashFS image:
1mksquashfs rootfs/ rootfs.squashfs -noappend
Alternatively, create an EROFS image:
1mkfs.erofs rootfs.erofs rootfs/
Do not modify the image after generating its hash tree. Even a one-byte change invalidates the root hash.
#Step 2: Generate the hash tree
Create a separate hash-tree image:
1veritysetup format rootfs.squashfs rootfs.hashtree
The output includes information similar to:
1UUID: ...
2Data blocks: ...
3Hash blocks: ...
4Data block size: 4096
5Hash block size: 4096
6Hash algorithm: sha256
7Salt: f00d...
8Root hash: a1b2c3...
Save the root hash:
1veritysetup format rootfs.squashfs rootfs.hashtree | \
2 awk '/Root hash/ {print $3}' > roothash.txt
Keep the complete output or at least these parameters:
- Root hash
- Salt
- Hash algorithm
- Data-block size
- Hash-block size
- Number of data blocks
The root hash must be stored securely because it is the trust anchor.
#Optional single-partition layout
The hash tree can be appended to the filesystem image instead of using a separate partition. Calculate a block-aligned offset first:
1DATA_SIZE=$(stat -c %s rootfs.squashfs)
2HASH_OFFSET=$(((DATA_SIZE + 4095) / 4096 * 4096))
3DATA_BLOCKS=$((HASH_OFFSET / 4096))
4
5truncate -s "$HASH_OFFSET" rootfs.squashfs
6
7veritysetup format rootfs.squashfs rootfs.squashfs \
8 --hash-offset="$HASH_OFFSET" \
9 --data-blocks="$DATA_BLOCKS"
The partition must be large enough for both the filesystem and the generated hash tree.
#Step 3: Flash the images
One possible eMMC layout is:
| Partition | Content |
| ---------------- | ------------------------- |
| /dev/mmcblk0p1 | Boot files |
| /dev/mmcblk0p2 | Read-only root filesystem |
| /dev/mmcblk0p3 | dm-verity hash tree |
Write the images:
1dd if=rootfs.squashfs of=/dev/mmcblk0p2 bs=4M conv=fsync
2dd if=rootfs.hashtree of=/dev/mmcblk0p3 bs=4M conv=fsync
Warning: Verify the device names carefully. Writing to the wrong block device can destroy data.
#Step 4: Open the verified device manually
Create a verified mapping named vroot:
1veritysetup open \
2 /dev/mmcblk0p2 \
3 vroot \
4 /dev/mmcblk0p3 \
5 "$(cat roothash.txt)"
Mount the verified filesystem:
1mkdir -p /mnt/vroot
2mount -o ro /dev/mapper/vroot /mnt/vroot
Check its status:
1veritysetup status vroot
Close it after testing:
1umount /mnt/vroot
2veritysetup close vroot
#Step 5: Test corruption detection
Perform this test only on a disposable test image or test device.
With the verity mapping closed, modify one byte in the data partition:
1dd if=/dev/urandom \
2 of=/dev/mmcblk0p2 \
3 bs=1 count=1 seek=100000 \
4 conv=notrunc
Open the mapping again and read the complete device:
1veritysetup open \
2 /dev/mmcblk0p2 \
3 vroot \
4 /dev/mmcblk0p3 \
5 "$(cat roothash.txt)"
6
7dd if=/dev/mapper/vroot of=/dev/null bs=1M
When the corrupted block is read, the operation should fail. The kernel log should contain a message similar to:
1device-mapper: verity: data block N is corrupted
Check the log with:
1dmesg | grep -i verity
Redeploy the original filesystem and hash tree after this destructive test.
#Step 6: Configure dm-verity during boot
The verified device must be created before Linux mounts the real root filesystem.
#Option A: Initramfs
An initramfs can run veritysetup open before switch_root.
Example kernel command line:
1roothash=a1b2c3... verityroot=/dev/mmcblk0p2 verityhash=/dev/mmcblk0p3 root=/dev/mapper/vroot ro
The initramfs can create the mapping with:
1veritysetup open \
2 "$verityroot" \
3 vroot \
4 "$verityhash" \
5 "$roothash"
The kernel command line must be protected by the verified-boot chain. Otherwise, an attacker could replace both the filesystem and its root hash.
#Option B: dm-mod.create=
With CONFIG_DM_INIT=y, the kernel can create the mapping without an initramfs:
1dm-mod.create="vroot,,,ro,0 <data_sectors> verity 1 /dev/mmcblk0p2 /dev/mmcblk0p3 4096 4096 <data_blocks> 0 sha256 <roothash> <salt>" root=/dev/dm-0 ro
The parameters include:
- Device size in 512-byte sectors
- Data device
- Hash-tree device
- Data- and hash-block sizes
- Number of data blocks
- Hash-tree start block
- Hash algorithm
- Root hash
- Salt
#Option C: systemd
Systems using systemd can use systemd-veritysetup. Configuration can come from:
roothash=orusrhash=kernel parameters/etc/veritytab- Discoverable GPT partitions
- Embedded verity metadata
#Step 7: Establish the chain of trust
The root hash must itself be authenticated. Otherwise, an attacker can create a new hash tree and supply a new root hash for a modified filesystem.
A complete chain of trust can be:
- The immutable Boot ROM verifies the first-stage bootloader.
- The first-stage bootloader verifies the next boot stage.
- U-Boot verifies a signed FIT configuration.
- The FIT image contains or authenticates the kernel, device tree, initramfs, command line, and dm-verity root hash.
- Linux uses the trusted root hash to verify the root filesystem.
Suitable mechanisms include:
- Signed FIT images
- UEFI Secure Boot
- Signed kernel and initramfs images
- Xilinx authenticated or encrypted boot images
#Signed root hash
With the following kernel option enabled:
1CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
veritysetup can supply a PKCS#7 root-hash signature:
1veritysetup open \
2 /dev/mmcblk0p2 \
3 vroot \
4 /dev/mmcblk0p3 \
5 "$(cat roothash.txt)" \
6 --root-hash-signature=sig.p7s
The signing certificate must be trusted by the kernel keyring.
#Updates and A/B partitioning
Because dm-verity protects an immutable image, the filesystem cannot be updated in place. Every update requires:
- Building a new filesystem image.
- Generating a new hash tree.
- Obtaining a new root hash.
- Signing or authenticating that root hash.
- Deploying the complete image and tree.
An A/B layout works particularly well:
| Slot | Root filesystem | Hash tree |
| ---- | --------------- | ---------- |
| A | rootfs_a | verity_a |
| B | rootfs_b | verity_b |
The inactive slot can be updated while the active slot remains bootable. If the new system fails, the bootloader can roll back to the previous slot.
#Corruption policies
dm-verity can respond to corruption in different ways:
- Return an I/O error
- Ignore corrupted blocks
- Restart the system
- Panic the kernel
Available options include:
1ignore_corruption
2restart_on_corruption
3panic_on_corruption
For security-sensitive systems, silently ignoring corruption is normally inappropriate. Restarting or panicking can be combined with a bootloader rollback mechanism.
#Forward error correction
dm-verity optionally supports forward error correction:
1veritysetup format \
2 rootfs.squashfs \
3 rootfs.hashtree \
4 --fec-device=rootfs.fec
FEC can recover some corrupted data instead of only detecting it. It requires additional storage and does not replace protection of the root hash.
#dm-verity compared with related technologies
| Technology | Protection scope | Writable? | Main use | | ------------ | --------------------: | -----------------: | --------------------------------------- | | dm-verity | Complete block device | No | Immutable root filesystem | | fs-verity | Individual files | Not after enabling | Authenticating selected files | | dm-integrity | Block device | Yes | Integrity metadata for writable storage | | dm-crypt | Block device | Yes | Data confidentiality through encryption |
#Conclusion
dm-verity provides strong runtime integrity protection for read-only Linux filesystems. Every block is checked against a Merkle hash tree, allowing the kernel to detect malicious modification and accidental corruption.
However, dm-verity alone does not establish secure boot. Its root hash must be authenticated by a higher layer, such as a signed FIT image, UEFI Secure Boot, or a Xilinx secure-boot chain.
A robust embedded design combines:
- Secure or verified boot
- A trusted dm-verity root hash
- A read-only root filesystem
- An A/B update mechanism
- A defined corruption and rollback policy
Together, these components establish a continuous chain of trust from the first boot instruction to every filesystem block read by Linux.