‹ back home

Installing postmarketOS on a OnePlus 6 with an encrypted filesystem

2023-04-12 #how-to #linux-mobile #open-source #qemu

I’ve been experimenting with postmarketOS for a long time now. My long-term aspiration is to set up a phone that I can use as a daily driver. I need to overcome a lot of obstacles to achieve this.

Today, my goal is to encrypt the main partition. So if I lose the phone, it doesn’t have all my messaging, email and credentials totally unencrypted. This is a hard requirement before moving forward with a lot of other things.

Encrypting the main partition is a lot more complex on pmOS compared to a regular computing device. On most other devices (desktop, laptop server or even a Raspberry Pi) I would usually boot into a minimal environment with the tools necessary for partitioning, encrypting installation, etc.

postmarketOS takes a rather distinct approach to installation: instead of running the installation and setup process on the device, an entire disk image must be build on another computer, and then flashed over onto the phone. This approach works really well if you have a dozens or hundreds of devices and makes things a bit simpler for devices that don’t have physical keyboards. Personally: I would have preferred a simple installation via SSH.

Preparing a workspace VM

To create a device image, I need a privileged environment with pmbootstrap. I’m going to use a VM for this to avoid messing up my system.

First, create a disk image for the VM:

qemu-img create workspace.img 20G

Then, download the Alpine “virtual” image, and run a VM with both the disk and the Alpine installation image installed (notes on qemu usage):

qemu-system-x86_64 --enable-kvm \
    -nic user \
    -nographic \
    -m 1G \
    -smp cores=2 \
    -drive file=alpine-virt-3.17.3-x86_64.iso,format=raw \
    -drive file=workspace.img,format=raw

You might have to drop --enable-kvm if you hardware doesn’t support KVM. If you’re on aarch64 just use the aarch64 image and qemu-system-aarch64. You don’t need to use x86_64, this is just what matches my architecture.

In the VM, use setup-alpine and go through the Alpine installation process. Nothing special needs to be done here.I didn’t bother setting up ssh here and left an empty root password.

Then turn off the VM with poweroff, and start it again, this time without the installation media and exposing a directory on the host via 9p:

qemu-system-x86_64 --enable-kvm \
    -nic user \
    -nographic \
    -m 1G -smp cores=2 \
    -drive file=workspace.img,format=raw \
    -virtfs local,path=/home/hugo/workspace/oneplus/output,mount_tag=output,security_model=mapped-xattr

Log in as root, and then edit /etc/apk/repositories. Uncomment the edge repositories and remove everything else. E.g.:

http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing

Run apk update && apk upgrade -a and then reboot (the kernel likely gets updated, so it’s best to boot into the new one).

Building the device images

Install pmbootstrap. It also expects either sudo or doas to be installed and configured. sudo is the easier choice, since it comes pre-configured to allow root to use it for anything (and I’ll be using user root).

apk add pmbootstrap sudo

pmbootstrap uses sudo a lot. Simply building an image has 155 invocations of so it would need to be configured with NOPASSWD, plus a dedicated user for it, and then need to sudo -u newuser pmbootstrap each call. I’m going to skip this pointless indirection entirely:

alias pmbootstrap="pmbootstrap --as-root"

Now initialise it:

pmbootstrap init

The default work path is fine, and so is the edge channel. However, for vendor and device pick the ones matching your phone. That’s oneplus and enchilada respectively for me. See pmOS#Devices to find yours.

There’s a variety of user interfaces available. phosh is a simple user friendly one, but not very flexible, tweakable nor developer-oriented. I’m going with sxmo-de-sway. sxmo takes some learning to initially understand (especially if you’re coming from iOS/Android), but it’s the most hackable one and a very good target if you’re wanting to develop applications and test them on phones.

Additional packages can be specified at this time. For example:

zsh,docs,git,neovim,font-noto-cjk,cargo,yubikey-manager,dino,telegram-desktop,bubblewrap

Now it’s time to build the actual image. Contrary to what I initially expected pmbootstrap build does not build the image (this command builds a single package). It’s pmbootstrap install that builds an image, and pmbootstrap export creates some handy symlinks to it.

To build an image with full disk encryption, use pmbootstrap install --fde.

Put together, it all looks something like this:

# pmbootstrap install --fde
[... lots of output ommitted ...]
# pmbootstrap export
[13:34:56] (rootfs_oneplus-enchilada) install device-oneplus-enchilada
[13:34:58] (rootfs_oneplus-enchilada) install postmarketos-mkinitfs
[13:35:00] (rootfs_oneplus-enchilada) mkinitfs postmarketos-qcom-sdm845
[13:35:03] Export symlinks to: /tmp/postmarketOS-export
[13:35:03]  * boot.img (Fastboot compatible boot.img file, contains initramfs and kernel)
[13:35:03]  * initramfs-extra (Extra initramfs files in /boot)
[13:35:03]  * initramfs (Initramfs)
[13:35:03]  * vmlinuz (Linux kernel)
[13:35:03]  * oneplus-enchilada.img (Rootfs with partitions for /boot and /)
[13:35:03] NOTE: chroot is still active (use 'pmbootstrap shutdown' as necessary)
[13:35:03] DONE!
# ls -l /tmp/postmarketOS-export/
total 0
lrwxrwxrwx    1 root     root            74 Apr 12 13:30 boot.img -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/boot.img
lrwxrwxrwx    1 root     root            75 Apr 12 13:30 initramfs -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/initramfs
lrwxrwxrwx    1 root     root            81 Apr 12 13:30 initramfs-extra -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/initramfs-extra
lrwxrwxrwx    1 root     root            81 Apr 12 13:30 oneplus-enchilada.img -> /root/.local/var/pmbootstrap/chroot_native/home/pmos/rootfs/oneplus-enchilada.img
lrwxrwxrwx    1 root     root            73 Apr 12 13:30 vmlinuz -> /root/.local/var/pmbootstrap/chroot_rootfs_oneplus-enchilada/boot/vmlinuz

Now mount the directory that’s exposed from the host. Note that output here matches the value provided for mount_tag when specified when running qemu:

mount -t 9p -o trans=virtio output /mnt

An copy the images out:

cp /tmp/postmarketOS-export/boot.img /mnt/
cp /tmp/postmarketOS-export/oneplus-enchilada.img /mnt/

It is now safe to turn off the virtual machine: poweroff.

Flashing the images onto the device

I’m assuming the device is already unlocked (otherwise check the Devices wiki page linked above). Make sure the USB cable is not plugged into the phone and then press and hold VolUp+Power. After it boots, it will indicate “Fastboot” mode and once it’s in the menu you can release first VolUp, then Power. Now plug the USB cable onto the phone and the other end of it to your other computer.

Flash the images onto the device and then reboot it:

doas fastboot flash boot boot.img
doas fastboot flash userdata oneplus-enchilada.img
doas fastboot reboot

During the initial boot, the main partition will be extended to occupy all of the disk.

The initial installation is now done.

— § —