mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
dissect-image: guess verity root hash from the resources we found
When dissecting an image, let's make use of the Verity data even if we got told no root hash explicitly: we can simply determine it by concatenating the data partition uuid with the verity partition uuid. Of course, on first thought this doesn't really add much: if the root hash is not pinned from somewhere, this does not guarantee trust in the image. However, this is very useful for attestation: if we have the root hash we can measure it before mounting things, even if we don't actually authenticate it. Hence, at best this helps us with attestation, at worst it doesn't improve security but certainly doesn't hurt it.
This commit is contained in:
@@ -529,6 +529,14 @@ disk images with `--image=` or similar:
|
||||
images. Defaults to true, i.e. userspace signature validation is allowed. If
|
||||
false, authentication can be done only via the kernel's internal keyring.
|
||||
|
||||
* `$SYSTEMD_DISSECT_VERITY_GUESS` – takes a boolean. Controls whether to guess
|
||||
the Verity root hash from the partition UUIDs of a suitable pair of data
|
||||
partition and matching Verity partition: the UUIDs two are simply joined and
|
||||
used as root hash, in accordance with the recommendations in [Discoverable
|
||||
Partitions
|
||||
Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification). Defaults
|
||||
to true.
|
||||
|
||||
`systemd-cryptsetup`:
|
||||
|
||||
* `$SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE` – takes a boolean, which controls
|
||||
|
||||
@@ -2364,6 +2364,12 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_guess_verity_roothash(
|
||||
dissected_image,
|
||||
p->verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
||||
@@ -2177,8 +2177,10 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
if (arg_image) {
|
||||
r = verity_settings_load(
|
||||
&arg_verity_settings,
|
||||
arg_image, NULL, NULL);
|
||||
&arg_verity_settings,
|
||||
arg_image,
|
||||
/* root_hash_path= */ NULL,
|
||||
/* root_hash_sig_path= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image);
|
||||
|
||||
@@ -2244,6 +2246,12 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load verity signature partition: %m");
|
||||
|
||||
r = dissected_image_guess_verity_roothash(
|
||||
m,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to guess verity root hash: %m");
|
||||
|
||||
if (arg_action != ACTION_DISSECT) {
|
||||
r = dissected_image_decrypt_interactively(
|
||||
m, NULL,
|
||||
|
||||
@@ -461,6 +461,12 @@ static int vl_method_mount_image(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_guess_verity_roothash(
|
||||
di,
|
||||
&verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
di,
|
||||
p.password,
|
||||
|
||||
@@ -6391,10 +6391,20 @@ static int run(int argc, char *argv[]) {
|
||||
dissected_image,
|
||||
loop->fd,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to load Verity signature partition: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (dissected_image->has_verity && !arg_verity_settings.root_hash && !dissected_image->has_verity_sig)
|
||||
r = dissected_image_guess_verity_roothash(
|
||||
dissected_image,
|
||||
&arg_verity_settings);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to guess Verity root hash: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (dissected_image->has_verity && !arg_verity_settings.root_hash)
|
||||
log_notice("Note: image %s contains verity information, but no root hash specified and no embedded "
|
||||
"root hash signature found! Proceeding without integrity checking.", arg_image);
|
||||
|
||||
|
||||
@@ -3525,6 +3525,69 @@ int dissected_image_load_verity_sig_partition(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_guess_verity_roothash(
|
||||
DissectedImage *m,
|
||||
VeritySettings *verity) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(verity);
|
||||
|
||||
/* Guesses the Verity root hash from the partitions we found, taking into account that as per
|
||||
* https://uapi-group.org/specifications/specs/discoverable_partitions_specification/ the UUIDS of
|
||||
* the data and verity partitions are respectively the first and second halves of the dm-verity
|
||||
* roothash.
|
||||
*
|
||||
* Note of course that relying on this guesswork is mostly useful for later attestation, not so much
|
||||
* for a-priori security. */
|
||||
|
||||
if (verity->root_hash) /* Already loaded? */
|
||||
return 0;
|
||||
|
||||
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_GUESS");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_GUESS, ignoring: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
PartitionDesignator dd = verity->designator;
|
||||
if (dd < 0) {
|
||||
if (m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
dd = PARTITION_ROOT;
|
||||
else if (m->partitions[PARTITION_USR_VERITY].found)
|
||||
dd = PARTITION_USR;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
DissectedPartition *d = m->partitions + dd;
|
||||
if (!d->found)
|
||||
return 0;
|
||||
|
||||
PartitionDesignator dv = partition_verity_of(dd);
|
||||
assert(dv >= 0);
|
||||
|
||||
DissectedPartition *p = m->partitions + dv;
|
||||
if (!p->found)
|
||||
return 0;
|
||||
|
||||
_cleanup_free_ uint8_t *rh = malloc(sizeof(sd_id128_t) * 2);
|
||||
if (!rh)
|
||||
return log_oom_debug();
|
||||
|
||||
memcpy(mempcpy(rh, &d->uuid, sizeof(sd_id128_t)), &p->uuid, sizeof(sd_id128_t));
|
||||
verity->root_hash = TAKE_PTR(rh);
|
||||
verity->root_hash_size = sizeof(sd_id128_t) * 2;
|
||||
|
||||
verity->designator = dd;
|
||||
|
||||
m->verity_ready = true;
|
||||
m->partitions[dd].rw = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dissected_image_acquire_metadata(
|
||||
DissectedImage *m,
|
||||
int userns_fd,
|
||||
@@ -4038,6 +4101,10 @@ int mount_image_privately_interactively(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_guess_verity_roothash(dissected_image, &verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, &verity, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -4181,6 +4248,10 @@ int verity_dissect_and_mount(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_guess_verity_roothash(dissected_image, verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
||||
@@ -229,6 +229,7 @@ static inline bool verity_settings_data_covers(const VeritySettings *verity, Par
|
||||
int verity_settings_copy(VeritySettings *dest, const VeritySettings *source);
|
||||
|
||||
int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity);
|
||||
int dissected_image_guess_verity_roothash(DissectedImage *m, VeritySettings *verity);
|
||||
|
||||
bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
|
||||
bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d);
|
||||
|
||||
@@ -1814,6 +1814,12 @@ static int merge_subprocess(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_guess_verity_roothash(
|
||||
m,
|
||||
&verity_settings);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(
|
||||
m, NULL,
|
||||
&verity_settings,
|
||||
|
||||
@@ -196,6 +196,10 @@ static int verb_probe(UdevEvent *event, sd_device *dev) {
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to load verity signature data from image: %m");
|
||||
|
||||
r = dissected_image_guess_verity_roothash(image, &verity);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to guess root hash from image: %m");
|
||||
|
||||
/* Marker that we determined this to be a suitable image */
|
||||
(void) udev_builtin_add_property(event, "ID_DISSECT_IMAGE", "1");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user