From 33319701ca54abae71afae27b0f925db5f500fae Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 14 Sep 2024 00:19:48 +0200 Subject: [PATCH] veritysetup: parse signature from DPS partition If the signature is not specified manually, and sd-veritysetup is running on a device, try to find the parent and if it's a DPS-compliant GPT image with a signature partition, parse it and use it. This allows automatically using the signature on boot, which allows setting an IPE policy that enforces a validated signature on the rootfs too. --- man/veritytab.xml | 5 ++- src/veritysetup/veritysetup.c | 84 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/man/veritytab.xml b/man/veritytab.xml index 6bd09604b67..e6b36f55f91 100644 --- a/man/veritytab.xml +++ b/man/veritytab.xml @@ -217,7 +217,10 @@ This is based on crypttab(5). A base64 string encoding the root hash signature prefixed by base64: or a path to roothash signature file used to verify the root hash (in kernel). This feature requires Linux kernel - version 5.4 or more recent. + version 5.4 or more recent. Since version 257, if not specified and the data device is in a GPT image with a + + Discoverable Partitions Specification compliant matching signature partition, it will be + automatically loaded and used. diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index d1335724644..90f953edc14 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -5,12 +5,16 @@ #include #include "alloc-util.h" +#include "blockdev-util.h" #include "cryptsetup-util.h" +#include "dissect-image.h" #include "fileio.h" #include "fstab-util.h" #include "hexdecoct.h" #include "log.h" +#include "loop-util.h" #include "main-func.h" +#include "missing_loop.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -274,6 +278,79 @@ static int parse_options(const char *options) { return r; } +static int find_dps_signature( + const char *data_device, + void *root_hash, + size_t root_hash_size, + char **ret_root_hash_signature) { + + _cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT; + _cleanup_free_ char *base64_signature = NULL, *string_signature = NULL; + _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; + _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + DissectImageFlags dissect_image_flags = + DISSECT_IMAGE_GPT_ONLY | + DISSECT_IMAGE_USR_NO_ROOT | + DISSECT_IMAGE_ADD_PARTITION_DEVICES | + DISSECT_IMAGE_DEVICE_READ_ONLY; + ssize_t len; + int r; + + assert(data_device); + assert(root_hash); + assert(root_hash_size > 0); + assert(ret_root_hash_signature); + + if (!startswith(data_device, "/dev/")) + return -EINVAL; + + verity.root_hash_size = root_hash_size; + verity.root_hash = malloc(root_hash_size); + if (!verity.root_hash) + return log_oom_debug(); + memcpy(verity.root_hash, root_hash, root_hash_size); + + r = block_device_new_from_path(data_device, BLOCK_DEVICE_LOOKUP_WHOLE_DISK, &device); + if (r < 0) + return log_debug_errno(r, "Failed to get udev device for data device: %m"); + + r = loop_device_open(device, O_RDONLY, LOCK_SH, &loop_device); + if (r < 0) + return log_debug_errno(r, "Failed to create loop device for root image: %m"); + + r = dissect_loop_device( + loop_device, + &verity, + /* mount_options= */ NULL, + /* image_policy= */ NULL, + dissect_image_flags, + &dissected_image); + if (r < 0) + return log_debug_errno(r, "Failed to dissect image: %m"); + + r = dissected_image_load_verity_sig_partition( + dissected_image, + loop_device->fd, + &verity); + if (r < 0) + return log_debug_errno(r, "Failed to load verity signature partition: %m"); + if (r == 0) + return -ENOENT; + + len = base64mem(verity.root_hash_sig, verity.root_hash_sig_size, &base64_signature); + if (len < 0) + return log_debug_errno(len, "Failed to encode root hash signature: %m"); + + string_signature = strjoin("base64:", base64_signature); + if (!string_signature) + return log_oom_debug(); + + *ret_root_hash_signature = TAKE_PTR(string_signature); + + return 0; +} + static int run(int argc, char *argv[]) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; const char *verb; @@ -371,6 +448,13 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to configure data device: %m"); +#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY + /* If we can support signature checks but we weren't given one, try to find it following the + * DPS on the same GPT device */ + if (!arg_root_hash_signature) + (void) find_dps_signature(data_device, m, l, &arg_root_hash_signature); +#endif + if (arg_root_hash_signature) { #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY _cleanup_free_ char *hash_sig = NULL;