Bootable snapshots and Full Disk Encryption on the Pinebook Pro

Intro

Ever since I got the pinebook pro, I have waited for the ability to put /boot on the same filesystem as the OS on an ecrypted partition. While it is not enough for fully trusted computing, having a single partition containing the entire OS would be wonderful.

I have been using archlinuxarm-pbp on my pinebook pro since the beginning, I like to live on the edge, having the latest packages. This also means though that I have to deal with some… possibility of breakage, especially since I tinker (a lot).

Putting the whole OS on single block device allows me to use btrfs snapshots with snapper and snap-pac so that when I perform updates, I can automatically do a full OS snapshot, excluding my home directory, logs, and package caches. Couple this with a bootloader which can provide menus to choose various options, I can even boot the system (readonly) from a previous snapshot, and restore the snapshot if I like.

Today, I introduce the method I used to setup bootable snapshots on an encrypted partition on the pinebook pro. This is not for beginners, but I am happy to help if you have problems, reach out on Matrix or in the Fediverse, or email.

Boot Loader

The team at https://tow-boot.org/ have done an excellent job with Tow-Boot, which builds upon u-boot to provide some options more familiar to the user who has worked on X86 machines. I chose to install tow-boot to the SPI flash. You can download the release from here, or grab it with archlinuxarm-pbp install like we do below.

Operating System

I run archlinuxarm-pbp. It does a great job of providing me something minimal to build my custom setup with. You will probably need to use the Arch Wiki to help with installation.

Preparation

First, download the tar.gz from the archlinuxarm-pbp releases, to get an idea of how it is typically installed, take a look at the installation instructions

I am just going to post how I did it though. In order to install to the emmc, we need an sdcard with archlinuxarm-pbp on it.

Standard install onto a microsd card

First, follow the microsd installation, as that will become our installation media.

Once done, boot the pinebook pro from the microsd card, and follow along

Installation

Clean the emmc

Wipe the beginning of the emmc ( this is to ensure no previous bootloader signatures are there )

dd if=/dev/zero of=/dev/mmcblk2 bs=1M count=32

Partitioning

Partition the disk, but we are going to do a slightly different partition layout:

fdisk /dev/mmcblk2

Press o to make a dos partition table (this may work with gpt as well) Press n to make a new partition Press p to make it primary, 1 to make it the first, 2048 for the first sector and +64M for the last sector. Press t, choos partition one, and provide hex code ef for EFI ^^ The above creates a 64M size EFI partition.

now is the time to make a swap partition if you want one, since suspend-to-disk(hibernation) doesnt currently work on pbp, i skipped this step

Press n to create a new partition Choose p to make it primary, 2 to make it the second Press enter to let it select the first sector Press enter again to select the last sector Press t, choose 2 to select the 2nd partition, and use hex code 83 for Linux.

Press w to write the changes when you are done

Filesystems

We need to put a FAT EFI filesystem on the first partition.

mkfs.vfat -F32 /dev/mmcblk2p1

For the 2nd, we are going to put the filesystem on top of encryption, lets setup encryption first:

# Note we use `--type luks1` because at the time of writing, grub may not support luks2, support should be there shortly.
# After examining `cryptsetup benchmark` aes-xts-plain with size 512 seems like a good compromise for this system. Feel free to make your own choices though.
cryptsetup luksFormat /dev/mmcblk2p2 --type luks1 --cipher aes-xts-plain64 -s 512

Type all caps YES and hit enter

Enter the passphrase twice

Now lets open the new encrypted partition with the name ‘cryptroot’:

cryptsetup luksOpen /dev/mmcblk2p2 cryptroot

Enter the password to decrypt the partition.

Now lets put a btrfs filesystems on it:

mkfs.btrfs /dev/mapper/cryptroot

Mount the filesystem:

sudo mount /dev/mapper/cryptroot /mnt

We need to create some btrfs subvolumes so we can do snapshots properly:

btrfs subvolume create /mnt/@{home,root,snapshots,var_cache_pacman,var_log}

Unmount the root of the btrfs device and remount it properly

We will mount the snapshots subvol later Compression is not required here, but from my understating, compression can actually speed up disk access, at the very least, this shouldnt hurt things much. You can change it later too.

umount /mnt
mount -osubvol=/@root,compress=zstd:1 /dev/mapper/cryptroot /mnt
mount -osubvol=/@home,compress=zstd:1 /dev/mapper/cryptroot /mnt/home
mount -osubvol=/@var_log,compress=zstd:1 /dev/mapper/cryptroot /mnt/var/log
mount -osubvol=/@var_cache_pacman,compress=zstd:1 /dev/mapper/cryptroot /mnt

Installation

We can just copy the installation from the microsd:

rsync -aAXq --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/lost+found"} / /mnt

Install Tow-Boot to the SPI flash:

Be careful here, recovery from a bad flash can be a pain, make sure you dont power off, and that the battery doesnt die during this process, we are writing to a chip on the motherboard

flash_erase /dev/mtd0 0 0
nandwrite -p /dev/mtd0 /mnt/boot/Tow-Boot.spi.bin

We need to fix the fstab

genfstab -U  >> /mnt/etc/fstab

Customization

Now we need to chroot into our new installatation and take care of a few things!

arch-chroot /mnt

We need to update our initramfs to support encryption of the root filesystem, including display drivers so it can provide a password prompt edit the lines of the following files:

/etc/mkinitcpio.conf

# Modules to include in the initramdisk
MODULES=(gpu_sched panfrost rockchipdrm drm_kms_helper dw_mipi_dsi hantro_vpu analogix_dp rockchip_rga panel_simple panel_edp arc_uart cw2015_battery i2c-hid iscsi_boot_sysfs jsm pwm_bl uhid)

# Hooks to use
HOOKS=(base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt filesystems fsck)

#Optionally speed up boot and initramfs creation by setting the following:
COMPRESSION="cat"

Regenerate the initramfs:

mkinitcpio -P linux

We also need to install grub:

pacman -S grub efibootmgr
#Symlink the kernel image because linux-manjaro gives it a weird name that won't be detected by grub.
ln -s /boot/Image /boot/vmlinuz-linux

Edit the grub configurations, get the UUID first:

blkid /dev/mapper/cryptroot

/etc/default/grub

GRUB_CMDLINE_LINUX="rd.luks.name=YOUR-UUID=cryptroot"
# You can also do this instead, allowing discards(trim) on the root filesystem (this has security implications)

GRUB_CMDLINE_LINUX="GRUB_CMDLINE_LINUX="rd.luks.name=YOUR-UUID=cryptroot rd.luks.options=allow-discards"

#This is also necessary:
GRUB_PRELOAD_MODULES="part_gpt part_msdos"

#Uncomment the following line:
GRUB_ENABLE_CRYPTODISK=y

Install grub and generate its configuration:

grub-install --target=arm64-efi --efi-directory=/boot/efi --bootloader-id=GRUB --recheck /dev/mmcblk2p2 --removable --modules="part_gpt part_msdos"
grub-mkconfig -o /boot/grub/grub.cfg

Exit and reboot

exit # To leave the chroot
cd /
umount -R /mnt
reboot

When the system boots, it should automatically go to emmc first, and pop up a password prompt. Note, you will have to type the password twice, and the first one takes a LONG LONG time, please be patient.

Snapper

Once we are booted, we can now setup snapper! Login with alarm:alarm Become root with su -

pacman -S snapper
snapper -c root create-config /
#Snapper automatically creates /.snapshots, but we dont want that as it makes complications for restoring a snapshot.
btrfs subvol remove /.snapshots
mkdir /.snapshots

# Mount our snapshots subvolume onto /.snapshots
mount -o subvol=/@snapshots /dev/mapper/cryptroot /.snapshots
# Add the new mount to fstab
mount | grep @snapshots >> /etc/fstab

Now we want to setup snap-pac, to make snapshots whenever we change packages with pacman.

pacman -S snap-pac

Then we can install snap-pac-grub from the AUR, I use an AUR helper called pikaur, but you can use whichever works for you. This will automatically update grub configuration when we make package changes.

pikaur -S snap-pac-grub

If you aren’t using a helper, you can clone the PKGBUILD and just create and install the package yourself. You may need to import a gpg key, or add keyserver-options auto-key-retrieve to your ~/.gnupg/gpg.conf file.

git clone https://aur.archlinux.org/snap-pac-grub.git
cd snap-pac-grub
makepkg -i

After the install, it should have automatically created your grub config with snapshots, and you should be able to boot the snapshots as you like. We followed https://wiki.archlinux.org/title/Snapper#Suggested_filesystem_layout to make it easier to roll back to a previous snapshot, and boot from them, but note that snapper rollback may not work as expected.

Conclusion

Thanks for following along. Hopefully, you should now be able to setup your pinebook pro with bootable btrfs snapshots on an encrypted partition. I want to drop some special thanks here for [SvenKiljan[(https://kiljan.org/2021/06/20/arch-linux-arm-on-a-pinebook-pro/) for maintaining archlinuxarm-pbp and the team at tow-boot for releasing a bootloader build that could init the display and keyboard.

By @Charims in
Tags : #hardware, #hacking, #alternative hardware, #arm64, #encryption, #grub, #pine64, #pinebook pro, #btrfs,