Block devices' integrity is important because it holds bootloader, system files, etc., and heavilty used in Android and Linux kernel.
Let's play with it.
upgautam@amd:~/Desktop$ dd if=/dev/zero of=~/Desktop/verity_test.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.00858481 s, 12.2 GB/s
upgautam@amd:~/Desktop$ ls
DummyApp filtering pack.txt 'QEMU modification' verity_test.img
Explanation:
of: output file
if: input file
/dev/zero is sepcial input file that has 0x00 (all zero bytes)
bs: block size
upgautam@amd:~/Desktop$ sudo losetup /dev/loop133 ~/Desktop/verity_test.img
You can find all used loopback devices using losetup -a command, and don't use those. For example, in my case loop133 is not being used.
upgautam@amd:~/Desktop$ sudo mkfs.ext4 /dev/loop133
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 25600 4k blocks and 25600 inodes
Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done
sudo mount /dev/loop133 ~/Desktop/mount_point_loop_dm_verity
Now, we repeat most of the steps above to create to store hash tree.
upgautam@amd:~/Desktop$ dd if=/dev/zero of=~/Desktop/verity_hash.img bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00141643 s, 7.4 GB/s
upgautam@amd:~/Desktop$ sudo losetup /dev/loop135 ~/Desktop/verity_hash.img
If not alreayd installed, install the required tools.
sudo apt install cryptsetup-bin
Kernel config,
upgautam@amd:~/Desktop$ grep DM_VERITY /boot/config-$(uname -r)
CONFIG_DM_VERITY=m
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING=y
# CONFIG_DM_VERITY_FEC is not set
sudo modprobe dm-verity
Now, we can format those devices and then create vroot using the same hash value that we got during format.
upgautam@amd:~/Desktop$ sudo veritysetup format /dev/loop133 /dev/loop135
VERITY header information for /dev/loop135
UUID: 7a5d78ac-caad-4ce7-b0a4-ca1b2c9b77d4
Hash type: 1
Data blocks: 25600
Data block size: 4096
Hash blocks: 203
Hash block size: 4096
Hash algorithm: sha256
Salt: bd25e6c7da025b83ae5e1cf9750228a7e3f01649e8454adedd9e32d9fac7cadd
Root hash: 3de39aa81b1c32508dd559ae7e3d1fab35d86f2daa03854ffcdf644ba3fd438a
Hash device size: 835584 [bytes]
upgautam@amd:~/Desktop$ sudo veritysetup create vroot /dev/loop133 /dev/loop135 3de39aa81b1c32508dd559ae7e3d1fab35d86f2daa03854ffcdf644ba3fd438a
upgautam@amd:~/Desktop$ sudo dmsetup status
vroot: 0 204800 verity V
The command sudo veritysetup create vroot /dev/loop133 /dev/loop135
creates vroot block device that tracks both loop133 (i.e., data), and loop135 (i..e, corresponding hashes of root and then block by block basis of data). Then we can mount vroot to /mnt using `sudo mount /dev/mapper/vroot /mnt'. Since dm-verity creates a read-only device, all writes to /dev/mapper/vroot will be rejected. The device is designed to ensure that only valid data (data that matches the hash tree) is accessible. Modifications or corruptions will automatically be flagged, preventing tampered data from being accessed. When the system accesses data from /dev/loop133 through /dev/mapper/vroot, the hashes in /dev/loop135 are checked to verify that the data has not been altered. The vroot is basically readonly mount of loop133. We can also mount loop135 to see the corresponding hash, and we can also mount loop133 and then write something. Then we consume from vroot mounted at /mnt that is the time when verity system checks its hashes.
When a block is accessed from /dev/mapper/vroot (which is the verity device created using veritysetup), the kernel performs a hash check on the corresponding block in the data device (e.g., /dev/loop133). This is all on-demand.
upgautam@amd:~/Desktop$ sudo umount /dev/loop133
upgautam@amd:~/Desktop$ sudo veritysetup close vroot
upgautam@amd:~/Desktop$ sudo fsck /dev/loop135
fsck from util-linux 2.39.3
upgautam@amd:~/Desktop$ sudo fsck /dev/loop133
fsck from util-linux 2.39.3
e2fsck 1.47.0 (5-Feb-2023)
/dev/loop133: clean, 16/25600 files, 2653/25600 blocks
upgautam@amd:~/Desktop$ sudo umount /dev/mapper/vroot
umount: /mnt: target is busy.
upgautam@amd:~/Desktop$ sudo veritysetup close vroot
Device vroot is still in use.
upgautam@amd:~/Desktop$ sudo lsof /dev/mapper/vroot
lsof: WARNING: can't stat() fuse.portal file system /run/user/1000/doc
Output information may be incomplete.
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nautilus 33410 upgautam 46r DIR 252,0 4096 2 /mnt
upgautam@amd:~/Desktop$ sudo lsof /mnt
lsof: WARNING: can't stat() fuse.portal file system /run/user/1000/doc
Output information may be incomplete.
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nautilus 33410 upgautam 46r DIR 252,0 4096 2 /mnt
upgautam@amd:~/Desktop$ sudo kill -9 33410
upgautam@amd:~/Desktop$ sudo veritysetup close vroot
Device vroot is still in use.
upgautam@amd:~/Desktop$ sudo umount /dev/mapper/vroot
upgautam@amd:~/Desktop$ sudo veritysetup close vroot
Any two .img files (e..g, boot.img, userdata.img etc.) can be verified for their data integrity via dm-verify. In Android system, it is implemented many vendors including Samsung. You will see dm-very options in Recovery mode.