Skip to content

Discoverable partition UUIDs misused #1771

@gucci-on-fleek

Description

@gucci-on-fleek

There are (at least) 3 different types of UUIDs for Linux filesystems/partitions:

  1. The filesystem UUID. This is intrinsic to the filesystem, so it can exist with both MBR and GPT, and its format depends on the specific filesystem (8 hex chars on FAT, a GUID for most other filesystems). You can mount a disk by its filesystem UUID by running mount UUID=<uuid>, and you can display a filesystem's UUID by running lsblk --output=name,fstype,uuid. Theoretically, no 2 disks should ever have the same filesystem UUIDs.

  2. The partition UUID. This is a part of GPT, so it has the same format for every filesystem, but it doesn't work with MBR. You can mount a disk by its partition UUID by running mount PARTUUID=<uuid>, and you can display a partitions's UUID by running lsblk --output=name,fstype,partuuid. Theoretically, no 2 disks should ever have the same partition UUIDs.

  3. The partition type UUID. This is a part of GPT, so it has the same format for every filesystem, but it doesn't work with MBR. You can mount a disk by its partition type UUID with systemd-gpt-auto-generator, and you can display a partitions's type UUID by running lsblk --output=name,fstype,parttype (or …,parttypename for its friendly name). Many disks will have the same partition type UUIDs, and common values are defined by the Discoverable Partitions Specification.

Right now, bootc is setting the filesystem UUIDs to one of the values defined by the DPS:

Cmdline::from(format!(
"root=UUID={} {RW_KARG} {COMPOSEFS_CMDLINE}={id_hex}",
this_arch_root()
)),

let u = uuid::Uuid::parse_str(crate::discoverable_partition_specification::this_arch_root())?;
let mut t = Task::new(
&format!("Creating {label} filesystem ({fs}) on device {dev} (size={size})"),
format!("mkfs.{fs}"),
);
match fs {
Filesystem::Xfs => {
if wipe {
t.cmd.arg("-f");
}
t.cmd.arg("-m");
t.cmd.arg(format!("uuid={u}"));
}
Filesystem::Btrfs | Filesystem::Ext4 => {
t.cmd.arg("-U");
t.cmd.arg(u.to_string());
}
};

This is bad because

  1. This isn't actually following the DPS, so tools like systemd-gpt-auto-generator won't recognize this.

  2. Some software assumes that filesystem/partition UUIDs are truly unique, so bad things will happen if you try to mount 2 disks formatted this way at the same time.

Here's an example of the disk generated by bootc install to-disk (using v1.10):

$ lsblk --output=name,fstype,parttypename,uuid,partuuid,parttype
NAME        FSTYPE PARTTYPENAME     UUID                                 PARTUUID                             PARTTYPE
loop0                                                                                                         
├─loop0p1          BIOS boot                                             6188eeaa-d52e-4c89-b077-6373578a8146 21686148-6449-6e6f-744e-656564454649
├─loop0p2   vfat   EFI System       5081-C36B                            d30abf07-204f-40a0-9d25-62f089c73137 c12a7328-f81f-11d2-ba4b-00a0c93ec93b
└─loop0p3   btrfs  Linux filesystem 4f68bce3-e8cd-4db1-96e7-fbcaf984b709 834f3c93-e330-443c-97fc-4c0238e90a81 0fc63daf-8483-4772-8e79-3d69d8477de4

(Note how the filesystem and partition UUIDs for loop0p2 are random, but the partition type UUID is set to c12a7328-…, so the partition type name shows up as EFI System.)

Here's an example from my server running bootc, where I manually corrected the partition types with sfdisk --part-type:

$ lsblk --output=name,fstype,parttypename,uuid,partuuid,parttype | cat
NAME   FSTYPE PARTTYPENAME        UUID                                 PARTUUID                             PARTTYPE                                   
vda                                                                                                         
├─vda1 vfat   EFI System          312A-0AD0                            1c8b0885-9a88-4bb8-a494-22f27c793b3c c12a7328-f81f-11d2-ba4b-00a0c93ec93b
├─vda2 ext4   Linux extended boot 26d65031-c51b-4e2c-999f-9642f90ebcab b692ac66-0966-4811-a186-885208933efd bc13c2ff-59e6-4262-a352-b275fd6f7172
├─vda3 swap   Linux swap          25c85fb7-eadd-414c-9c56-475bf2a401f4 6f6482e5-128f-4347-a428-d557940a92a1 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
└─vda4 btrfs  Linux root (x86-64) 54b902ba-941a-495f-ae19-770ee22681c4 3b5f07c0-7a5d-4025-9bfe-b89e28974fdd 4f68bce3-e8cd-4db1-96e7-fbcaf984b709

(Note how the filesystem and partition UUIDs for vda4 are random, but the partition type UUID is set to 4f68bce3-…, so the partition type name shows up as Linux root (x86-64). Whereas in the previous example with the filesystem UUID set to 4f68bce3-…, the partition type name only shows up as Linux filesystem)

A nice side effect of this is that you no longer need to pass a long architecture-dependent UUID in the kernel cmdline; instead, you can just use root=gpt-auto, and systemd will automatically find the correct partition. I've done exactly this on my server running bootc, and everything works as expected.

The only catch is that older versions of Grub don't set the required UEFI variables, so you'll need to make sure to run bootupctl update first. And this also won't work on MBR-based systems (since the partition type is only defined in GPT), so if you need to support MBR-based systems, I'd recommend using the filesystem label (mount LABEL=<label>) instead of trying to reuse filesystem UUIDs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions