A few minor mods to Pitop OS.

28 July 2021

Some time ago I wrote up a minor project I'd done, rigging up Raspberry Pi OS to run on a Pi-Top. And then never revisited the post.

I think you can guess why. It didn't go very well.

Even though all of the secret sauce software is available in the Raspberry Pi OS package repositories these days and there is a process for installing it, for whatever reason they don't quite work right. The speakers were never detected, nor was even the system hub detected. Finally, my tinkering wrecked the desktop configuration entirely. After some frustrated debugging, I kicked it in the head and grabbed the latest rev of Pi-Top OS. While tinkering with it I actually wrote down everything I did (which will involve a separate exocortex post in and of itself) this time. With source links. So, in case somebody else out there is in a similar fix, here they are.

First, let's tweak a few system settings. Go to User Preferences -> Raspberry Pi Configuration:

  • change hostname
  • boot: to desktop
  • auto login: disabled
    • • I haven't tried yet with this enabled, to be honest.
  • network at boot: disabled
  • splash screen: disabled
  • Interfaces disabled:
    • • camera
    • • VNC
    • • serial port
    • • 1-wire
    • • remote GPIO
  • GPU memory: 64
    • • I don't need a whole lot of video memory but maybe you do. Up to you.

Be sure to set a password on the root account to unlock it, in case you need to get in and debug something! Consider enabling sshd (touch /boot/ssh.txt) as well.

Turn off IPv6 in /etc/systemctl.d/99-sysctl.conf:

net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
net.ipv6.conf.eth0.disable_ipv6=1

Technically leaving this turned on is a good idea. In practice, I found out the hard way that it bogs everything down because Linux tries to resolve the IPv6 address, times out most of the time because there isn't any AAAA DNS record, and then finds the IPv4 address in DNS. It kinda sucks. But that's a rant for a different time.

Get rid of Visual Studio:

  • sudo apt-purge code
  • sudo apt autoremove

Or don't, if it's your jam. No judgement.

Then sure a few critical packages are installed:

sudo apt-get install -y cryptsetup ecryptfs-utils initramfs-tools lsof

Turn off a couple of system services to free up compute cycles:

  • avahi-daemon.service
  • avahi-daemon.socket
  • cups-browsed.service
  • cups.service
  • cups.socket
  • geoclue.service
    • systemctl disable geoclue.service
    • systemctl mask geoclue.service

There are three services that are always started up which can really bog down the system. Delete these:

  • /etc/xdg/autostart/compton.desktop
  • /etc/xdg/autostart/geoclue-demo-agent.desktop
  • /etc/xdg/autostart/print-applet.desktop
    • • Unless you really do need to print stuff, then don't do this.

Now for the fun part: Putting /home on an encrypted flash drive. I leave it plugged in all the time because my home directory's on it. Because they're not too expensive these days I went with an ultra-tiny (to fit inside the case) 256 gig flash drive that also seems to be pretty fast. I then cribbed liberally from this web page which is a good starting point. I do recommend benchmarking the LUKS-related cryptosystems on your RasPi (cryptsetup benchmark); my results definitely did not match those on the website in question. The compiled in default of aes-xts-plain64 was much faster than the recommended one. You might not have to do anything really exotic in that regard.

Partition the flash drive and set up a LUKS volume. Here's what I did:

sudo cryptsetup --type luks2 --iter-time 5000 -y luksFormat /dev/sda1
sudo cryptsetup luksOpen /dev/sda1 pitop
sudo mkfs.ext4 -c -v -L pitop /dev/mapper/pitop
sudo mount /dev/mapper/pitop /mnt

Don't forget to set a strong password that you can also remember when prompted.

Now the fun part: Make a copy of your home directory (/home/pi) into the flash drive's encrypted volume. To make things a little more standard we're going to mount the flash drive on /home instead of /home/pi:

sudo mkdir -p /mnt/home/pi

# The trailing slashes are important, don't leave them out.
sudo rsync -avz /home/pi/ /mnt/home/pi/

Depending on how much you've used your Pi-Top this might take a while, so make sure that you have enough battery power, or that it's plugged into the wall. Now two config files have to be edited, /etc/fstab (which tells the OS where to mount what filesystem when) and /etc/crypttab (which is what tells Pi-Top OS that there are encrypted volumes that will need to be unlocked at boot-time). Add the following to /etc/fstab; you can leave the #comment out if you like:

