]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: try harder to find verity-sig partitions for CopyBlocks=auto
authorLennart Poettering <lennart@poettering.net>
Mon, 2 Jun 2025 17:27:33 +0000 (19:27 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 6 Jun 2025 10:37:44 +0000 (12:37 +0200)
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

index 5fe195c033d5e2c5cb9af32aec80dad1e472ed6b..b8bfeb87e8bd7f6627c7647d93c6f812fcbc793f 100644 (file)
@@ -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);