]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: use blkid_probe filters to restrict probing to supported FSes and no raid
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 10 Sep 2025 17:13:37 +0000 (18:13 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 17 Sep 2025 12:46:24 +0000 (14:46 +0200)
We only support a subset of filesystems, and no RAID, for DDIs. blkid spends a lot
of time trying to probe for the filesystem type, so cut it short by using
the filtering options to restrict it to the filesystems we support, and to
exclude raid probing.

src/shared/dissect-image.c
src/shared/dissect-image.h

index 26c218e90e4d59a1d4ae7cf8e61ac7bf3a2be56f..bd648d84b0590d9255f22f63faff841330c5654a 100644 (file)
 /* how many times to wait for the device nodes to appear */
 #define N_DEVICE_NODE_LIST_ATTEMPTS 10
 
-int dissect_fstype_ok(const char *fstype) {
+static int allowed_fstypes(char ***ret_strv) {
+        _cleanup_strv_free_ char **l = NULL;
         const char *e;
-        bool b;
 
-        /* When we automatically mount file systems, be a bit conservative by default what we are willing to
-         * mount, just as an extra safety net to not mount with badly maintained legacy file system
-         * drivers. */
+        assert(ret_strv);
 
         e = secure_getenv("SYSTEMD_DISSECT_FILE_SYSTEMS");
         if (e) {
-                _cleanup_strv_free_ char **l = NULL;
-
                 l = strv_split(e, ":");
                 if (!l)
                         return -ENOMEM;
+        } else {
+                l = strv_new("btrfs",
+                             "erofs",
+                             "ext4",
+                             "f2fs",
+                             "squashfs",
+                             "vfat",
+                             "xfs");
+                if (!l)
+                        return -ENOMEM;
+        }
 
-                b = strv_contains(l, fstype);
-        } else
-                b = STR_IN_SET(fstype,
-                               "btrfs",
-                               "erofs",
-                               "ext4",
-                               "f2fs",
-                               "squashfs",
-                               "vfat",
-                               "xfs");
-        if (b)
+        *ret_strv = TAKE_PTR(l);
+
+        return 0;
+}
+
+int dissect_fstype_ok(const char *fstype) {
+        _cleanup_strv_free_ char **l = NULL;
+        int r;
+
+        /* When we automatically mount file systems, be a bit conservative by default what we are willing to
+         * mount, just as an extra safety net to not mount with badly maintained legacy file system
+         * drivers. */
+
+        r = allowed_fstypes(&l);
+        if (r < 0)
+                return r;
+
+        if (strv_contains(l, fstype))
                 return true;
 
         log_debug("File system type '%s' is not allowed to be mounted as result of automatic dissection.", fstype);
@@ -177,11 +191,37 @@ int probe_sector_size_prefer_ioctl(int fd, uint32_t *ret) {
         return probe_sector_size(fd, ret);
 }
 
+#if HAVE_BLKID
+static int probe_blkid_filter(blkid_probe p) {
+        _cleanup_strv_free_ char **fstypes = NULL;
+        int r;
+
+        assert(p);
+
+        r = allowed_fstypes(&fstypes);
+        if (r < 0)
+                return r;
+
+        errno = 0;
+        r = blkid_probe_filter_superblocks_type(p, BLKID_FLTR_ONLYIN, fstypes);
+        if (r != 0)
+                return errno_or_else(EINVAL);
+
+        errno = 0;
+        r = blkid_probe_filter_superblocks_usage(p, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
+        if (r != 0)
+                return errno_or_else(EINVAL);
+
+        return 0;
+}
+#endif
+
 int probe_filesystem_full(
                 int fd,
                 const char *path,
                 uint64_t offset,
                 uint64_t size,
+                bool restrict_fstypes,
                 char **ret_fstype) {
 
         /* Try to find device content type and return it in *ret_fstype. If nothing is found,
@@ -221,6 +261,12 @@ int probe_filesystem_full(
         if (!b)
                 return -ENOMEM;
 
+        if (restrict_fstypes) {
+                r = probe_blkid_filter(b);
+                if (r < 0)
+                        return r;
+        }
+
         /* The Linux kernel maintains separate block device caches for main ("whole") and partition block
          * devices, which means making a change to one might not be reflected immediately when reading via
          * the other. That's massively confusing when mixing accesses to such devices. Let's address this in
@@ -387,9 +433,9 @@ static int dissected_image_probe_filesystems(
                         /* If we have an fd referring to the partition block device, use that. Otherwise go
                          * via the whole block device or backing regular file, and read via offset. */
                         if (p->mount_node_fd >= 0)
-                                r = probe_filesystem_full(p->mount_node_fd, p->node, 0, UINT64_MAX, &p->fstype);
+                                r = probe_filesystem_full(p->mount_node_fd, p->node, 0, UINT64_MAX, /* bool restrict_fstypes= */ true, &p->fstype);
                         else
-                                r = probe_filesystem_full(fd, p->node, p->offset, p->size, &p->fstype);
+                                r = probe_filesystem_full(fd, p->node, p->offset, p->size, /* bool restrict_fstypes= */ true, &p->fstype);
                         if (r < 0)
                                 return r;
                 }
@@ -751,6 +797,10 @@ static int dissect_image(
         if (!b)
                 return -ENOMEM;
 
+        r = probe_blkid_filter(b);
+        if (r < 0)
+                return r;
+
         errno = 0;
         r = blkid_probe_set_device(b, fd, 0, 0);
         if (r != 0)
@@ -3053,7 +3103,7 @@ int dissected_image_decrypt(
                 }
 
                 if (!p->decrypted_fstype && p->mount_node_fd >= 0 && p->decrypted_node) {
-                        r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, &p->decrypted_fstype);
+                        r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, /* bool restrict_fstypes= */ true, &p->decrypted_fstype);
                         if (r < 0 && r != -EUCLEAN)
                                 return r;
                 }
index 97431bca673bdbe970bb2338edbd6e0f526a0afb..2be4c3429538e468a8bec69cfccea2ac8d484db7 100644 (file)
@@ -156,9 +156,9 @@ MountOptions* mount_options_free_all(MountOptions *options);
 DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
 const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
 
-int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, char **ret_fstype);
+int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, bool restrict_fstypes, char **ret_fstype);
 static inline int probe_filesystem(const char *path, char **ret_fstype) {
-        return probe_filesystem_full(-1, path, 0, UINT64_MAX, ret_fstype);
+        return probe_filesystem_full(-1, path, 0, UINT64_MAX, /* bool restrict_fstypes= */ false, ret_fstype);
 }
 
 int dissect_log_error(int log_level, int r, const char *name, const VeritySettings *verity);