DM-verity

Why DM-Verity?
Possibly you want to continue the RoT (Root of Trust [1]) - from the hardware (Hardware TPM as Root of Trust, which ensures only the hardware with the correct secret cryptographic key in the TPM to decrypt the disk/file encryption) -> secure boot (Secure Boot to only run approved signed EFIStub/signed Bootloader) -> To NOW DM-Verity rootfs (which ensures your root-image/root-parition has not been tampered with) -> Mandatory Access Control (AppArmor or SELinux - SELinux is disabled on default linux-lts btw) -> Sandboxed/Virtual-Machined Applications.
What's the difference between me just setting the root partition as read-only (basically just an Immutable Root Partition) vs this?
DM-Verity COMPLETELY disallows modifying any files in the root-partition/root-image, or even disallow a part of a root-image/root-partition (the root-image/root-partition needs to be INTACT and match the signed cryptography verified by DM-Verity on a different partition), and with this consideration, you may use ERO-FS or SquashFS to generate Read-Only Root-Paritition/File Images. If you set your EXT4 file system to writable, and DM-Verity were to use it, it would be seen as "corrupted" and not boot anymore, because even just ONE tiny data change to the root image/partition would render it "corrupted". This is the same technology used in Android and Chrome OS Devices. Also related to use in A/B root, also used by Fedora.
- This following guide will use dracut to make a signed secureboot-able EFIStub.
- If you haven't, you may follow the Alpine Linux disk encryption setup [2] with DM-Crypt LUKS and LVM
- You may choose to decrypt the image with TPM when generating with Dracut Modules with
add_dracutdrivers+=" ... tpm2-tss ... "
and Clevis [3] - Apply AppArmor using Alpine Linux AppArmor Wiki (Docker does use AppArmor already, but you may apply an AppArmor profile on any application that should not have access to specific directories (AppArmor is a PATH based MAC)) [4]
- Use GVisor [5] with Docker (Docker is NOT a sandbox [6] (Because docker uses native kernel compared to Gvisor using its own kernel reimplementation)) for sandboxing on servers
What is ERO-FS?
Google thought about implementing ERO-FS with DM-Verity [7]. Google was reported to be using it in Android 13, and ERO-FS is an excellent and fast compressed read-only filesystem.
Here is an excerpt about mkfs.erofs
on [Arch Linux Wiki] [8]:
mkfs.erofs(1) offers an attractive alternative to ext4 or squashfs on the root partition. EROFS, like squashfs, does not allow writes by design and has better performance in many cases than comparable filesystems on flash and solid-state media. It uses lz4 compression by default and was designed for Android phones by Huawei, which make extensive use of dm-verity.
Installing
Working with ERO-FS

/etc/apk/repositories
as well)
First, some considerations, you may use a strictly READ-ONLY file system, such as SquashFS or ERO-FS, this wiki will be using ERO-FS (if you use a custom kernel, make sure it supports a file system such as ERO-FS, the default linux-lts does). [ERO-FS Github] [9] contains some information about how to compress and make your own read-only root image.
$ apk install erofs-utils
$ mkdir image && cd image
$ wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.0-x86_64.tar.gz
$ tar -xvf alpine-minirootfs-3.21.0-x86_64.tar.gz && rm alpine-minirootfs-3.21.0-x86_64.tar.gz
Command below will generate an ERO-FS Image compressed with lz4 as ./erofs.img (erofs.img would be the root-partition file to use for dracut)
$ cd .. && mkfs.erofs -zlz4hc erofs.img ./image
Choose between a file or a partition

You can verify the integrity of your erofs/squashfs image, by comparing the hashtable. The hashtable can be a file or a partition.
- The partition should be at least 10 percent the size of the final root-image squashfs/erofs.
- When making a hashtable, running veritysetup should also provide a root hash. Keep this roothash for later use when unlocking the device via a kernel parameter/in the initramfs.
Working with mkinitfs/kernel-hooks/secureboot-hooks

Using mkinitfs, it is possible to force veritysetup in initramfs generation. It is recommended to make a chroot or docker so you don't mess with your system files, and by adding these files:

