dissect: relate verity partitions

When using `systemd.image_filter=usr=250` a `/usr` was selected based on
its label but the corresponding verity partitions were *not* selected
based on their (potential labels).

This leads to mismatched verity partitions and `dm-verity` failure when
using `image_filter` without also explicitly passing matching
`usr-verity` and `usr-verity-sig`.

Signed-off-by: Simon de Vlieger <cmdr@supakeen.com>
(cherry picked from commit b5326670faac3064bcfa01ae3c1d57565d387bfb)
This commit is contained in:
Simon de Vlieger
2026-10-16 11:36:32 +01:00
committed by Luca Boccassi
parent b07c5a0639
commit d5c945bddb
3 changed files with 110 additions and 3 deletions
+18 -3
View File
@@ -966,16 +966,31 @@ static int compare_arch(Architecture a, Architecture b) {
return 0;
}
static bool image_filter_test(const ImageFilter *filter, PartitionDesignator d, const char *label) {
bool image_filter_test(const ImageFilter *filter, PartitionDesignator d, const char *label) {
assert(d < _PARTITION_DESIGNATOR_MAX);
if (d < 0) /* For unspecified designators we have no filter expression */
return true;
if (!filter || !filter->pattern[d])
if (!filter)
return true;
return fnmatch(filter->pattern[d], strempty(label), FNM_NOESCAPE) == 0;
const char *pattern = filter->pattern[d];
/* If there's no filter for this specific designator but it's a verity partition, fall back to the
* filter for the corresponding data partition. This ensures that e.g. image_filter=usr=250 also
* constrains which usr verity (and verity sig) partitions are selected. This assumes verity
* partitions carry the same label as their corresponding data partition. */
if (!pattern) {
PartitionDesignator data = partition_verity_to_data(d);
if (data >= 0)
pattern = filter->pattern[data];
}
if (!pattern)
return true;
return fnmatch(pattern, strempty(label), FNM_NOESCAPE) == 0;
}
static int dissect_image_from_unpartitioned(
+1
View File
@@ -203,6 +203,7 @@ 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);
bool image_filter_test(const ImageFilter *filter, PartitionDesignator d, const char *label);
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);
+91
View File
@@ -36,4 +36,95 @@ TEST(image_filter) {
ASSERT_ERROR(image_filter_parse("root=knuff:root=knuff", &f), EINVAL);
}
#if HAVE_BLKID
TEST(image_filter_test_basic) {
_cleanup_(image_filter_freep) ImageFilter *f = NULL;
/* NULL filter matches everything */
ASSERT_TRUE(image_filter_test(NULL, PARTITION_ROOT, "foo"));
ASSERT_TRUE(image_filter_test(NULL, PARTITION_USR, "bar"));
ASSERT_TRUE(image_filter_test(NULL, PARTITION_USR_VERITY, "baz"));
/* Filter on usr matches the right label */
ASSERT_OK(image_filter_parse("usr=250", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR, "251"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR, ""));
/* Unfiltered designators pass through */
ASSERT_TRUE(image_filter_test(f, PARTITION_ROOT, "anything"));
ASSERT_TRUE(image_filter_test(f, PARTITION_HOME, "anything"));
}
TEST(image_filter_test_verity_fallback) {
_cleanup_(image_filter_freep) ImageFilter *f = NULL;
/* Filter on usr= should also constrain usr-verity and usr-verity-sig */
ASSERT_OK(image_filter_parse("usr=250", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY, "251"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "251"));
f = image_filter_free(f);
/* Filter on root= should also constrain root-verity and root-verity-sig */
ASSERT_OK(image_filter_parse("root=A", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_ROOT_VERITY, "A"));
ASSERT_FALSE(image_filter_test(f, PARTITION_ROOT_VERITY, "B"));
ASSERT_TRUE(image_filter_test(f, PARTITION_ROOT_VERITY_SIG, "A"));
ASSERT_FALSE(image_filter_test(f, PARTITION_ROOT_VERITY_SIG, "B"));
/* Unrelated verity-less designators are not affected */
ASSERT_TRUE(image_filter_test(f, PARTITION_HOME, "anything"));
f = image_filter_free(f);
/* Glob patterns should work through the fallback too */
ASSERT_OK(image_filter_parse("usr=25*", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "250"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "259"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR, "260"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "250"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "259"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY, "260"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "250"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "259"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "260"));
}
TEST(image_filter_test_verity_explicit) {
_cleanup_(image_filter_freep) ImageFilter *f = NULL;
/* Explicit usr-verity= pattern wins over the usr= fallback */
ASSERT_OK(image_filter_parse("usr=250:usr-verity=999", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR, "999"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "999"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY, "250"));
/* usr-verity-sig still falls back to usr= since no explicit usr-verity-sig= was given */
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "999"));
f = image_filter_free(f);
/* Explicit usr-verity-sig= pattern wins over the usr= fallback */
ASSERT_OK(image_filter_parse("usr=250:usr-verity-sig=777", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "250"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "777"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY_SIG, "250"));
/* usr-verity still falls back to usr= since no explicit usr-verity= was given */
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "250"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY, "777"));
f = image_filter_free(f);
/* Fallback does not apply in reverse: usr-verity= must not constrain usr */
ASSERT_OK(image_filter_parse("usr-verity=999", &f));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR_VERITY, "999"));
ASSERT_FALSE(image_filter_test(f, PARTITION_USR_VERITY, "250"));
ASSERT_TRUE(image_filter_test(f, PARTITION_USR, "anything"));
}
#endif
DEFINE_TEST_MAIN(LOG_INFO);