diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 26c218e90e..bd648d84b0 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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; } diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 97431bca67..2be4c34295 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -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);