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
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,
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);
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,
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,
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;
+ }
+
+ 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 && !dissected_image->has_verity_sig)
+ 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);
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,
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;
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,
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);
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,
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");