diff --git a/src/shared/image-policy.c b/src/shared/image-policy.c index 1fb24138fb..e08fbba966 100644 --- a/src/shared/image-policy.c +++ b/src/shared/image-policy.c @@ -774,6 +774,56 @@ int image_policy_intersect(const ImagePolicy *a, const ImagePolicy *b, ImagePoli return 0; } +int image_policy_ignore_designators(const ImagePolicy *p, const PartitionDesignator table[], size_t n_table, ImagePolicy **ret) { + assert(p); + assert(table || n_table == 0); + assert(ret); + + /* Patches the specified image policy, replacing the policy for the specified designators by an + * "ignore" policy. Returns a patched copy. This is useful in context where only some of the + * available partitions shall be mounted, and hence the policy for the others really doesn't + * matter. */ + + _cleanup_(image_policy_freep) ImagePolicy *np = image_policy_new(_PARTITION_DESIGNATOR_MAX); + if (!np) + return -ENOMEM; + + FOREACH_ARRAY(t, table, n_table) { + assert(*t >= 0); + assert(*t < _PARTITION_DESIGNATOR_MAX); + + if (image_policy_bsearch(np, *t)) + continue; + + /* Insert an ignore policy for this entry, and sort it to the right place, so that image_policy_bsearch() can work */ + np->policies[np->n_policies++] = (PartitionPolicy) { + .designator = *t, + .flags = PARTITION_POLICY_IGNORE, + }; + typesafe_qsort(np->policies, np->n_policies, partition_policy_compare); + } + + FOREACH_ARRAY(i, p->policies, p->n_policies) { + + if (image_policy_bsearch(np, i->designator)) + continue; + + /* Copy the policy entry from the old image policy, and sort it to the right place, so that image_policy_bsearch() can work */ + np->policies[np->n_policies++] = *i; + typesafe_qsort(np->policies, np->n_policies, partition_policy_compare); + } + + np->default_flags = p->default_flags; + + /* Return unused space to libc */ + ImagePolicy *t = realloc(np, offsetof(ImagePolicy, policies) + sizeof(PartitionPolicy) * np->n_policies); + if (t) + np = t; + + *ret = TAKE_PTR(np); + return 0; +} + const ImagePolicy image_policy_allow = { /* Allow policy */ .n_policies = 0, diff --git a/src/shared/image-policy.h b/src/shared/image-policy.h index a1a6afa345..f61f55fd60 100644 --- a/src/shared/image-policy.h +++ b/src/shared/image-policy.h @@ -106,3 +106,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(ImagePolicy*, image_policy_free); CONFIG_PARSER_PROTOTYPE(config_parse_image_policy); int parse_image_policy_argument(const char *s, ImagePolicy **policy); + +int image_policy_ignore_designators(const ImagePolicy *p, const PartitionDesignator table[], size_t n_table, ImagePolicy **ret); diff --git a/src/test/test-image-policy.c b/src/test/test-image-policy.c index 12fc10acf0..7d29e3d12e 100644 --- a/src/test/test-image-policy.c +++ b/src/test/test-image-policy.c @@ -162,4 +162,31 @@ TEST(image_policy_intersect) { test_policy_intersect_one("root=open", "=verity+ignore", "root=verity+ignore:=ignore"); } +static void test_policy_ignore_designators_one(const char *a, const PartitionDesignator array[], size_t n, const char *b) { + _cleanup_(image_policy_freep) ImagePolicy *x = NULL, *y = NULL, *t = NULL; + + ASSERT_OK(image_policy_from_string(a, &x)); + ASSERT_OK(image_policy_from_string(b, &y)); + + _cleanup_free_ char *s1 = NULL, *s2 = NULL, *s3 = NULL; + ASSERT_OK(image_policy_to_string(x, true, &s1)); + ASSERT_OK(image_policy_to_string(y, true, &s2)); + + ASSERT_OK(image_policy_ignore_designators(x, array, n, &t)); + + ASSERT_OK(image_policy_to_string(t, true, &s3)); + + log_info("%s → %s vs. %s", s1, s2, s3); + + ASSERT_TRUE(image_policy_equivalent(t, y)); +} + +TEST(image_policy_ignore_designators) { + test_policy_ignore_designators_one("-", NULL, 0, "-"); + test_policy_ignore_designators_one("-", ((const PartitionDesignator[]) { PARTITION_ROOT }), 1, "-"); + test_policy_ignore_designators_one("*", ((const PartitionDesignator[]) { PARTITION_ROOT }), 1, "root=ignore:=open"); + test_policy_ignore_designators_one("*", ((const PartitionDesignator[]) { PARTITION_ROOT, PARTITION_USR }), 2, "root=ignore:usr=ignore:=open"); + test_policy_ignore_designators_one("~", ((const PartitionDesignator[]) { PARTITION_VAR, PARTITION_ESP, PARTITION_VAR }), 2, "var=ignore:esp=ignore:=absent"); +} + DEFINE_TEST_MAIN(LOG_INFO);