mount_entry_path(m),
m->image_options_const,
image_policy,
+ /* image_filter= */ NULL,
host_os_release_id,
host_os_release_version_id,
host_os_release_sysext_level,
p->verity,
p->root_image_options,
p->root_image_policy,
+ /* image_filter= */ NULL,
dissect_image_flags,
&dissected_image);
if (r < 0)
r = dissect_image_file_and_warn(
arg_image,
&arg_verity_settings,
- NULL,
+ /* mount_options= */ NULL,
arg_image_policy,
+ /* image_filter= */ NULL,
arg_flags,
- NULL);
+ /* ret= */ NULL);
if (r < 0)
return r;
&arg_verity_settings,
/* mount_options= */ NULL,
arg_image_policy,
+ /* image_filter= */ NULL,
arg_flags,
&m);
if (r < 0)
/* verity= */ NULL,
/* mount_options= */ NULL,
image_policy,
+ /* image_filter= */ NULL,
DISSECT_IMAGE_GPT_ONLY|
DISSECT_IMAGE_USR_NO_ROOT|
DISSECT_IMAGE_DISKSEQ_DEVNODE|
&verity,
/* mount_options= */ NULL,
use_policy,
+ /* image_filter= */ NULL,
dissect_flags,
&di);
if (r == -ENOPKG)
r = dissect_loop_device_and_warn(
loop,
&arg_verity_settings,
- /* mount_options=*/ NULL,
+ /* mount_options= */ NULL,
arg_image_policy ?: &image_policy_container,
+ /* image_filter= */ NULL,
dissect_image_flags,
&dissected_image);
if (r == -ENOPKG) {
/* verity= */ NULL,
/* mount_options= */ NULL,
image_policy,
+ /* image_filter= */ NULL,
flags,
&m);
if (r == -ENOPKG)
/* verity= */ NULL,
/* mount_options= */ NULL,
image_policy,
+ /* image_filter= */ NULL,
flags,
&m);
if (r < 0)
return 0;
}
+static bool image_filter_test(const ImageFilter *filter, PartitionDesignator d, const char *name) {
+ assert(d < _PARTITION_DESIGNATOR_MAX);
+
+ if (d < 0) /* For unspecified designators we have no filter expression */
+ return true;
+
+ if (!filter || !filter->pattern[d])
+ return true;
+
+ return fnmatch(filter->pattern[d], strempty(name), FNM_NOESCAPE) == 0;
+}
+
static int dissect_image(
DissectedImage *m,
int fd,
const VeritySettings *verity,
const MountOptions *mount_options,
const ImagePolicy *policy,
+ const ImageFilter *filter,
DissectImageFlags flags) {
sd_id128_t root_uuid = SD_ID128_NULL, root_verity_uuid = SD_ID128_NULL;
/* OK, we have found a file system, that's our root partition then. */
+ if (!image_filter_test(filter, PARTITION_ROOT, /* label= */ NULL)) /* do a filter check with an empty partition label */
+ return -ECOMM;
+
r = image_policy_may_use(policy, PARTITION_ROOT);
if (r < 0)
return r;
if (streq_ptr(label, "_empty"))
continue;
+ if (!image_filter_test(filter, type.designator, label))
+ continue;
+
log_debug("Dissecting %s partition with label %s and UUID %s",
strna(partition_designator_to_string(type.designator)), strna(label), SD_ID128_TO_UUID_STRING(id));
/* We don't have a designator for SD_GPT_LINUX_GENERIC so check the UUID instead. */
} else if (sd_id128_equal(type.uuid, SD_GPT_LINUX_GENERIC)) {
+ if (!image_filter_test(filter, PARTITION_ROOT, label))
+ continue;
+
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags != 0x80) /* Bootable flag */
continue;
+ if (!image_filter_test(filter, PARTITION_ROOT, /* label= */ NULL))
+ continue;
+
if (generic_node)
multiple_generic = true;
else {
sd_id128_t id = SD_ID128_NULL;
const char *options = NULL;
+ if (!image_filter_test(filter, PARTITION_XBOOTLDR, /* label= */ NULL))
+ continue;
+
r = image_policy_may_use(policy, PARTITION_XBOOTLDR);
if (r < 0)
return r;
const VeritySettings *verity,
const MountOptions *mount_options,
const ImagePolicy *image_policy,
+ const ImageFilter *image_filter,
DissectImageFlags flags,
DissectedImage **ret) {
if (r < 0)
return r;
- r = dissect_image(m, fd, path, verity, mount_options, image_policy, flags);
+ r = dissect_image(m, fd, path, verity, mount_options, image_policy, image_filter, flags);
if (r < 0)
return r;
const VeritySettings *verity,
const MountOptions *mount_options,
const ImagePolicy *image_policy,
+ const ImageFilter *image_filter,
DissectImageFlags flags,
DissectedImage **ret) {
return dissect_log_error(
LOG_ERR,
- dissect_image_file(path, verity, mount_options, image_policy, flags, ret),
+ dissect_image_file(path, verity, mount_options, image_policy, image_filter, flags, ret),
path,
verity);
}
return 0;
}
+void image_filter_done(ImageFilter *f) {
+ assert(f);
+
+ FOREACH_ELEMENT(p, f->pattern)
+ *p = mfree(*p);
+}
+
+ImageFilter *image_filter_free(ImageFilter *f) {
+ if (!f)
+ return NULL;
+
+ image_filter_done(f);
+ return mfree(f);
+}
+
+int image_filter_parse(const char *s, ImageFilter **ret) {
+ _cleanup_(image_filter_freep) ImageFilter *f = NULL;
+ int r;
+
+ if (isempty(s)) {
+ if (ret)
+ *ret = NULL;
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&s, &word, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to extract word: %m");
+ if (r == 0)
+ break;
+
+ _cleanup_free_ char *designator = NULL, *pattern = NULL;
+ const char *x = word;
+ r = extract_many_words(&x, "=", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &designator, &pattern);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to extract designator: %m");
+ if (r != 2 || !isempty(x))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to split: %m");
+
+ PartitionDesignator d = partition_designator_from_string(designator);
+ if (d < 0)
+ return log_debug_errno(d, "Failed to parse partition designator: %s", designator);
+
+ if (!f) {
+ f = new0(ImageFilter, 1);
+ if (!f)
+ return log_oom_debug();
+ } else if (f->pattern[d])
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate pattern for '%s', refusing.", partition_designator_to_string(d));
+
+ f->pattern[d] = TAKE_PTR(pattern);
+ }
+
+ if (ret)
+ *ret = TAKE_PTR(f);
+
+ return 0;
+}
+
static char *build_auxiliary_path(const char *image, const char *suffix) {
const char *e;
char *n;
const VeritySettings *verity,
const MountOptions *mount_options,
const ImagePolicy *image_policy,
+ const ImageFilter *image_filter,
DissectImageFlags flags,
DissectedImage **ret) {
m->image_size = m->loop->device_size;
m->sector_size = m->loop->sector_size;
- r = dissect_image(m, loop->fd, loop->node, verity, mount_options, image_policy, flags);
+ r = dissect_image(
+ m,
+ loop->fd,
+ loop->node,
+ verity,
+ mount_options,
+ image_policy,
+ image_filter,
+ flags);
if (r < 0)
return r;
const VeritySettings *verity,
const MountOptions *mount_options,
const ImagePolicy *image_policy,
+ const ImageFilter *image_filter,
DissectImageFlags flags,
DissectedImage **ret) {
return dissect_log_error(
LOG_ERR,
- dissect_loop_device(loop, verity, mount_options, image_policy, flags, ret),
+ dissect_loop_device(loop, verity, mount_options, image_policy, image_filter, flags, ret),
loop->backing_file ?: loop->node,
verity);
}
&verity,
/* mount_options= */ NULL,
image_policy,
+ /* image_filter= */ NULL,
flags,
&dissected_image);
if (r < 0)
const char *dest,
const MountOptions *options,
const ImagePolicy *image_policy,
+ const ImageFilter *image_filter,
const char *required_host_os_release_id,
const char *required_host_os_release_version_id,
const char *required_host_os_release_sysext_level,
verity,
options,
image_policy,
+ image_filter,
dissect_image_flags,
&dissected_image);
/* No partition table? Might be a single-filesystem image, try again */
verity,
options,
image_policy,
+ image_filter,
dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE,
&dissected_image);
if (r < 0)
typedef struct DecryptedImage DecryptedImage;
typedef struct MountOptions MountOptions;
typedef struct VeritySettings VeritySettings;
+typedef struct ImageFilter ImageFilter;
struct DissectedPartition {
bool found:1;
.designator = _PARTITION_DESIGNATOR_INVALID \
}
+struct ImageFilter {
+ /* A per designator glob matching against the partition label */
+ char *pattern[_PARTITION_DESIGNATOR_MAX];
+};
+
/* We include image-policy.h down here, since ImagePolicy wants a complete definition of PartitionDesignator first. */
#include "image-policy.h"
}
int dissect_log_error(int log_level, int r, const char *name, const VeritySettings *verity);
-int dissect_image_file(const char *path, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret);
-int dissect_image_file_and_warn(const char *path, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret);
-int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret);
-int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image_file(const char *path, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, const ImageFilter *filter, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image_file_and_warn(const char *path, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, const ImageFilter *filter, DissectImageFlags flags, DissectedImage **ret);
+int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, const ImageFilter *filter, DissectImageFlags flags, DissectedImage **ret);
+int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, const ImagePolicy *image_policy, const ImageFilter *filter, DissectImageFlags flags, DissectedImage **ret);
void dissected_image_close(DissectedImage *m);
DissectedImage* dissected_image_unref(DissectedImage *m);
int dissected_image_relinquish(DissectedImage *m);
+void image_filter_done(ImageFilter *f);
+ImageFilter *image_filter_free(ImageFilter *f);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ImageFilter*, image_filter_free);
+int image_filter_parse(const char *s, ImageFilter **ret);
+
int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
static inline bool verity_settings_set(const VeritySettings *settings) {
int mount_image_privately_interactively(const char *path, const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device);
-int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_host_os_release_confext_level, const char *required_sysext_scope, VeritySettings *verity, DissectedImage **ret_image);
+int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const ImageFilter *image_filter, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_host_os_release_confext_level, const char *required_sysext_scope, VeritySettings *verity, DissectedImage **ret_image);
int dissect_fstype_ok(const char *fstype);
mount_tmp,
options,
image_policy,
+ /* image_filter= */ NULL,
/* required_host_os_release_id= */ NULL,
/* required_host_os_release_version_id= */ NULL,
/* required_host_os_release_sysext_level= */ NULL,
/* dest= */ NULL,
options,
image_policy,
+ /* image_filter= */ NULL,
/* required_host_os_release_id= */ NULL,
/* required_host_os_release_version_id= */ NULL,
/* required_host_os_release_sysext_level= */ NULL,
&verity_settings,
/* mount_options= */ NULL,
pick_image_policy(img),
+ /* image_filter= */ NULL,
flags,
&m);
if (r < 0)
'test-hostname-setup.c',
'test-hostname-util.c',
'test-id128.c',
+ 'test-image-filter.c',
'test-image-policy.c',
'test-import-util.c',
'test-in-addr-prefix-util.c',
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "dissect-image.h"
+#include "tests.h"
+
+TEST(image_filter) {
+ _cleanup_(image_filter_freep) ImageFilter *f = NULL;
+
+ ASSERT_OK(image_filter_parse(NULL, &f));
+ ASSERT_NULL(f);
+ ASSERT_OK(image_filter_parse("", &f));
+ ASSERT_NULL(f);
+
+ ASSERT_OK(image_filter_parse("root=*", &f));
+ ASSERT_NOT_NULL(f);
+ ASSERT_STREQ(f->pattern[PARTITION_ROOT], "*");
+ f = image_filter_free(f);
+
+ ASSERT_OK(image_filter_parse("usr=foox?:root=kn*arz", &f));
+ ASSERT_NOT_NULL(f);
+ ASSERT_STREQ(f->pattern[PARTITION_ROOT], "kn*arz");
+ ASSERT_STREQ(f->pattern[PARTITION_USR], "foox?");
+ f = image_filter_free(f);
+
+ ASSERT_OK(image_filter_parse("usr=foox?:root=kn*arz:home=wumpi", &f));
+ ASSERT_NOT_NULL(f);
+ ASSERT_STREQ(f->pattern[PARTITION_ROOT], "kn*arz");
+ ASSERT_STREQ(f->pattern[PARTITION_USR], "foox?");
+ ASSERT_STREQ(f->pattern[PARTITION_HOME], "wumpi");
+ f = image_filter_free(f);
+
+ ASSERT_ERROR(image_filter_parse("usr=foox?:root=kn*arz:home=wumpi:schlumpf=smurf", &f), EINVAL);
+ ASSERT_ERROR(image_filter_parse(":", &f), EINVAL);
+ ASSERT_ERROR(image_filter_parse("::", &f), EINVAL);
+ ASSERT_ERROR(image_filter_parse("-", &f), EINVAL);
+ ASSERT_ERROR(image_filter_parse("root=knuff:root=knuff", &f), EINVAL);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted);
- r = dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected);
+ r = dissect_loop_device(
+ loop,
+ /* verity= */ NULL,
+ /* mount_options= */ NULL,
+ /* image_policy= */ NULL,
+ /* image_filter= */ NULL,
+ DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES,
+ &dissected);
if (r < 0)
log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node);
assert_se(r >= 0);
sfdisk = NULL;
#if HAVE_BLKID
- assert_se(dissect_image_file(p, NULL, NULL, NULL, 0, &dissected) >= 0);
+ assert_se(dissect_image_file(
+ p,
+ /* verity= */ NULL,
+ /* mount_options= */ NULL,
+ /* image_policy= */ NULL,
+ /* image_filter= */ NULL,
+ /* flags= */ 0,
+ &dissected) >= 0);
verify_dissected_image(dissected);
dissected = dissected_image_unref(dissected);
#endif
assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_EX, &loop) >= 0);
#if HAVE_BLKID
- assert_se(dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0);
+ assert_se(dissect_loop_device(
+ loop,
+ /* verity= */ NULL,
+ /* mount_options= */ NULL,
+ /* image_policy= */ NULL,
+ /* image_filter= */ NULL,
+ DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES,
+ &dissected) >= 0);
verify_dissected_image(dissected);
FOREACH_STRING(fs, "vfat", "ext4") {
/* Try to read once, without pinning or adding partitions, i.e. by only accessing the whole block
* device. */
- assert_se(dissect_loop_device(loop, NULL, NULL, NULL, 0, &dissected) >= 0);
+ assert_se(dissect_loop_device(
+ loop,
+ /* verity= */ NULL,
+ /* mount_options= */ NULL,
+ /* image_policy= */ NULL,
+ /* image_filter= */ NULL,
+ /* flags= */ 0,
+ &dissected) >= 0);
verify_dissected_image_harder(dissected);
dissected = dissected_image_unref(dissected);
/* Now go via the loopback device after all, but this time add/pin, because now we want to mount it. */
- assert_se(dissect_loop_device(loop, NULL, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0);
+ assert_se(dissect_loop_device(
+ loop,
+ /* verity= */ NULL,
+ /* mount_options= */ NULL,
+ /* image_policy= */ NULL,
+ /* image_filter= */ NULL,
+ DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES,
+ &dissected) >= 0);
verify_dissected_image_harder(dissected);
assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
&arg_verity_settings,
/* mount_options= */ NULL,
image_policy,
+ /* image_filter= */ NULL,
DISSECT_IMAGE_READ_ONLY|
DISSECT_IMAGE_GPT_ONLY|
DISSECT_IMAGE_USR_NO_ROOT|
&arg_verity_settings,
/* mount_options= */ NULL,
image_policy_mangled,
+ /* image_filter= */ NULL,
DISSECT_IMAGE_READ_ONLY|
DISSECT_IMAGE_GPT_ONLY|
DISSECT_IMAGE_USR_NO_ROOT|
/* verity= */ NULL,
/* mount_options= */ NULL,
/* image_policy= */ NULL,
+ /* image_filter= */ NULL,
/* flags= */ 0,
&image);
if (r < 0)