apk add cryptsetup
Edit /sbin/mkinitfs (put "# Copy custom init" before "# copy modloop signature"):
Contents of /etc/mkinitfs
PUT "# Call custom script" before "if [ "$SINGLEMODE" = "yes" ]; then"
Contents of /initramfs/init
Contents of /etc/mkinitfs/features.d/my-custom-script.files
Contents of /etc/mkinitfs/features.d/veritysetup.files
Contents of /etc/mkinitfs/features.d/veritysetup.modules
Contents of /etc/mkinitfs/features.d/erofs.modules
Contents of /etc/mkinitfs/mkinitfs.conf
Contents of /etc/scripts/my-custom-script.sh
Then just do:
apk add secureboot-hook gummiboot gummiboot-efistub efibootmgr kernel-hooks secureboot-hook
mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b / $(uname -r)
Decompress:
mkdir /tmp/initramfs cd /tmp/initramfs zcat /boot/initramfs-$KERNEL | cpio -idmv
Test if "init" works by just executing it and see how it runs:
./init
Working with Dracut
Remember, mount your $ROOT_PARTITION
as read only (assuming you use EXT4, if using ERO-FS or SquashFS, ignore this), since any changes will cause DM-Verity to detect it as "corrupt"

Install basic stuff:
apk add dracut dracut-core cryptsetup gummiboot gummiboot-efistub tpm2-tools clevis tpm2-tss tpm2-tss-tcti-device
Using Clevis for TPM
clevis luks bind -d /$ENCRYPTED_ROOT_PARTITION tpm2 '{"pcr_ids":"1,7"}'
Input LUKS passphrase, remember that yes now it has tpm, but if possible remove old luks passphrase and use keyfile or different passphrase to unlock because tpm is better, and so if your computer breaks, you won't be locked out of your data!
Create a new partition for your DM-Verity:
Replace /dev/sdX with your actual device name.
sudo fdisk /dev/sdX
Once in the fdisk interface:
- Press n to create a new partition
- Choose p for primary partition
- Select the partition number (e.g., 4)
- For the first sector, press Enter to use the default
- For the last sector, calculate 10% of your root partition size and use +SIZE format. For example, if your root partition is 100GB, enter +10G
- Press t to change the partition type
- Enter the partition number you just created
- Type 8e for Linux LVM type (closest to verity)
- Press w to write changes and exit
Adding custom lines for full disk decryption
Edit "/usr/lib/dracut/modules.d/90crypt/cryptroot-ask.sh
" and add these lines right BEFORE "exit 0
" (add your $ROOT_PARTITION
directory and $VERITY_PARTITION
directory):
Contents of /usr/lib/dracut/modules.d/90crypt/cryptroot-ask.sh
Generating an EFIStub with Dracut + DM-Verity
To setup DM-Verity (borrowed from Arch Linux Wiki):
veritysetup format /dev/$ROOT_PARTITION /dev/$VERITY_PARTITION
/etc/dracut.conf (put whatever your boot parameters are in "kernel_cmdline
"):
Contents of /etc/dracut.conf
Finally, generate UKI using dracut (replace 6.X.X-X-lts
with your kernel $VERSION
) (also replace /boot/efi/EFI/Linux/alpine-linux.efi
with your mount efi partition):
export DRACUT_KMODDIR_OVERRIDE=1
dracut --include /usr/lib/dracut/roothash.txt /usr/lib/dracut/roothash.txt --host-only --kernel-image /boot/vmlinuz-lts --kmoddir /lib/modules/6.X.X-X-lts --kver 6.X.X-X-lts --uefi --uefi-stub /usr/lib/gummiboot/linuxx64.efi.stub --force --compress lz4 /boot/efi/EFI/Linux/alpine-linux.efi /boot/efi/EFI/Linux/alpine-linux.efi
efibootmgr --create --disk /dev/$EFI_PARTITION --part 1 --label alpine-linux --loader EFI/Linux/alpine-linux.efi
Unfortunately, using the default Alpine Linux kernel (linux-lts
) didn't work so download another distributions root system (like debians or devuan), and replace /lib/modules/6.X.X-X-lts
, and /boot/vmlinuz-lts
with anothers distributions kernel modules and kernel image (Or consider compiling your own linux-hardened kernel [11]).
$ROOT_PARTITION
's files and it should say it is "corrupt", and not continue the boot process (only if you use EXT4).External Links
Root of Trust/Chain of Trust
Full disk encryption with LVM and LUKS (AlpineWiki):
- LVM_on_LUKS [2]
Clevis Github
AppArmor Wiki (AlpineWiki)
- AppArmor [4]
GVisor
Gvisor Github stating docker is not a sandbox
Android-13 Possibility of using ERO-FS:
DM-Verity (Arch Wiki):
ERO-FS Github
Dracut (Arch Wiki):
Linux-Hardened Kernel (AlpineWiki):
- Hardened_linux [11]