From 9a8a4428bbfcf557c458917124fde7e8a84df50c Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 15 Oct 2026 16:42:48 +0200 Subject: [PATCH] veritysetup: make root-hash-signature=auto optional systemd-gpt-auto-generator always passes root-hash-signature=auto for the root and /usr partitions. The data device doesn't have the ID_DISSECT_PART_ROOTHASH_SIG udev property if the image has no signature partition. In that case, systemd-veritysetup fails, and the system can't boot from a verity image that isn't signed. If a signature exists but neither the kernel nor userspace validates it, we activate the device without the signature. The image builder controls whether the image has a signature partition. Whether the boot requires a signature thus depends on the image contents. The failure gives no protection, because an image with a signature that doesn't validate boots. Anyone can avoid the failure by adding a signature partition with any well-formed signature. Whether a signature is required must come from the host. systemd-gpt-auto-generator enables root-hash-signature-required= if systemd.image_policy= requires a signature. With that option, activation fails if the signature is missing or invalid. Let's activate the device without a signature if the property is missing and root-hash-signature-required= isn't enabled. --- NEWS | 12 +++++++----- man/veritytab.xml | 5 +++-- src/veritysetup/veritysetup.c | 15 +++++++++------ test/units/TEST-50-DISSECT.dissect.sh | 11 +++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index d36ffd1297c..88f69f1b04f 100644 --- a/NEWS +++ b/NEWS @@ -79,11 +79,13 @@ CHANGES WITH 263 in spe: * systemd-portabled now asks polkit before it inspects extension images that are specified by path. - * systemd-veritysetup gained a root-hash-signature-required= option, - which systemd-gpt-auto-generator enables if systemd.image_policy= - requires a signature. If the kernel can't validate the root hash - signature, systemd-veritysetup now validates it in userspace with - the certificates in /etc/verity.d/, like systemd-dissect does. + * systemd-veritysetup no longer fails if root-hash-signature=auto + finds no signature. It gained a root-hash-signature-required= + option, which systemd-gpt-auto-generator enables if + systemd.image_policy= requires a signature. If the kernel can't + validate the root hash signature, systemd-veritysetup now + validates it in userspace with the certificates in + /etc/verity.d/, like systemd-dissect does. * systemd-networkd and networkctl have been merged into a single multi-call binary, with the former becoming a symlink to the latter. diff --git a/man/veritytab.xml b/man/veritytab.xml index 9aafa226521..924715dabc7 100644 --- a/man/veritytab.xml +++ b/man/veritytab.xml @@ -221,8 +221,9 @@ This is based on crypttab(5). base64:, or an absolute path to a root hash signature file used to verify the root hash (in kernel). If the special string auto is specified, the root hash signature is attempted to be read from the udev property ID_DISSECT_PART_ROOTHASH_SIG= (in - Base64 format) of the data device. This feature requires Linux kernel version 5.4 or more - recent. + Base64 format) of the data device. If the data device doesn't have this property, the device is + activated without a root hash signature, unless is + specified. This feature requires Linux kernel version 5.4 or more recent. diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index 1bda60c8a24..535babc0a0d 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -366,12 +366,15 @@ static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata) const char *t; r = sd_device_get_property_value(ASSERT_PTR(datadev), "ID_DISSECT_PART_ROOTHASH_SIG", &t); - if (r < 0) - return log_error_errno(r, "Automatic root hash signature pick up requested, and device doesn't carry ID_DISSECT_PART_ROOTHASH_SIG property, cannot determine root hash signature."); - - r = unbase64mem(t, &arg_root_hash_signature.iov_base, &arg_root_hash_signature.iov_len); - if (r < 0) - return log_error_errno(r, "Failed to decode root hash signature data from udev data device: %m"); + if (r == -ENOENT) + log_debug("Data device doesn't have the ID_DISSECT_PART_ROOTHASH_SIG property, activating without root hash signature."); + else if (r < 0) + return log_error_errno(r, "Failed to read ID_DISSECT_PART_ROOTHASH_SIG property of data device: %m"); + else { + r = unbase64mem(t, &arg_root_hash_signature.iov_base, &arg_root_hash_signature.iov_len); + if (r < 0) + return log_error_errno(r, "Failed to decode root hash signature data from udev data device: %m"); + } } if (arg_root_hash_signature_required && !iovec_is_set(&arg_root_hash_signature)) diff --git a/test/units/TEST-50-DISSECT.dissect.sh b/test/units/TEST-50-DISSECT.dissect.sh index 0e1916ce7b6..cd0ab7827f6 100755 --- a/test/units/TEST-50-DISSECT.dissect.sh +++ b/test/units/TEST-50-DISSECT.dissect.sh @@ -264,6 +264,17 @@ cp /tmp/test-50-unknown.crt /run/verity.d/test-50-unknown.crt root-hash-signature=/tmp/test-50-unknown.p7s,root-hash-signature-required=yes /usr/lib/systemd/systemd-veritysetup detach test-50-required rm /run/verity.d/test-50-mkosi.crt /run/verity.d/test-50-unknown.crt /tmp/test-50-unknown.key /tmp/test-50-unknown.crt /tmp/test-50-unknown.p7s /tmp/test-50-garbage.p7s +# A loop device of the plain file system image has no ID_DISSECT_PART_ROOTHASH_SIG property. With +# root-hash-signature=auto, systemd-veritysetup activates it without a signature. If +# root-hash-signature-required=yes is set as well, systemd-veritysetup refuses to activate it. +loop="$(losetup --show -r -f "$MINIMAL_IMAGE.raw")" +udevadm wait --timeout=60 --settle "$loop" +(! /usr/lib/systemd/systemd-veritysetup attach test-50-auto "$loop" "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE_ROOTHASH" \ + root-hash-signature=auto,root-hash-signature-required=yes) +/usr/lib/systemd/systemd-veritysetup attach test-50-auto "$loop" "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE_ROOTHASH" \ + root-hash-signature=auto +/usr/lib/systemd/systemd-veritysetup detach test-50-auto +losetup -d "$loop" # Test BindLogSockets= systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket