DM-verity: Difference between revisions

From Alpine Linux
mNo edit summary
mNo edit summary
 
(70 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Draft}}
== Why DM-Verity? ==
Possibly you want to continue the RoT ([https://en.wikipedia.org/wiki/Chain_of_trust 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) -> <u>To NOW DM-Verity rootfs</u> (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.


== Why DM-Verity? ==
=== What's the difference between me just setting the root partition as read-only (basically just an Immutable Root Partition) vs this? ===
Possibly you want to continue the RoT (Root of Trust) from the hardware -> secure boot -> to dm-verity rootfs, and you already use TPMs to ensure only the hardware can unlock the disk encryption, but now you want to ensure your root-image/root-parition has not been tampered with.
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 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.


=== What's the different between me just setting the root partition as read-only (or using Fedora's Immutable Root Partition) vs this? ===
{{tip| To keep the security reasonable, you would ideally want to work on the whole RoT, if not then anybody else can attack the non-verifed boot process that ISN'T the root-partition/root-image that is enforced by DM-Verity.
DM-Verity disallows tampering with the read-only partition, and with this consideration, you may use ERO-FS or SquashFS to generate Read-Only Root-Paritition Images. If you set your EXT4 file system to writable, and DM-Verity were to use it, it would be seen as "corurpted" 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.
* This following guide will use dracut to make a signed secureboot-able EFIStub.
* If you haven't, you may follow [https://wiki.alpinelinux.org/wiki/LVM_on_LUKS the Alpine Linux disk encryption setup] [2] with DM-Crypt LUKS and LVM
{{todo| Make the below bulleted item incorporated into the following Dracut guide}}
* You may choose to decrypt the image with TPM when generating with Dracut Modules with <code>add_dracutdrivers+{{=}}" ... tpm ... "</code> and [https://github.com/latchset/clevis?tab{{=}}readme-ov-file#pin-tpm2 Clevis] [3]
* Apply AppArmor using [https://wiki.alpinelinux.org/wiki/AppArmor 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 [https://gvisor.dev/docs/user_guide/install/ GVisor] [5] with Docker ([https://github.com/google/gvisor?tab{{=}}readme-ov-file#why-does-gvisor-exist 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? ===
=== What is ERO-FS? ===
[[https://pocketnow.com/erofs-android-13-explained/ Google thought about implementing it for DM-Verity]] [1]. But even if Google didn't use it for some reason, ERO-FS is still an excellent and fast compressed read-only filesystem.
[https://pocketnow.com/erofs-android-13-explained/ 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 <code>mkfs.erofs</code> on [[https://wiki.archlinux.org/title/Dm-verity Arch Linux Wiki]] [2]:
Here is an excerpt about <code>mkfs.erofs</code> on [[https://wiki.archlinux.org/title/Dm-verity 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. ''
'' 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 ===
=== Installing ===
{{note| This wiki will be using Alpine Linux Edge Version. (Alpine Linux Non-Edge Versions may not contain these packages in the this wiki page) (Use Alpine Linux Edge Testing as well)}}


First, some considerations, you may use a strictly READ-ONLY file system, such as SquashFS or EROFS, this wiki will be using EROFS (if you use a custom kernel, make sure it supports a file system such as ERO-FS, the default linux-lts does). [[https://github.com/erofs/erofs-utils ERO-FS Github]] [3] contains some information about how to compress and make your own read-only root image.
==== Working with ERO-FS ====
 
{{warning| This wiki will be using Alpine Linux Edge Version. (Alpine Linux Non-Edge Versions may not contain these packages in the following rest of the wiki page) (Use Alpine Linux Edge Testing Repository in <code>/etc/apk/repositories</code> as well)}}
 
{{note| To not be confused, ERO-FS generates a "root image", but you can replace the words "root partition" with "root image" and vice versa.}}
 
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). [[https://github.com/erofs/erofs-utils ERO-FS Github]] [9] contains some information about how to compress and make your own read-only root image.


{{cmd| $ apk install dracut erofs-utils}}
{{cmd| $ apk install erofs-utils}}
{{cmd| $ mkdir image && cd image }}
{{cmd| $ mkdir image && cd image }}
{{cmd| $ wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.0-x86_64.tar.gz}}
{{cmd| $ wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.0-x86_64.tar.gz}}
{{cmd| $ tar -xvf alpine-minirootfs-3.21.0-x86_64.tar.gz}}
{{cmd| $ tar -xvf alpine-minirootfs-3.21.0-x86_64.tar.gz && rm alpine-minirootfs-3.21.0-x86_64.tar.gz}}
{{cmd| $ cd .. && mkfs.erofs erofs.img ./image}}
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)
{{cmd| $ cd .. && mkfs.erofs -zlz4hc erofs.img ./image}}
 
----
 
==== Working with Dracut ====
 
If you want to use DM-Verity on Alpine Linux, you need to use [https://wiki.archlinux.org/title/Dracut Dracut] [10] (Thus also generating a secure boot EFIStub with it as well). Reason is because dracut is one of the only initramfs generators to let you import your own modules and files into its initramfs.
 
Also remember, mount your <code>$ROOT_PARTITION</code> 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"
 
{{warning| The following guide was done with FULL disk encryption, so this might not work perfectly on Non encrypted disk setup, also done on UEFI using gummiboot (now called systemd-boot - yes, systemd-boot is a separate project from the systemd init system) EFIStub and generating a UKI (Unified Kernel Image)}}
 
===== Install basic stuff: =====
 
{{cmd| apk add dracut dracut-core cryptsetup gummiboot gummiboot-efistub}}
 
===== Create a new partition for your DM-Verity: =====
 
Replace /dev/sdX with your actual device name.
{{cmd |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 "<code>/usr/lib/dracut/modules.d/90crypt/cryptroot-ask.sh</code>" and add these lines right BEFORE "<code>exit 0</code>" (add your <code>$ROOT_PARTITION</code> directory and <code>$VERITY_PARTITION</code> directory):
 
{{cat| /usr/lib/dracut/modules.d/90crypt/cryptroot-ask.sh|...
### DM-Verity
mount /dev/mapper/$ROOT_PARTITION /var/tmp
cryptsetup open --key-file /var/tmp/$KEYFILE_DIR /dev/$VERITY_PARTITION $VERITY_DM_NAME
umount /var/tmp
veritysetup open /dev/$ROOT_PARTITION /dev/$VERITY_PARTITION $(cat /usr/lib/dracut/roothash.txt)
###
...}}
 
===== Generating an EFIStub with Dracut + DM-Verity =====
 
To setup DM-Verity (borrowed from [https://wiki.archlinux.org/title/Dm-verity Arch Linux Wiki]):
 
{{cmd| veritysetup format /dev/$ROOT_PARTITION /dev/$VERITY_PARTITION | grep Root | cut -f2 >> /usr/lib/dracut/roothash.txt}}
 
/etc/dracut.conf (put whatever your boot parameters are in "<code>kernel_cmdline</code>"):
 
{{cat| /etc/dracut.conf|...
kernel_cmdline{{=}}""
add_dracutdrivers+{{=}}" busybox crypt crypt-gpg dm rootfs-block kernel-modules kernel-modules-extra "
/etc/dracut.conf.d/secureboot.conf
 
# Do the 3 lines below this if you have your own secureboot keys, or want to use secureboot:
uefi_secureboot_cert{{=}}"/[secureboot-keys-directory]/db.crt"
uefi_secureboot_key{{=}}"/[secureboot-keys-directory]/db.key"
/etc/dracut.conf.d/files.conf
 
install_items+{{=}}" /sbin/veritysetup " # This is what will import veritysetup binary file into dracut initramfs
...}}
 
Finally, generate UKI using dracut (replace <code>6.X.X-X-lts</code> with your kernel <code>$VERSION</code>) (also replace <code>/boot/efi/EFI/Linux/alpine-linux.efi</code> with your mount efi partition):
 
{{cmd| export DRACUT_KMODDIR_OVERRIDE{{=}}1}}
{{cmd| 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}}
{{cmd| efibootmgr --create --disk /dev/[efi_partition] --part 1 --label alpine-linux --loader EFI/Linux/alpine-linux.efi}}
 
Unfortunately, using the default Alpine Linux kernel (<code>linux-lts</code>) didn't work so download another distributions root system (like debians or devuan), and replace <code>/lib/modules/6.X.X-X-lts</code>, and <code>/boot/vmlinuz-lts</code> with anothers distributions kernel modules and kernel image (Or consider compiling your [https://wiki.alpinelinux.org/wiki/Hardened_linux own linux-hardened kernel] [11]).
 
{{tip| If you want to test if DM-Verity fully works, change the <code>$ROOT_PARTITION</code>'s files and it should say it is "corrupt", and not continue the boot process (only if you use EXT4).}}


== External Links ==
== External Links ==
==== Link about Android-13 Possibility of using ERO-FS: ====
==== Root of Trust/Chain of Trust ====
* [https://pocketnow.com/erofs-android-13-explained/ https://pocketnow.com/erofs-android-13-explained/] [1]
* [https://en.wikipedia.org/wiki/Chain_of_trust https://en.wikipedia.org/wiki/Chain_of_trust] [1]
==== Full disk encryption with LVM and LUKS (AlpineWiki): ====
* [https://wiki.alpinelinux.org/wiki/LVM_on_LUKS LVM_on_LUKS] [2]
==== Clevis Github ====
* [https://github.com/latchset/clevis?tab=readme-ov-file#pin-tpm2 https://github.com/latchset/clevis?tab=readme-ov-file#pin-tpm2] [3]
==== AppArmor Wiki (AlpineWiki) ====
* [https://wiki.alpinelinux.org/wiki/AppArmor AppArmor] [4]
==== GVisor ====
* [https://gvisor.dev/docs/user_guide/install/ https://gvisor.dev/docs/user_guide/install/] [5]
==== Gvisor Github stating docker is not a sandbox ====
* [https://github.com/google/gvisor?tab=readme-ov-file#why-does-gvisor-exist https://github.com/google/gvisor?tab=readme-ov-file#why-does-gvisor-exist] [6]
==== Android-13 Possibility of using ERO-FS: ====
* [https://pocketnow.com/erofs-android-13-explained/ https://pocketnow.com/erofs-android-13-explained/] [7]
==== DM-Verity (Arch Wiki): ====
==== DM-Verity (Arch Wiki): ====
* [https://wiki.archlinux.org/title/Dm-verity https://wiki.archlinux.org/title/Dm-verity] [2]
* [https://wiki.archlinux.org/title/Dm-verity https://wiki.archlinux.org/title/Dm-verity] [8]
==== ERO-FS Github ====
==== ERO-FS Github ====
* [https://github.com/erofs/erofs-utils https://github.com/erofs/erofs-utils] [3]
* [https://github.com/erofs/erofs-utils https://github.com/erofs/erofs-utils] [9]
==== Dracut (Arch Wiki): ====
* [https://wiki.archlinux.org/title/Dracut https://wiki.archlinux.org/title/Dracut] [10]
==== Linux-Hardened Kernel (AlpineWiki): ====
* [https://wiki.alpinelinux.org/wiki/Hardened_linux Hardened_linux] [11]
==== My old post on how it worked ====
* [https://www.reddit.com/r/AlpineLinux/comments/15oibcc/comment/k1l7jv0/ https://www.reddit.com/r/AlpineLinux/comments/15oibcc/comment/k1l7jv0/] [12]


[[Category:Security]] [[Category:InitRAMFS]]
[[Category:Security]] [[Category:Booting]]

Latest revision as of 02:47, 16 December 2024

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 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.

Tip: To keep the security reasonable, you would ideally want to work on the whole RoT, if not then anybody else can attack the non-verifed boot process that ISN'T the root-partition/root-image that is enforced by DM-Verity.
Todo: Make the below bulleted item incorporated into the following Dracut guide

  • You may choose to decrypt the image with TPM when generating with Dracut Modules with add_dracutdrivers+=" ... tpm ... " 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

Warning: This wiki will be using Alpine Linux Edge Version. (Alpine Linux Non-Edge Versions may not contain these packages in the following rest of the wiki page) (Use Alpine Linux Edge Testing Repository in /etc/apk/repositories as well)


Note: To not be confused, ERO-FS generates a "root image", but you can replace the words "root partition" with "root image" and vice versa.

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


Working with Dracut

If you want to use DM-Verity on Alpine Linux, you need to use Dracut [10] (Thus also generating a secure boot EFIStub with it as well). Reason is because dracut is one of the only initramfs generators to let you import your own modules and files into its initramfs.

Also 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"

Warning: The following guide was done with FULL disk encryption, so this might not work perfectly on Non encrypted disk setup, also done on UEFI using gummiboot (now called systemd-boot - yes, systemd-boot is a separate project from the systemd init system) EFIStub and generating a UKI (Unified Kernel Image)


Install basic stuff:

apk add dracut dracut-core cryptsetup gummiboot gummiboot-efistub

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:

  1. Press n to create a new partition
  2. Choose p for primary partition
  3. Select the partition number (e.g., 4)
  4. For the first sector, press Enter to use the default
  5. 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
  6. Press t to change the partition type
  7. Enter the partition number you just created
  8. Type 8e for Linux LVM type (closest to verity)
  9. 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

... ### DM-Verity mount /dev/mapper/$ROOT_PARTITION /var/tmp cryptsetup open --key-file /var/tmp/$KEYFILE_DIR /dev/$VERITY_PARTITION $VERITY_DM_NAME umount /var/tmp veritysetup open /dev/$ROOT_PARTITION /dev/$VERITY_PARTITION $(cat /usr/lib/dracut/roothash.txt) ### ...
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

... kernel_cmdline="" add_dracutdrivers+=" busybox crypt crypt-gpg dm rootfs-block kernel-modules kernel-modules-extra " /etc/dracut.conf.d/secureboot.conf # Do the 3 lines below this if you have your own secureboot keys, or want to use secureboot: uefi_secureboot_cert="/[secureboot-keys-directory]/db.crt" uefi_secureboot_key="/[secureboot-keys-directory]/db.key" /etc/dracut.conf.d/files.conf install_items+=" /sbin/veritysetup " # This is what will import veritysetup binary file into dracut initramfs ...

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

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]).

Tip: If you want to test if DM-Verity fully works, change the $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):

Clevis Github

AppArmor Wiki (AlpineWiki)

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):

My old post on how it worked