From 870d6da909f762cb64d25d0100d5b18157cd074f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 Jun 2025 12:20:13 +0200 Subject: [PATCH 1/4] gpt: add partition_designator_is_verity() helper And rework partition_designator_is_verity_sig() to be based on partition_verity_sig_to_data(), so that we don't have to maintain two lists of verity sig partition types. --- src/shared/gpt.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 9e5ace35a4..3261d0001b 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -31,15 +31,19 @@ typedef enum PartitionDesignator { bool partition_designator_is_versioned(PartitionDesignator d) _const_; -static inline bool partition_designator_is_verity_sig(PartitionDesignator d) { - return IN_SET(d, PARTITION_ROOT_VERITY_SIG, PARTITION_USR_VERITY_SIG); -} - PartitionDesignator partition_verity_of(PartitionDesignator p) _const_; PartitionDesignator partition_verity_sig_of(PartitionDesignator p) _const_; PartitionDesignator partition_verity_to_data(PartitionDesignator d) _const_; PartitionDesignator partition_verity_sig_to_data(PartitionDesignator d) _const_; +static inline bool partition_designator_is_verity(PartitionDesignator d) { + return partition_verity_to_data(d) >= 0; +} + +static inline bool partition_designator_is_verity_sig(PartitionDesignator d) { + return partition_verity_sig_to_data(d) >= 0; +} + const char* partition_designator_to_string(PartitionDesignator d) _const_; PartitionDesignator partition_designator_from_string(const char *name) _pure_; From 188467dfd9290b7d6246b68fc82ac70436fd6c29 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 Jun 2025 18:31:40 +0200 Subject: [PATCH 2/4] udev: add udev properties that point to verity/verity sig metadata partitions from data partitions This extends the dissect_image builtin to actually add device node references to the device nodes where the associated data is placed, if we can find it. This is kept very generic, and independent from the roothash properties and suchlike, since it makes sense to make it possible to set these properties also independently of the dissect-image builtin. The device path is a /dev/disk/by-diskseq/ symlink, so that we have stable reference that are not subject to dev_t reuses. --- src/udev/udev-builtin-dissect_image.c | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/udev/udev-builtin-dissect_image.c b/src/udev/udev-builtin-dissect_image.c index 02aa8fcbea..444b0fce37 100644 --- a/src/udev/udev-builtin-dissect_image.c +++ b/src/udev/udev-builtin-dissect_image.c @@ -124,6 +124,11 @@ static int verb_probe(UdevEvent *event, sd_device *dev) { return 0; } + uint64_t diskseq; + r = sd_device_get_diskseq(dev, &diskseq); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get diskseq of '%s': %m", devnode); + r = blockdev_partscan_enabled(dev); if (r < 0) return log_device_debug_errno(dev, r, "Failed to determine if block device '%s' supports partitions: %m", devnode); @@ -262,11 +267,22 @@ static int verb_probe(UdevEvent *event, sd_device *dev) { /* Indicate whether this partition has verity protection */ PartitionDesignator dv = partition_verity_of(d); if (dv >= 0 && image->partitions[dv].found) { + /* Add one property that indicates as a boolean whether Verity is available at all for this */ _cleanup_free_ char *f = NULL; if (asprintf(&f, "ID_DISSECT_PART%i_HAS_VERITY", p->partno) < 0) return log_oom_debug(); (void) udev_builtin_add_property(event, f, "1"); + + /* Add a second property that indicates where the block device is found with the + * Verity data. We maintain this in an independent property, since Verity data might + * be available from other sources too, not just block devices, and we'd like to keep + * the props somewhat open for that. */ + f = mfree(f); + if (asprintf(&f, "ID_DISSECT_PART%i_VERITY_DEVICE", p->partno) < 0) + return log_oom_debug(); + + (void) udev_builtin_add_propertyf(event, f, "/dev/disk/by-diskseq/%" PRIu64 "-part%i", diskseq, image->partitions[dv].partno); } dv = partition_verity_sig_of(d); @@ -276,6 +292,12 @@ static int verb_probe(UdevEvent *event, sd_device *dev) { return log_oom_debug(); (void) udev_builtin_add_property(event, f, "1"); + + f = mfree(f); + if (asprintf(&f, "ID_DISSECT_PART%i_VERITY_SIG_DEVICE", p->partno) < 0) + return log_oom_debug(); + + (void) udev_builtin_add_propertyf(event, f, "/dev/disk/by-diskseq/%" PRIu64 "-part%i", diskseq, image->partitions[dv].partno); } if (d == verity.designator) { @@ -344,7 +366,12 @@ static int verb_copy(UdevEvent *event, sd_device *dev) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to get partition number of partition block device '%s': %m", devnode); - FOREACH_STRING(f, "_DESIGNATOR", "_ARCHITECTURE", "_HAS_VERITY", "_HAS_VERITY_SIG", "_ROOTHASH", "_ROOTHASH_SIG") { + FOREACH_STRING(f, + "_DESIGNATOR", "_ARCHITECTURE", + "_HAS_VERITY", "_HAS_VERITY_SIG", + "_ROOTHASH", "_ROOTHASH_SIG", + "_VERITY_DEVICE", "_VERITY_SIG_DEVICE") { + /* The property on the parent device contains the partition number */ _cleanup_free_ char *p = strjoin("ID_DISSECT_PART", partn, f); if (!p) From d3a6606cea2929c209e7da3118dafc8d29b0ce19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 Jun 2025 19:27:33 +0200 Subject: [PATCH 3/4] repart: try harder to find verity-sig partitions for CopyBlocks=auto verity-sig partitions are not kernel concepts, hence dm-verity won't link them for us from the slaves/ subdir in sysfs. Hence let's instead look up the partition via udev's database. Hence: when we search for the data+verity+verity-sig partitions then search for the first two as usual, but search for the latter by looking up the udev props on the first two, and then following the paths provided therein. Fixes: #34835 --- src/repart/repart.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/repart/repart.c b/src/repart/repart.c index 5fe195c033..b8bfeb87e8 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -7250,6 +7250,82 @@ static int resolve_copy_blocks_auto_candidate( return true; } +static int resolve_copy_blocks_auto_candidate_harder( + dev_t start_devno, + GptPartitionType partition_type, + dev_t restrict_devno, + dev_t *ret_found_devno, + sd_id128_t *ret_uuid) { + + _cleanup_(sd_device_unrefp) sd_device *d = NULL, *nd = NULL; + int r; + + /* A wrapper around resolve_copy_blocks_auto_candidate(), but looks for verity/verity-sig associated + * partitions, too. i.e. if the input is a data or verity partition, will try to find the + * verity/verity-sig partition for it, based on udev metadata. */ + + const char *property; + if (partition_designator_is_verity(partition_type.designator)) + property = "ID_DISSECT_PART_VERITY_DEVICE"; + else if (partition_designator_is_verity_sig(partition_type.designator)) + property = "ID_DISSECT_PART_VERITY_SIG_DEVICE"; + else + goto not_found; + + r = sd_device_new_from_devnum(&d, 'b', start_devno); + if (r < 0) + return log_error_errno(r, "Failed to allocate device object for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(start_devno)); + + const char *node; + r = sd_device_get_property_value(d, property, &node); + if (r == -ENOENT) { + log_debug_errno(r, "Property %s not set on " DEVNUM_FORMAT_STR ", skipping.", property, DEVNUM_FORMAT_VAL(start_devno)); + goto not_found; + } + if (r < 0) + return log_error_errno(r, "Failed to read property %s from device " DEVNUM_FORMAT_STR ": %m", property, DEVNUM_FORMAT_VAL(start_devno)); + + r = sd_device_new_from_devname(&nd, node); + if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) { + log_debug_errno(r, "Device %s referenced in %s property not found, skipping: %m", node, property); + goto not_found; + } + if (r < 0) + return log_error_errno(r, "Failed to allocate device object for '%s': %m", node); + + r = device_in_subsystem(nd, "block"); + if (r < 0) + return log_error_errno(r, "Failed to determine if '%s' is a block device: %m", node); + if (r == 0) { + log_debug("Device referenced by %s property of %s does not refer to block device, refusing.", property, node); + goto not_found; + } + + dev_t found_devno = 0; + r = sd_device_get_devnum(nd, &found_devno); + if (r < 0) + return log_error_errno(r, "Failed to get device number for '%s': %m", node); + + r = resolve_copy_blocks_auto_candidate(found_devno, partition_type, restrict_devno, ret_uuid); + if (r < 0) + return r; + if (r == 0) + goto not_found; + + if (ret_found_devno) + *ret_found_devno = found_devno; + + return 1; + +not_found: + if (ret_found_devno) + *ret_found_devno = 0; + if (ret_uuid) + *ret_uuid = SD_ID128_NULL; + + return 0; +} + static int find_backing_devno( const char *path, const char *root, @@ -7391,7 +7467,7 @@ static int resolve_copy_blocks_auto( return r; if (r > 0) { /* We found a matching one! */ - if (found != 0) + if (found != 0 && found != sl) return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Multiple matching partitions found for partition type %s, refusing.", partition_designator_to_string(type.designator)); @@ -7399,6 +7475,20 @@ static int resolve_copy_blocks_auto( found = sl; found_uuid = u; } + + dev_t harder_devno = 0; + r = resolve_copy_blocks_auto_candidate_harder(sl, type, restrict_devno, &harder_devno, &u); + if (r < 0) + return r; + if (r > 0) { + /* We found a matching one! */ + if (found != 0 && found != harder_devno) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "Multiple matching partitions found, refusing."); + + found = harder_devno; + found_uuid = u; + } } } else if (errno != ENOENT) return log_error_errno(errno, "Failed open %s: %m", p); From 6513646c6206f1c62d5326ca182fa26c12061e5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 Jun 2025 12:30:41 +0200 Subject: [PATCH 4/4] repart: use partition_designator_is_verity_sig() + partition_designator_is_verity() more --- src/repart/repart.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/repart/repart.c b/src/repart/repart.c index b8bfeb87e8..de138c15d3 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -2612,9 +2612,7 @@ static int partition_read_definition(Partition *p, const char *path, const char } /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */ - if ((IN_SET(p->type.designator, - PARTITION_ROOT_VERITY, - PARTITION_USR_VERITY) || p->verity == VERITY_DATA) && p->read_only < 0) + if ((partition_designator_is_verity(p->type.designator) || p->verity == VERITY_DATA) && p->read_only < 0) p->read_only = true; /* Default to "growfs" on, unless read-only */ @@ -5325,7 +5323,7 @@ static int context_copy_blocks(Context *context) { continue; /* For offline signing case */ - if (!set_isempty(arg_verity_settings) && IN_SET(p->type.designator, PARTITION_ROOT_VERITY_SIG, PARTITION_USR_VERITY_SIG)) + if (!set_isempty(arg_verity_settings) && partition_designator_is_verity_sig(p->type.designator)) return partition_format_verity_sig(context, p); if (p->copy_blocks_fd < 0) @@ -6298,7 +6296,7 @@ static int context_mkfs(Context *context) { continue; /* For offline signing case */ - if (!set_isempty(arg_verity_settings) && IN_SET(p->type.designator, PARTITION_ROOT_VERITY_SIG, PARTITION_USR_VERITY_SIG)) + if (!set_isempty(arg_verity_settings) && partition_designator_is_verity_sig(p->type.designator)) return partition_format_verity_sig(context, p); /* Minimized partitions will use the copy blocks logic so skip those here. */