# disk device       where   FS      mount options       don't dump(8)   fsck last
/dev/mapper/pitop   /home   ext4    defaults,noatime    0               2

And now, /etc/crypttab, without #comment if you like:

# /dev/mapper/what  disk device     key file    type of encrypted volume
pitop               /dev/sda1       none        luks

Now the twitchy part: Because LUKS is part of the Linux kernel, and some kernel modules need to be available at boot-time, we have to make sure that everything is available in the initramfs. We only have to do this once, thankfully. As the root user, create the file /etc/kernel/postinst.d/initramfs-rebuild with the following contents:

#!/bin/sh -e

# Rebuild initramfs.gz after kernel upgrade to include new kernel's modules.
# https://github.com/Robpol86/robpol86.com/blob/master/docs/_static/initramfs-rebuild.sh
# Save as (chmod +x): /etc/kernel/postinst.d/initramfs-rebuild

# Remove splash from cmdline.
if grep -q '\bsplash\b' /boot/cmdline.txt; then
  sed -i 's/ \?splash \?/ /' /boot/cmdline.txt
fi

# Exit if not building kernel for this Raspberry Pi's hardware version.
version="$1"
current_version="$(uname -r)"
case "${current_version}" in
  *-v7+)
    case "${version}" in
      *-v7+) ;;
      *) exit 0
    esac
  ;;
  *+)
    case "${version}" in
      *-v7+) exit 0 ;;
    esac
  ;;
esac

# Exit if rebuild cannot be performed or not needed.
[ -x /usr/sbin/mkinitramfs ] || exit 0
[ -f /boot/initramfs.gz ] || exit 0
lsinitramfs /boot/initramfs.gz |grep -q "/$version$" && exit 0  # Already in initramfs.

# Rebuild.
mkinitramfs -o /boot/initramfs.gz "$version"

What this shell script does is edit the /boot/cmdline.txt file to make sure that a particular option is not present and rebuilds the /boot/initramfs.gz file if the kernel has been updated (usually with sudo apt-get upgrade). Now we need another shell script (/etc/initramfs-tools/hooks/luks_hooks) to make sure some essential tools are in the initramfs:

#!/bin/sh -e
PREREQS=""
case $1 in
        prereqs) echo "${PREREQS}"; exit 0;;
esac

. /usr/share/initramfs-tools/hook-functions

copy_exec /sbin/resize2fs /usr/sbin
copy_exec /sbin/fdisk /usr/sbin
copy_exec /sbin/cryptsetup /usr/sbin

Now we need a file that lists the kernel modules that need to be available at boot-time, /etc/initramfs-tools/modules:

aes_arm_bs
algif_skcipher
dm-crypt
dm-mod
sha256_generic

Make sure the shell scripts you just created (ideally with copy-and-paste, because retyping all of that kinda sucks):

sudo chmod 0755 /etc/kernel/postinst.d/initramfs-rebuild /etc/initramfs-tools/hooks/luks_hooks

Now let's test all of these mods by running the process manually, by first regenerating the initramfs:

# We have to do this as root.
sudo -s

CRYPTSETUP=y mkinitramfs -o /boot/initramfs.gz

This'll take a minute or two, so sit tight. Now we take a peek inside the initramfs to make sure that everything is in there. If both of these commands have outputs that aren't obvious errors everything worked.

lsinitramfs /boot/initramfs.gz | grep -P "sbin/(cryptsetup|resize2fs|fdisk)"
lsinitramfs /boot/initramfs.gz | grep -P "(algif_skcipher|aes_arm_bs|sha256_generic|dm-crypt)"

Edit the /boot/config.txt file and append the following to its contents:

initramfs initramfs.gz followkernel

Edit the /boot/cmdline.txt file and make sure that the words "quiet" and "splash" aren't in there. If they are, delete them.

Now the moment of truth - does it work? Shut down your Pi-Top, count to 10, and then turn it back on. You should notice a few things, among them the fact that there's no splash screen anymore, just lots of messages from the Linux kernel as it boots up. At some point you'll be prompted to enter a passphrase to unlock the volume "PITOP" - type the passphrase you set when you formatted the flash drive. If it matches the boot process will continue, and you'll be presented with the Pi-Top desktop. If you see it, you're good to go. Nice work.