mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
repart: fix CopyBlocks=auto for verity-sig partitions, even harder (#37704)
@DaanDeMeyer, this is for you. Seems to work great here to duplicate ParticleOS onto another disk.
This commit is contained in:
@@ -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. */
|
||||
@@ -7250,6 +7248,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 +7465,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 +7473,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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user