Skip to content

Instantly share code, notes, and snippets.

@NekkoDroid
Last active July 5, 2024 11:52
Show Gist options
  • Save NekkoDroid/f5ecc9540863eaad7752f73587b419de to your computer and use it in GitHub Desktop.
Save NekkoDroid/f5ecc9540863eaad7752f73587b419de to your computer and use it in GitHub Desktop.

This document is mostly just a write-down some thoughts about the partition layout mentioned in Fitting Everything Together.

The proposed layout for image based systems is (all created by systemd-repart):

  1. EFI System Partition
  2. usr Partition (A) with label fooOS_0.1
  3. usr-verity Partition (A) with label fooOS_0.1
  4. usr-verity-sig Partition (A) with label fooOS_0.1
  5. usr Partition (B) with label _empty
  6. usr-verity Partition (B) with label _empty
  7. usr-verity-sig Partition (B) with label _empty
  8. root Partition, encrypted and locked to TPM2
  9. home Partition, integrity protected with TPM2 (managed by sd-homed)
  10. swap Partition, encrypted and locked to TPM2

This in my mind has the following problems:

  1. When wanting to dual-boot with Windows an already existing an EFI System Parition will already exist, which by default has ~100M of storage space. This is not enough for generic UKIs (especially not multiple), therefor the XBOOTLDR partiton will be required to store the UKIs. The EFI System Partition would only hause systemd-boot, its config and some other small EFI binaries which can be installed with bootctl install, therefor systemd-repart does not need to learn to merge/selectivly copy files into an existing partiton as I see that could cause some unexpected issues down the road.
  2. Having a single root partition results in system configuration being modifyable by default, which reduces the barrier to causing accidental breakage. Idealy no root partition exists and all the mutable state are split between the var and the home partition. This has the problem that the UUID of the var partition depends on the value of /etc/machine-id, so ideally there would be an etc partition (this currently does not exist as part of the Discoverable Partitions Specification) that is populated during installation and then made read-only by default (can be remounted to be read-write if needed)
  3. Splitting mutable state between the home partition and root(/var) partition has the problem that its very difficult to know how much space should be allocated to each. Once the space is allocated it is difficult to reallocate when more space is needed in one or the other, so ideally the home partition is axed and systemd-homed learns to manage home directories somewhere in /var/. This has the problem of nested encryption which isn't good performance wise, so it would be good to have some nice way of layering encryption without performance cost.

This would result in the following partition layout:

  1. EFI System Partition (managed by bootctl)
  2. XBOOTLDR Partition
  3. usr Partition (A) with label fooOS_0.1
  4. usr-verity Partition (A) with label fooOS_0.1
  5. usr-verity-sig Partition (A) with label fooOS_0.1
  6. usr Partition (B) with label _empty
  7. usr-verity Partition (B) with label _empty
  8. usr-verity-sig Partition (B) with label _empty
  9. etc Partition, encrypted and locked to TPM2
  10. var Partition, encrypted and locked to TPM2 (nested /home/ management by sd-homed)
  11. swap Partition, encrypted and locked to TPM2

/ would be a special tmpfs created during bootup, that is limited to creating symlinks and directories

An installation medium/the generated minimum image would have the following layout:

  1. EFI System Partition
  2. XBOOTLDR Partition
  3. usr Partition (A) with label fooOS_0.1
  4. usr-verity Partition (A) with label fooOS_0.1
  5. usr-verity-sig Partition (A) with label fooOS_0.1

/ would be a regular tmpfs created during bootup (probably determined by the existance of /etc/machine-id)

For an installation of this kinda system the following steps would be used ($DRIVE is the target to install on):

systemd-repart --defer-partitions=var --dry-run=false "$DRIVE"
systemd-firstboot --image="$DRIVE" --prompt --setup-machine-id
systemd-repart --dry-run=false "$DRIVE"
bootctl --image="$DRIVE" install

Maybe instead of setting up fully setting up a random machine-id, sd-firstboot initializes it to uninitialized and it mounts the etc partition during ConditionFirstBoot=true read-write, commits the generated id, then remounts it read-only. The var partition would then be identified as uninitialized by a UUID of 4d21b016-b534-45c2-a9fb-5c16e091fd2d and have its UUID changed to the value of HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d). Then the installation could be reduced to:

systemd-repart --dry-run=false "$DRIVE"
systemd-firstboot --image="$DRIVE" --machine-id=uninitialized # No --prompt to leave that to the actual first boot, with committing machine-id
bootctl --image="$DRIVE" install
@Gigadoc2
Copy link

Gigadoc2 commented Jul 5, 2024

I like this setup, it is basically what I want to have on my driver (and tried once, but mkosi was missing something at that time and so I ended up with a mutable installation once more). I am also waiting for a solution to layered encryption, and am still trying to figure out how to deal with (unprivileged) user-installable software, to retain flexibility and keep the /usr partitions minimal (seeing how they require 2x the space in the A/B system). Flatpak has this solved for graphical applications, but shell environments are more difficult.

About problem 2, the etc partition: Doesn't the root partition fulfill the same purpose? With both /usr and /var on different partitions (and the homes being sourced from /var), what would be left on root aside from /etc and a few empty directories for mount points? I always thought that this is the reason why we don't have etc in the Discoverable Partitions Spec in the first place.

@NekkoDroid
Copy link
Author

NekkoDroid commented Jul 5, 2024

About problem 2, the etc partition: Doesn't the root partition fulfill the same purpose?

I did often think if this would be the way to go, but I had mostly 2 reasons to not do that:

  1. You'd need to set up the root directory structure and symlinks. sd-repart can do directories in the config, but not so much symlinks (without copying it from somewhere). That is why I decided it would probably be better to just have a special tmpfs that is only used to create the root structure and can be used to mount other stuff within it. That way the needed directories are only created when needed, but don't contain any actual content within it. Maybe also just a normal tmpfs would also suffice, since /etc/ would be RO when it has a separate partition.
  2. If /etc/ should be RO and a new directory needs to be created at / (for example to serve as a new mount point) you'd need to either have the directory already exist or you need to remount the entire partition to be RW, which I'd prefer not to do.

and am still trying to figure out how to deal with (unprivileged) user-installable software, to retain flexibility and keep the /usr partitions minimal

systemd-sysext would be used in my case for global stuff (DE, podman, neovim, ...) and user specific stuff can always be installed in the home directory (as long as it's not suid stuff).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment