Protecting operating system partitions from unauthorized rootkits, persistent offline tampering, and malicious firmware implants requires cryptographically enforced block-level integrity. While standard filesystem permissions defend against unprivileged processes, they provide zero protection if an adversary boots an alternative live OS and modifies system binaries on disk. The Linux kernel’s Device Mapper Verity (dm-verity) target resolves this vulnerability by computing transparent, real-time cryptographic hashes across every storage block. Using a Merkle hash tree anchored to a single root hash, the kernel validates each sector as it is read into RAM. If even a single byte is altered, the I/O read fails instantly. In Ubuntu, system administrators and embedded security engineers configure dm-verity using veritysetup.
Understanding dm-verity and Merkle Hash Trees
The dm-verity architecture operates between the raw block device and the filesystem (such as ext4 or squashfs):
- Data Device: The primary block device containing the read-only operating system filesystem (e.g.
/dev/sdb1or a raw image file). - Hash Device: A dedicated block partition or auxiliary file that stores the multi-tiered Merkle tree containing SHA-256 hashes of every 4096-byte data block.
- Root Hash: A single 32-byte cryptographic digest that represents the cryptographic top of the Merkle tree. Providing this root hash to the kernel at boot binds the entire filesystem’s validity. If any data block is modified, its hash changes, propagating an invalid checksum up to the root hash.
- Kernel Enforcement: Integrated directly into the Linux kernel block layer. Reads that pass verification are served transparently at native hardware speeds; modified blocks trigger an I/O error (EIO) or panic the kernel based on restart policies.
Installing Cryptsetup and Verity Utilities on Ubuntu
The veritysetup binary is distributed as part of the standard cryptsetup-bin package in Ubuntu:
sudo apt update && sudo apt install -y cryptsetup-bin
Ensure the dm-verity kernel module is active in the system:
sudo modprobe dm-verity
lsmod | grep dm_verity
Formatting a Block Device with dm-verity
To establish block integrity, first prepare a clean read-only filesystem on your data device. For testing, create an ext4 filesystem on a dedicated partition (or loopback image):
# Create data and hash images for demonstration
dd if=/dev/zero of=rootfs.img bs=1M count=500
mkfs.ext4 -F rootfs.img
# Create dedicated hash image
dd if=/dev/zero of=hash.img bs=1M count=50
Format the hash device and generate the Merkle tree using veritysetup format:
veritysetup format rootfs.img hash.img
The command computes the Merkle tree and displays crucial cryptographic parameters:
VERITY header information for hash.img
UUID: 12345678-abcd-ef01-2345-6789abcdef01
Hash type: 1
Data blocks: 128000
Data block size: 4096
Hash block size: 4096
Hash algorithm: sha256
Salt: a1b2c3d4e5f6...
Root hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Crucial: Record the Root hash string. This value is required to mount and verify the volume.
Activating and Mounting the Verified Device
Map the verified block device to the device mapper using veritysetup open:
sudo veritysetup open rootfs.img verified_root hash.img e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Once opened, the mapped device becomes available under /dev/mapper/verified_root. Mount it as a read-only filesystem:
sudo mkdir -p /mnt/secure_root
sudo mount -o ro /dev/mapper/verified_root /mnt/secure_root
Verify the mount status:
df -h /mnt/secure_root
sudo veritysetup status verified_root
Simulating Tamper Detection and Block Corruption
To verify that dm-verity detects unauthorised modifications, deliberately corrupt a single byte on the raw underlying data image while mounted:
# Overwrite a byte inside the underlying raw data block
printf '\xff' | dd of=rootfs.img bs=1 seek=1048576 count=1 conv=notrunc
Attempt to read or compute a checksum across the mounted filesystem:
cat /mnt/secure_root/* > /dev/null
Check the kernel system logs:
sudo dmesg | grep -i verity
The kernel flags the corrupted block immediately:
device-mapper: verity: 7:0: metadata block 256 is corrupted
Buffer I/O error on dev dm-0, logical block 256, async page read
The read call is aborted with an Input/Output error, preventing compromised code from executing in memory.
Closing the Verified Device
When unmounting and closing the verified block mapper:
sudo umount /mnt/secure_root
sudo veritysetup close verified_root
Deploying dm-verity with veritysetup establishes an immutable, cryptographic root of trust for Ubuntu systems, securing appliances and critical servers against persistent offline disk tampering.