Skip to content

Build signed efi binaries which mount a dm-verity verified squashfs image as rootfs on boot.

License

Notifications You must be signed in to change notification settings

brandsimon/verity-squash-root

Repository files navigation

verity-squash-root

Build signed efi binaries which mount a dm-verity verified squashfs image as rootfs on boot.

The goal of this project is to reduce the harm a successful attacker can do to a system. It prevents an attacker of persistently modifying the root-filesystem. This gets accomplished via building a chain-of-trust based on UEFI secure boot. The system-firmware verifies the signature of the UKI (unified-kernel-image). The UKI verifies the squashfs-rootfs via dm-verity. On boot you can choose to boot the squashfs with a tmpfs overlay. You start with the system you signed the last time and changes are discarded on power off. So if you reboot in the tmpfs variant, the system is in a state you signed before and the modifications in the time between by an attacker are gone. You can also boot in persistent mode, which loads changes from disk and saves them to the disk.

This project also provides A/B-style update support. The current booted files (GKI and squashfs) won't be overridden on updates, so you can boot an old known-good image if there are problems). The squashfs images are stored on the configured root-partition, so they will still be encrypted, if encryption of the root image is configured.

What happens on boot?

  • The initramfs mounts the root-partition as before. This is why encryption of the root-partition still works. Cmdline parameters to decrypt still need to be configured.
  • Depending on the kernel cmdline, either the A or B image will be verified via dm-verity and used. (The build command will set these automatically.) If you boot a tmpfs image, a tmpfs will be used as overlay image for volatile changes (Note: the changes will be stored in the system RAM). If you boot a non-tmpfs image, the folder overlay on the root-partition will be used as overlayfs upper directory to save persistent changes.

Install

  • Install verity-squash-root from AUR or install a package built by CI.
  • Create your encrypted secure-boot keys:
verity-squash-root --ignore-warnings create-keys
  • Mount your EFI partition and configure it.
  • Add your EFI partition to /etc/fstab.
  • Make sure your EFI partition is big enough (1 GB recommended).
  • Create directory /mnt/root.
  • Mount your root-partition to /mnt/root and configure it in fstab file.
  • Configure your kernel cmdline (see: Configuration)
  • Exclude directories or files not wanted in the squashfs in the config file (EXCLUDE_DIRS)
  • Configure a bind-mount for every excluded directory from /mnt/root/...
  • Configure distribution specific options (see Configuration)
  • Install systemd-boot, configure it and build the first image:
verity-squash-root --ignore-warnings setup systemd
verity-squash-root --ignore-warnings build
  • Now reboot into the squashfs
  • If everything works as expected, enable secure-boot with the keys from /etc/verity_squash_root/public_keys.tar.

Updates

  • Boot into a tmpfs image.
  • Update your distribution
  • Create new squashfs image with signed efis:
verity-squash-root build

Using custom keys

Make yourself familiar with the process of creating, installing and using custom Secure Boot keys. See:

After you have generated your custom keys:

cd to/your/keys/directory
tar cf keys.tar db.key db.crt
age -p -e -o keys.tar.age keys.tar
mv keys.tar.age /etc/verity_squash_root/
rm keys.tar
  • Remove your plaintext keys

Configuration

The config file is located at /etc/verity_squash_root/config.ini. These config options are available:

Section DEFAULT

  • CMDLINE: configures kernel cmdline, if not configured, fallback to /etc/kernel/cmdline.
  • EFI_STUB: path to efi stub, default is the one provided by systemd.
  • DECRYPT_SECURE_BOOT_KEYS_CMD: Command to decrypt your secure-boot keys tarfile, {} will be replaced with the output tar file. db.key and db.crt in the tarfile are used to sign the efi binaries.
  • EXCLUDE_DIRS: These directories are not included in the squashfs image. EFI_PARTITION and ROOT_MOUNT are excluded automatically.
  • EFI_PARTITION: Path to your efi partition. Efi binaries and systemd-boot configuration files are stored there.
  • ROOT_MOUNT: Path to your "original" root partition.
  • IGNORE_KERNEL_EFIS: Which efi binaries are not built. You can use the list parameter to show which can exist and which are excluded already.

Section EXTRA_SIGN

You can specify files to be signed when running with the sign_extra_files command. The format is:

NAME = SOURCE_PATH => DESTINATION_PATH

e.g. to sign the systemd-boot efi files:

[EXTRA_SIGN]
systemd-boot = /usr/lib/systemd/boot/efi/systemd-bootx64.efi => /boot/efi/EFI/systemd/systemd-bootx64.efi

Be careful to not specify files from untrusted sources, e.g. the ESP partition. An attacker could exchange these files.

Supported setups

Currently Arch Linux and Debian are supported with mkinitcpio and dracut. Mkinitcpio is only supported, if it is used with systemd-hooks.

Considerations / Recommendations

  • Directly before updating, reboot into a tmpfs overlay, so modifications made by an attacker are removed and you have your trusted environment from the last update.
  • If you enable automatic decryption of your secure-boot keys, an attacker who gets access can also sign efi binaries. So manually decrypting secure-boot keys via age is more secure.
  • To be sure to only enter the password for your secure-boot keys on your machine, you can verify your machine on boot with tpm2-totp or cryptographic-id.
  • Encrypt your root partition! If your encryption was handled by the initramfs (dracut/mkinitcpio) before installation, it will work with the squashfs root image as well.
  • You can only configure the network in the persistent system. This way you can download updates, reboot into the tmpfs system and install them offline.

Usage

To list all efi images, which will be created or ignored via IGNORE_KERNEL_EFIS:

verity-squash-root list

To install systemd-boot and create a UEFI Boot Manager entry for it:

verity-squash-root setup systemd

To add efi files to the UEFI Boot Manager with /dev/sda1 as EFI partition:

verity-squash-root setup uefi /dev/sda 1

To build a new squashfs image and efi files:

verity-squash-root build

If you are not yet booted in a verified image, you need --ignore-warnings, since there will be a warning if the root image is not fully verified.

Files

The following files will be used on your root-partition:

Images with verity info:

  • image_a.squashfs, image_a.squashfs.verity,
  • image_b.squashfs image_b.squashfs.verity

Overlayfs directories:

  • overlay workdir

Development

Dependencies

age (only when used for decryption of secure-boot keys)
binutils
cryptsetup-bin
efitools
python
sbsigntool
squashfs-tools
systemd-boot-efi (only when no other efi-stub is configured)
tar

Development

python-pyflakes
python-pycodestyle

Setup

Setup a python3 virtual environment:

git clone git@github.com:brandsimon/verity-squash-root.git
python3 -m venv .venv
.venv/bin/pip install -e . --no-deps

Run unit tests:

sudo mkdir -p /etc/mkinitcpio.d  # Otherwise mkinitcpio test will fail
.venv/bin/python -m unittest tests/unit/tests.py

Related resources