]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect-image: when autoprobing insist on vfat for XBOOTLDR
authorLennart Poettering <lennart@poettering.net>
Thu, 9 Oct 2025 09:01:48 +0000 (11:01 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 15 Oct 2025 06:32:37 +0000 (08:32 +0200)
Let's reduce our attack surface by insisting that XBOOTLDR is vfat when
auto-probing, just like we do for the ESP. Given neither can
realistically be integrity protected (because firmware needs to access
them) let's insist on a vfat which has a much smaller attack surface,
and one we have to accept (for now) anyway, given that the ESP must be
VFAT.

This only applies to auto-probing of course. If people mount things
explicitly via fstab none of this matters. But we really shouldn't
automount a btrfs/xfs/ext4 partition as XBOOTLDR just because it looks
like one, as that would really defeat our otherwise possibly very strict
image policies.

This also introduces a new env var $SYSTEMD_DISSECT_FSTYPE_<DESIGNATOR>
environment variable that may override this hardcoding. This is in
particular useful in our testcases, since various actually do use ext4
as XBOOTLDR case. The tests are updated to make use of the new env var,
both as a mechanism to test this and to keep the tests working.

docs/ENVIRONMENT.md
src/shared/dissect-image.c
test/units/TEST-87-AUX-UTILS-VM.bootctl.sh

index 3a35c1b9aa0f5bdb5833cc3ef48c66d9ef067d5d..6eda26c7d684e168177bdab4224e43ee3b2de80a 100644 (file)
@@ -529,6 +529,15 @@ disk images with `--image=` or similar:
   systems that may be mounted for automatically dissected disk images. If not
   specified defaults to something like: `ext4:btrfs:xfs:vfat:erofs:squashfs`
 
+* `$SYSTEMD_DISSECT_FSTYPE_<DESIGNATOR>=` – overrides the file system time to
+  use when mounting the partition of the indicated designator. The
+  `<DESIGNATOR>` string shall be one of `ROOT`, `USR`, `HOME`, `SRV`, `ESP`,
+  `XBOOTLDR`, `TMP`, `VAR` as per the [Discoverable Partitions
+  Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/). If
+  unspecified the image dissection logic will automatically probe the file
+  system type (subject to `$SYSTEMD_DISSECT_FILE_SYSTEMS`, see above), except
+  for ESP and XBOOTLDR where the file system type is set to VFAT.
+
 * `$SYSTEMD_LOOP_DIRECT_IO` – takes a boolean, which controls whether to enable
   `LO_FLAGS_DIRECT_IO` (i.e. direct IO + asynchronous IO) on loopback block
   devices when opening them. Defaults to on, set this to "0" to disable this
index e44c307bbf1f4fef9df9d852d81eba077d7e9f53..4cb84116faeb161043f6b283ece2211e4192f25c 100644 (file)
@@ -117,6 +117,17 @@ int dissect_fstype_ok(const char *fstype) {
         return false;
 }
 
+static const char *getenv_fstype(PartitionDesignator d) {
+
+        if (d < 0 ||
+            partition_designator_is_verity(d) ||
+            d == PARTITION_SWAP)
+                return NULL;
+
+        char *v = strjoina("SYSTEMD_DISSECT_FSTYPE_", partition_designator_to_string(d));
+        return secure_getenv(ascii_strupper(v));
+}
+
 int probe_sector_size(int fd, uint32_t *ret) {
 
         /* Disk images might be for 512B or for 4096 sector sizes, let's try to auto-detect that by searching
@@ -1032,7 +1043,7 @@ static int dissect_image(
                 }
 
                 if (is_gpt) {
-                        const char *fstype = NULL, *label;
+                        const char *label;
                         sd_id128_t type_id, id;
                         GptPartitionType type;
                         bool rw = true, growfs = false;
@@ -1085,6 +1096,8 @@ static int dissect_image(
                                 continue;
                         }
 
+                        const char *fstype = getenv_fstype(type.designator);
+
                         if (IN_SET(type.designator,
                                    PARTITION_HOME,
                                    PARTITION_SRV,
@@ -1097,6 +1110,11 @@ static int dissect_image(
                                 rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
                                 growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
 
+                                /* XBOOTLDR cannot be integrity protected (since firmware needs to access
+                                 * it), hence be restrictive with the fs choice when dissecting. */
+                                if (type.designator == PARTITION_XBOOTLDR && !fstype)
+                                        fstype = "vfat";
+
                         } else if (type.designator == PARTITION_ESP) {
 
                                 if (FLAGS_SET(pflags, SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL)) {
@@ -1104,7 +1122,9 @@ static int dissect_image(
                                         continue;
                                 }
 
-                                fstype = "vfat";
+                                /* Effectively the ESP has to be VFAT, let's enforce this */
+                                if (!fstype)
+                                        fstype = "vfat";
 
                         } else if (type.designator == PARTITION_ROOT) {
 
index c6b4ea06552eddc262f017bf51b9ac3c2b431ecc..c8e3da09cf664bf7ab1f8e26693d0e6569b0055b 100755 (executable)
@@ -158,6 +158,8 @@ EOF
 
     umount "${IMAGE_DIR}/root"
 
+    export SYSTEMD_DISSECT_FSTYPE_XBOOTLDR=ext4
+
     assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-esp-path)" "/run/systemd/mount-rootfs/efi"
     assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-esp-path --esp-path=/efi)" "/run/systemd/mount-rootfs/efi"
     assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-boot-path)" "/run/systemd/mount-rootfs/boot"
@@ -167,6 +169,8 @@ EOF
     bootctl --image "${IMAGE_DIR}/image" --print-root-device || :
 
     basic_tests --image "${IMAGE_DIR}/image"
+
+    unset SYSTEMD_DISSECT_FSTYPE_XBOOTLDR
 }
 
 cleanup_raid() (