dissect: use blkid_probe filters to restrict probing to supported FSes and no raid

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.
This commit is contained in:
Luca Boccassi
2025-09-10 18:13:37 +01:00
committed by Zbigniew Jędrzejewski-Szmek
parent 413a1c51c4
commit 72bf86663c
2 changed files with 75 additions and 25 deletions

View File

@@ -74,33 +74,47 @@
/* 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;
assert(ret_strv);
e = secure_getenv("SYSTEMD_DISSECT_FILE_SYSTEMS");
if (e) {
l = strv_split(e, ":");
if (!l)
return -ENOMEM;
} else {
l = strv_new("btrfs",
"erofs",
"ext4",
"f2fs",
"squashfs",
"vfat",
"xfs");
if (!l)
return -ENOMEM;
}
*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. */
e = secure_getenv("SYSTEMD_DISSECT_FILE_SYSTEMS");
if (e) {
_cleanup_strv_free_ char **l = NULL;
r = allowed_fstypes(&l);
if (r < 0)
return r;
l = strv_split(e, ":");
if (!l)
return -ENOMEM;
b = strv_contains(l, fstype);
} else
b = STR_IN_SET(fstype,
"btrfs",
"erofs",
"ext4",
"f2fs",
"squashfs",
"vfat",
"xfs");
if (b)
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;
}

View 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);