From: Lennart Poettering Date: Sat, 15 Nov 2025 06:42:12 +0000 (+0100) Subject: dissect-image,execute: switch root hash/root hash sig storage to struct iovec X-Git-Tag: v259-rc1~34 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=08d75cfb99fd2ec5266e6a062c90e9b18f9cc18f;p=thirdparty%2Fsystemd.git dissect-image,execute: switch root hash/root hash sig storage to struct iovec let's go one step further on our iovec'ification journey. No change in behaviour, just rework to make struct iovec used everywhere. --- diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 7c5e70d4077..a349c001611 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -772,7 +772,7 @@ static int property_get_root_hash( assert(property); assert(reply); - return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size); + return sd_bus_message_append_array(reply, 'y', c->root_hash.iov_base, c->root_hash.iov_len); } static int property_get_root_hash_sig( @@ -790,7 +790,7 @@ static int property_get_root_hash_sig( assert(property); assert(reply); - return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size); + return sd_bus_message_append_array(reply, 'y', c->root_hash_sig.iov_base, c->root_hash_sig.iov_len); } static int property_get_root_image_options( @@ -1915,35 +1915,30 @@ int bus_exec_context_set_transient_property( } if (streq(name, "RootHash")) { - const void *roothash_decoded; - size_t roothash_decoded_size; + struct iovec roothash_decoded; - r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size); + r = sd_bus_message_read_array(message, 'y', (const void**) &roothash_decoded.iov_base, &roothash_decoded.iov_len); if (r < 0) return r; if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - _cleanup_free_ char *encoded = NULL; - if (roothash_decoded_size == 0) { + if (!iovec_is_set(&roothash_decoded)) { c->root_hash_path = mfree(c->root_hash_path); - c->root_hash = mfree(c->root_hash); - c->root_hash_size = 0; + iovec_done(&c->root_hash); unit_write_settingf(u, flags, name, "RootHash="); } else { - _cleanup_free_ void *p = NULL; - - encoded = hexmem(roothash_decoded, roothash_decoded_size); + _cleanup_free_ char *encoded = hexmem(roothash_decoded.iov_base, roothash_decoded.iov_len); if (!encoded) return -ENOMEM; - p = memdup(roothash_decoded, roothash_decoded_size); - if (!p) + _cleanup_(iovec_done) struct iovec p = {}; + if (!iovec_memdup(&roothash_decoded, &p)) return -ENOMEM; - free_and_replace(c->root_hash, p); - c->root_hash_size = roothash_decoded_size; + iovec_done(&c->root_hash); + c->root_hash = TAKE_STRUCT(p); c->root_hash_path = mfree(c->root_hash_path); unit_write_settingf(u, flags, name, "RootHash=%s", encoded); @@ -1954,43 +1949,35 @@ int bus_exec_context_set_transient_property( } if (streq(name, "RootHashPath")) { - c->root_hash_size = 0; - c->root_hash = mfree(c->root_hash); - + iovec_done(&c->root_hash); return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error); } if (streq(name, "RootHashSignature")) { - const void *roothash_sig_decoded; - size_t roothash_sig_decoded_size; + struct iovec roothash_sig_decoded; - r = sd_bus_message_read_array(message, 'y', &roothash_sig_decoded, &roothash_sig_decoded_size); + r = sd_bus_message_read_array(message, 'y', (const void**) &roothash_sig_decoded.iov_base, &roothash_sig_decoded.iov_len); if (r < 0) return r; if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - _cleanup_free_ char *encoded = NULL; - - if (roothash_sig_decoded_size == 0) { + if (!iovec_is_set(&roothash_sig_decoded)) { c->root_hash_sig_path = mfree(c->root_hash_sig_path); - c->root_hash_sig = mfree(c->root_hash_sig); - c->root_hash_sig_size = 0; + iovec_done(&c->root_hash_sig); unit_write_settingf(u, flags, name, "RootHashSignature="); } else { - _cleanup_free_ void *p = NULL; - ssize_t len; - - len = base64mem(roothash_sig_decoded, roothash_sig_decoded_size, &encoded); + _cleanup_free_ char *encoded = NULL; + ssize_t len = base64mem(roothash_sig_decoded.iov_base, roothash_sig_decoded.iov_len, &encoded); if (len < 0) return -ENOMEM; - p = memdup(roothash_sig_decoded, roothash_sig_decoded_size); - if (!p) + _cleanup_(iovec_done) struct iovec p = {}; + if (!iovec_memdup(&roothash_sig_decoded, &p)) return -ENOMEM; - free_and_replace(c->root_hash_sig, p); - c->root_hash_sig_size = roothash_sig_decoded_size; + iovec_done(&c->root_hash_sig); + c->root_hash_sig = TAKE_STRUCT(p); c->root_hash_sig_path = mfree(c->root_hash_sig_path); unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded); @@ -2001,9 +1988,7 @@ int bus_exec_context_set_transient_property( } if (streq(name, "RootHashSignaturePath")) { - c->root_hash_sig_size = 0; - c->root_hash_sig = mfree(c->root_hash_sig); - + iovec_done(&c->root_hash_sig); return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error); } diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 44823a881fa..88178a82f96 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -3583,11 +3583,9 @@ static int setup_ephemeral( static int verity_settings_prepare( VeritySettings *verity, const char *root_image, - const void *root_hash, - size_t root_hash_size, + const struct iovec *root_hash, const char *root_hash_path, - const void *root_hash_sig, - size_t root_hash_sig_size, + const struct iovec *root_hash_sig, const char *root_hash_sig_path, const char *verity_data_path) { @@ -3596,26 +3594,20 @@ static int verity_settings_prepare( assert(verity); if (root_hash) { - void *d; + iovec_done(&verity->root_hash); - d = memdup(root_hash, root_hash_size); - if (!d) + if (!iovec_memdup(root_hash, &verity->root_hash)) return -ENOMEM; - free_and_replace(verity->root_hash, d); - verity->root_hash_size = root_hash_size; verity->designator = PARTITION_ROOT; } if (root_hash_sig) { - void *d; + iovec_done(&verity->root_hash_sig); - d = memdup(root_hash_sig, root_hash_sig_size); - if (!d) + if (!iovec_memdup(root_hash_sig, &verity->root_hash_sig)) return -ENOMEM; - free_and_replace(verity->root_hash_sig, d); - verity->root_hash_sig_size = root_hash_sig_size; verity->designator = PARTITION_ROOT; } @@ -3845,8 +3837,8 @@ static int apply_mount_namespace( r = verity_settings_prepare( &verity, root_image, - context->root_hash, context->root_hash_size, context->root_hash_path, - context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path, + &context->root_hash, context->root_hash_path, + &context->root_hash_sig, context->root_hash_sig_path, context->root_verity); if (r < 0) return r; diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c index d046a8a6945..f7a669d9c3b 100644 --- a/src/core/execute-serialize.c +++ b/src/core/execute-serialize.c @@ -1662,11 +1662,11 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) { if (r < 0) return r; - r = serialize_item_hexmem(f, "exec-context-root-hash", c->root_hash, c->root_hash_size); + r = serialize_item_hexmem(f, "exec-context-root-hash", c->root_hash.iov_base, c->root_hash.iov_len); if (r < 0) return r; - r = serialize_item_base64mem(f, "exec-context-root-hash-sig", c->root_hash_sig, c->root_hash_sig_size); + r = serialize_item_base64mem(f, "exec-context-root-hash-sig", c->root_hash_sig.iov_base, c->root_hash_sig.iov_len); if (r < 0) return r; @@ -2616,13 +2616,13 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) { if (r < 0) return r; } else if ((val = startswith(l, "exec-context-root-hash="))) { - c->root_hash = mfree(c->root_hash); - r = unhexmem(val, &c->root_hash, &c->root_hash_size); + iovec_done(&c->root_hash); + r = unhexmem(val, &c->root_hash.iov_base, &c->root_hash.iov_len); if (r < 0) return r; } else if ((val = startswith(l, "exec-context-root-hash-sig="))) { - c->root_hash_sig = mfree(c->root_hash_sig); - r= unbase64mem(val, &c->root_hash_sig, &c->root_hash_sig_size); + iovec_done(&c->root_hash_sig); + r= unbase64mem(val, &c->root_hash_sig.iov_base, &c->root_hash_sig.iov_len); if (r < 0) return r; } else if ((val = startswith(l, "exec-context-root-ephemeral="))) { diff --git a/src/core/execute.c b/src/core/execute.c index bb74b668836..29a4f692913 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -679,11 +679,9 @@ void exec_context_done(ExecContext *c) { c->root_directory = mfree(c->root_directory); c->root_image = mfree(c->root_image); c->root_image_options = mount_options_free_all(c->root_image_options); - c->root_hash = mfree(c->root_hash); - c->root_hash_size = 0; + iovec_done(&c->root_hash); c->root_hash_path = mfree(c->root_hash_path); - c->root_hash_sig = mfree(c->root_hash_sig); - c->root_hash_sig_size = 0; + iovec_done(&c->root_hash_sig); c->root_hash_sig_path = mfree(c->root_hash_sig_path); c->root_verity = mfree(c->root_verity); c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images); @@ -1178,9 +1176,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "\n"); } - if (c->root_hash) { + if (iovec_is_set(&c->root_hash)) { _cleanup_free_ char *encoded = NULL; - encoded = hexmem(c->root_hash, c->root_hash_size); + encoded = hexmem(c->root_hash.iov_base, c->root_hash.iov_len); if (encoded) fprintf(f, "%sRootHash: %s\n", prefix, encoded); } @@ -1188,10 +1186,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { if (c->root_hash_path) fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path); - if (c->root_hash_sig) { + if (iovec_is_set(&c->root_hash_sig)) { _cleanup_free_ char *encoded = NULL; ssize_t len; - len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded); + len = base64mem(c->root_hash_sig.iov_base, c->root_hash_sig.iov_len, &encoded); if (len) fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded); } diff --git a/src/core/execute.h b/src/core/execute.h index dc150e65bc0..62dd94e91d0 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "sd-id128.h" #include "bus-unit-util.h" @@ -181,8 +183,7 @@ typedef struct ExecContext { struct rlimit *rlimit[_RLIMIT_MAX]; char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path; - void *root_hash, *root_hash_sig; - size_t root_hash_size, root_hash_sig_size; + struct iovec root_hash, root_hash_sig; LIST_HEAD(MountOptions, root_image_options); bool root_ephemeral; bool working_directory_missing_ok:1; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b9c6ea6439c..ca1ce53066d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1714,9 +1714,7 @@ int config_parse_exec_root_hash( void *data, void *userdata) { - _cleanup_free_ void *roothash_decoded = NULL; ExecContext *c = ASSERT_PTR(data); - size_t roothash_decoded_size = 0; int r; assert(filename); @@ -1726,8 +1724,7 @@ int config_parse_exec_root_hash( if (isempty(rvalue)) { /* Reset if the empty string is assigned */ c->root_hash_path = mfree(c->root_hash_path); - c->root_hash = mfree(c->root_hash); - c->root_hash_size = 0; + iovec_done(&c->root_hash); return 0; } @@ -1740,24 +1737,24 @@ int config_parse_exec_root_hash( return -ENOMEM; free_and_replace(c->root_hash_path, p); - c->root_hash = mfree(c->root_hash); - c->root_hash_size = 0; + iovec_done(&c->root_hash); return 0; } /* We have a roothash to decode, eg: RootHash=012345789abcdef */ - r = unhexmem(rvalue, &roothash_decoded, &roothash_decoded_size); + _cleanup_(iovec_done) struct iovec roothash_decoded = {}; + r = unhexmem(rvalue, &roothash_decoded.iov_base, &roothash_decoded.iov_len); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue); return 0; } - if (roothash_decoded_size < sizeof(sd_id128_t)) { + if (roothash_decoded.iov_len < sizeof(sd_id128_t)) { log_syntax(unit, LOG_WARNING, filename, line, 0, "RootHash= is too short, ignoring: %s", rvalue); return 0; } - free_and_replace(c->root_hash, roothash_decoded); - c->root_hash_size = roothash_decoded_size; + iovec_done(&c->root_hash); + c->root_hash = TAKE_STRUCT(roothash_decoded); c->root_hash_path = mfree(c->root_hash_path); return 0; @@ -1775,10 +1772,7 @@ int config_parse_exec_root_hash_sig( void *data, void *userdata) { - _cleanup_free_ void *roothash_sig_decoded = NULL; - char *value; ExecContext *c = ASSERT_PTR(data); - size_t roothash_sig_decoded_size = 0; int r; assert(filename); @@ -1788,8 +1782,7 @@ int config_parse_exec_root_hash_sig( if (isempty(rvalue)) { /* Reset if the empty string is assigned */ c->root_hash_sig_path = mfree(c->root_hash_sig_path); - c->root_hash_sig = mfree(c->root_hash_sig); - c->root_hash_sig_size = 0; + iovec_done(&c->root_hash_sig); return 0; } @@ -1802,26 +1795,27 @@ int config_parse_exec_root_hash_sig( return log_oom(); free_and_replace(c->root_hash_sig_path, p); - c->root_hash_sig = mfree(c->root_hash_sig); - c->root_hash_sig_size = 0; + iovec_done(&c->root_hash_sig); return 0; } - if (!(value = startswith(rvalue, "base64:"))) { + const char *value = startswith(rvalue, "base64:"); + if (!value) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to decode RootHashSignature=, not a path but doesn't start with 'base64:', ignoring: %s", rvalue); return 0; } /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */ - r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size); + _cleanup_(iovec_done) struct iovec roothash_sig_decoded = {}; + r = unbase64mem(value, &roothash_sig_decoded.iov_base, &roothash_sig_decoded.iov_len); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHashSignature=, ignoring: %s", rvalue); return 0; } - free_and_replace(c->root_hash_sig, roothash_sig_decoded); - c->root_hash_sig_size = roothash_sig_decoded_size; + iovec_done(&c->root_hash_sig); + c->root_hash_sig = TAKE_STRUCT(roothash_sig_decoded); c->root_hash_sig_path = mfree(c->root_hash_sig_path); return 0; diff --git a/src/core/namespace.c b/src/core/namespace.c index 07a69c03a62..56c077b1628 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -24,6 +24,7 @@ #include "format-util.h" #include "fs-util.h" #include "glyph-util.h" +#include "iovec-util.h" #include "label-util.h" #include "list.h" #include "lock-util.h" @@ -1019,7 +1020,7 @@ static bool verity_has_later_duplicates(MountList *ml, const MountEntry *needle) assert(needle >= ml->mounts && needle < ml->mounts + ml->n_mounts); assert(needle->mode == MOUNT_EXTENSION_IMAGE); - if (needle->verity.root_hash_size == 0) + if (!iovec_is_set(&needle->verity.root_hash)) return false; /* Overlayfs rejects supplying the same directory inode twice as determined by filesystem UUID and @@ -1032,10 +1033,7 @@ static bool verity_has_later_duplicates(MountList *ml, const MountEntry *needle) for (const MountEntry *m = needle + 1; m < ml->mounts + ml->n_mounts; m++) { if (m->mode != MOUNT_EXTENSION_IMAGE) continue; - if (memcmp_nn(m->verity.root_hash, - m->verity.root_hash_size, - needle->verity.root_hash, - needle->verity.root_hash_size) == 0) + if (iovec_memcmp(&m->verity.root_hash, &needle->verity.root_hash) == 0) return true; } diff --git a/src/core/varlink-execute.c b/src/core/varlink-execute.c index c9c81152283..116d77e006d 100644 --- a/src/core/varlink-execute.c +++ b/src/core/varlink-execute.c @@ -790,9 +790,9 @@ int unit_exec_context_build_json(sd_json_variant **ret, const char *name, void * JSON_BUILD_PAIR_STRING_NON_EMPTY("RootImage", c->root_image), JSON_BUILD_PAIR_CALLBACK_NON_NULL("RootImageOptions", root_image_options_build_json, c->root_image_options), SD_JSON_BUILD_PAIR_BOOLEAN("RootEphemeral", c->root_ephemeral), - JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHash", c->root_hash, c->root_hash_size), + JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHash", c->root_hash.iov_base, c->root_hash.iov_len), JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashPath", c->root_hash_path), - JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHashSignature", c->root_hash_sig, c->root_hash_sig_size), + JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHashSignature", c->root_hash_sig.iov_base, c->root_hash_sig.iov_len), JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashSignaturePath", c->root_hash_sig_path), JSON_BUILD_PAIR_STRING_NON_EMPTY("RootVerity", c->root_verity), SD_JSON_BUILD_PAIR_CALLBACK("RootImagePolicy", image_policy_build_json, c->root_image_policy), diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index f4c02737f5a..1a8fa52fce8 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -474,23 +474,22 @@ static int parse_argv(int argc, char *argv[]) { case ARG_ROOT_HASH: case ARG_USR_HASH: { - _cleanup_free_ void *p = NULL; - size_t l; + _cleanup_(iovec_done) struct iovec roothash = {}; PartitionDesignator d = c == ARG_USR_HASH ? PARTITION_USR : PARTITION_ROOT; if (arg_verity_settings.designator >= 0 && arg_verity_settings.designator != d) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --root-hash=/--root-hash-sig= and --usr-hash=/--usr-hash-sig= options."); - r = unhexmem(optarg, &p, &l); + r = unhexmem(optarg, &roothash.iov_base, &roothash.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash '%s': %m", optarg); - if (l < sizeof(sd_id128_t)) + if (roothash.iov_len < sizeof(sd_id128_t)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128-bit long: %s", optarg); - free_and_replace(arg_verity_settings.root_hash, p); - arg_verity_settings.root_hash_size = l; + iovec_done(&arg_verity_settings.root_hash); + arg_verity_settings.root_hash = TAKE_STRUCT(roothash); arg_verity_settings.designator = d; break; } @@ -498,8 +497,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_ROOT_HASH_SIG: case ARG_USR_HASH_SIG: { char *value; - size_t l; - void *p; + _cleanup_(iovec_done) struct iovec sig = {}; PartitionDesignator d = c == ARG_USR_HASH_SIG ? PARTITION_USR : PARTITION_ROOT; if (arg_verity_settings.designator >= 0 && @@ -507,17 +505,17 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --root-hash=/--root-hash-sig= and --usr-hash=/--usr-hash-sig= options."); if ((value = startswith(optarg, "base64:"))) { - r = unbase64mem(value, &p, &l); + r = unbase64mem(value, &sig.iov_base, &sig.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg); } else { - r = read_full_file(optarg, (char**) &p, &l); + r = read_full_file(optarg, (char**) &sig.iov_base, &sig.iov_len); if (r < 0) return log_error_errno(r, "Failed to read root hash signature file '%s': %m", optarg); } - free_and_replace(arg_verity_settings.root_hash_sig, p); - arg_verity_settings.root_hash_sig_size = l; + iovec_done(&arg_verity_settings.root_hash_sig); + arg_verity_settings.root_hash_sig = TAKE_STRUCT(sig); arg_verity_settings.designator = d; break; } diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 78525f3836c..ac9b3456bb0 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -1191,8 +1191,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat arg_verity_settings.designator = PARTITION_ROOT; - free(arg_verity_settings.root_hash); - r = unhexmem(value, &arg_verity_settings.root_hash, &arg_verity_settings.root_hash_size); + iovec_done(&arg_verity_settings.root_hash); + r = unhexmem(value, &arg_verity_settings.root_hash.iov_base, &arg_verity_settings.root_hash.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse roothash= from kernel command line: %m"); @@ -1203,8 +1203,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat arg_verity_settings.designator = PARTITION_USR; - free(arg_verity_settings.root_hash); - r = unhexmem(value, &arg_verity_settings.root_hash, &arg_verity_settings.root_hash_size); + iovec_done(&arg_verity_settings.root_hash); + r = unhexmem(value, &arg_verity_settings.root_hash.iov_base, &arg_verity_settings.root_hash.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse usrhash= from kernel command line: %m"); diff --git a/src/mountfsd/mountwork.c b/src/mountfsd/mountwork.c index 32c0420ad00..2f12f02e7ba 100644 --- a/src/mountfsd/mountwork.c +++ b/src/mountfsd/mountwork.c @@ -379,14 +379,8 @@ static int vl_method_mount_image( return -ENOMEM; verity.designator = PARTITION_ROOT; - - verity.root_hash = TAKE_PTR(p.verity_root_hash.iov_base); - verity.root_hash_size = p.verity_root_hash.iov_len; - p.verity_root_hash.iov_len = 0; - - verity.root_hash_sig = TAKE_PTR(p.verity_root_hash_sig.iov_base); - verity.root_hash_sig_size = p.verity_root_hash_sig.iov_len; - p.verity_root_hash_sig.iov_len = 0; + verity.root_hash = TAKE_STRUCT(p.verity_root_hash); + verity.root_hash_sig = TAKE_STRUCT(p.verity_root_hash_sig); } const char *polkit_details[] = { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 000ac3cce67..2716a60d80c 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1305,38 +1305,36 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT_HASH: { - _cleanup_free_ void *k = NULL; - size_t l; + _cleanup_(iovec_done) struct iovec k = {}; - r = unhexmem(optarg, &k, &l); + r = unhexmem(optarg, &k.iov_base, &k.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash: %s", optarg); - if (l < sizeof(sd_id128_t)) + if (k.iov_len < sizeof(sd_id128_t)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128-bit long: %s", optarg); - free_and_replace(arg_verity_settings.root_hash, k); - arg_verity_settings.root_hash_size = l; + iovec_done(&arg_verity_settings.root_hash); + arg_verity_settings.root_hash = TAKE_STRUCT(k); break; } case ARG_ROOT_HASH_SIG: { + _cleanup_(iovec_done) struct iovec p = {}; char *value; - size_t l; - void *p; if ((value = startswith(optarg, "base64:"))) { - r = unbase64mem(value, &p, &l); + r = unbase64mem(value, &p.iov_base, &p.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg); } else { - r = read_full_file(optarg, (char**) &p, &l); + r = read_full_file(optarg, (char**) &p.iov_base, &p.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash signature file '%s': %m", optarg); } - free_and_replace(arg_verity_settings.root_hash_sig, p); - arg_verity_settings.root_hash_sig_size = l; + iovec_done(&arg_verity_settings.root_hash_sig); + arg_verity_settings.root_hash_sig = TAKE_STRUCT(p); break; } @@ -6358,7 +6356,7 @@ static int run(int argc, char *argv[]) { goto finish; } - if (dissected_image->has_verity && !arg_verity_settings.root_hash) + if (dissected_image->has_verity && !iovec_is_set(&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); diff --git a/src/repart/repart.c b/src/repart/repart.c index 456aed41bd7..698bbfab62c 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -5548,8 +5548,7 @@ static const VeritySettings *lookup_verity_settings_by_uuid_pair(sd_id128_t data memcpy(root_hash_key + sizeof(sd_id128_t), hash_uuid.bytes, sizeof(sd_id128_t)); VeritySettings key = { - .root_hash = &root_hash_key, - .root_hash_size = sizeof(root_hash_key), + .root_hash = IOVEC_MAKE(root_hash_key, sizeof(root_hash_key)), }; return set_get(arg_verity_settings, &key); @@ -5557,10 +5556,8 @@ static const VeritySettings *lookup_verity_settings_by_uuid_pair(sd_id128_t data static int partition_format_verity_sig(Context *context, Partition *p) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; - _cleanup_(iovec_done) struct iovec sig_free = {}; _cleanup_free_ char *text = NULL, *hint = NULL; const VeritySettings *verity_settings; - struct iovec roothash, sig; Partition *hp, *rp; uint8_t fp[X509_FINGERPRINT_SIZE]; int whole_fd, r; @@ -5600,22 +5597,18 @@ static int partition_format_verity_sig(Context *context, Partition *p) { assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0); + _cleanup_(iovec_done) struct iovec sig_free = {}; + const struct iovec *roothash, *sig; if (verity_settings) { - sig = (struct iovec) { - .iov_base = verity_settings->root_hash_sig, - .iov_len = verity_settings->root_hash_sig_size, - }; - roothash = (struct iovec) { - .iov_base = verity_settings->root_hash, - .iov_len = verity_settings->root_hash_size, - }; + sig = &verity_settings->root_hash_sig; + roothash = &verity_settings->root_hash; } else { r = sign_verity_roothash(context, &hp->roothash, &sig_free); if (r < 0) return r; - sig = sig_free; - roothash = hp->roothash; + sig = &sig_free; + roothash = &hp->roothash; } #if HAVE_OPENSSL @@ -5627,9 +5620,9 @@ static int partition_format_verity_sig(Context *context, Partition *p) { r = sd_json_buildo( &v, - SD_JSON_BUILD_PAIR("rootHash", SD_JSON_BUILD_HEX(roothash.iov_base, roothash.iov_len)), + SD_JSON_BUILD_PAIR("rootHash", SD_JSON_BUILD_HEX(roothash->iov_base, roothash->iov_len)), SD_JSON_BUILD_PAIR_CONDITION(has_fp, "certificateFingerprint", SD_JSON_BUILD_HEX(fp, sizeof(fp))), - SD_JSON_BUILD_PAIR("signature", JSON_BUILD_IOVEC_BASE64(&sig))); + SD_JSON_BUILD_PAIR("signature", JSON_BUILD_IOVEC_BASE64(sig))); if (r < 0) return log_error_errno(r, "Failed to build verity signature JSON object: %m"); @@ -8824,9 +8817,8 @@ static int parse_partition_types(const char *p, GptPartitionType **partitions, s static int parse_join_signature(const char *p, Set **verity_settings_map) { _cleanup_(verity_settings_freep) VeritySettings *verity_settings = NULL; _cleanup_free_ char *root_hash = NULL; - _cleanup_free_ void *content = NULL; const char *signature; - size_t len; + _cleanup_(iovec_done) struct iovec content = {}; int r; assert(p); @@ -8838,17 +8830,17 @@ static int parse_join_signature(const char *p, Set **verity_settings_map) { if (!p) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected hash:sig"); if ((signature = startswith(p, "base64:"))) { - r = unbase64mem(signature, &content, &len); + r = unbase64mem(signature, &content.iov_base, &content.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash signature '%s': %m", signature); } else { - r = read_full_file(p, (char**) &content, &len); + r = read_full_file(p, (char**) &content.iov_base, &content.iov_len); if (r < 0) return log_error_errno(r, "Failed to read root hash signature file '%s': %m", p); } - if (len == 0) + if (!iovec_is_set(&content)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty verity signature specified."); - if (len > VERITY_SIG_SIZE) + if (content.iov_len > VERITY_SIG_SIZE) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Verity signatures larger than %llu are not allowed.", VERITY_SIG_SIZE); @@ -8858,21 +8850,17 @@ static int parse_join_signature(const char *p, Set **verity_settings_map) { return log_oom(); *verity_settings = (VeritySettings) { - .root_hash_sig = TAKE_PTR(content), - .root_hash_sig_size = len, + .root_hash_sig = TAKE_STRUCT(content), }; - r = unhexmem(root_hash, &content, &len); + r = unhexmem(root_hash, &verity_settings->root_hash.iov_base, &verity_settings->root_hash.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash '%s': %m", root_hash); - if (len < sizeof(sd_id128_t)) + if (verity_settings->root_hash.iov_len < sizeof(sd_id128_t)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128-bit long: %s", root_hash); - verity_settings->root_hash = TAKE_PTR(content); - verity_settings->root_hash_size = len; - r = set_ensure_put(verity_settings_map, &verity_settings_hash_ops, verity_settings); if (r < 0) return log_error_errno(r, "Failed to add entry to hashmap: %m"); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 1162982f71c..ff59029f9f4 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -47,6 +47,7 @@ #include "image-policy.h" #include "import-util.h" #include "io-util.h" +#include "iovec-util.h" #include "json-util.h" #include "loop-util.h" #include "mkdir-label.h" @@ -572,16 +573,12 @@ static int acquire_sig_for_roothash( int fd, uint64_t partition_offset, uint64_t partition_size, - void **ret_root_hash, - size_t *ret_root_hash_size, - void **ret_root_hash_sig, - size_t *ret_root_hash_sig_size) { + struct iovec *ret_root_hash, + struct iovec *ret_root_hash_sig) { int r; assert(fd >= 0); - assert(!!ret_root_hash == !!ret_root_hash_size); - assert(!!ret_root_hash_sig == !!ret_root_hash_sig_size); if (partition_offset == UINT64_MAX || partition_size == UINT64_MAX) return -EINVAL; @@ -616,9 +613,8 @@ static int acquire_sig_for_roothash( if (!rh) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'rootHash' field."); - _cleanup_free_ void *root_hash = NULL; - size_t root_hash_size; - r = sd_json_variant_unhex(rh, &root_hash, &root_hash_size); + _cleanup_(iovec_done) struct iovec root_hash = {}; + r = sd_json_variant_unhex(rh, &root_hash.iov_base, &root_hash.iov_len); if (r < 0) return log_debug_errno(r, "Failed to parse root hash field: %m"); @@ -626,21 +622,16 @@ static int acquire_sig_for_roothash( if (!sig) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'signature' field."); - _cleanup_free_ void *root_hash_sig = NULL; - size_t root_hash_sig_size; - r = sd_json_variant_unbase64(sig, &root_hash_sig, &root_hash_sig_size); + _cleanup_(iovec_done) struct iovec root_hash_sig = {}; + r = sd_json_variant_unbase64(sig, &root_hash_sig.iov_base, &root_hash_sig.iov_len); if (r < 0) return log_debug_errno(r, "Failed to parse signature field: %m"); - if (ret_root_hash) { - *ret_root_hash = TAKE_PTR(root_hash); - *ret_root_hash_size = root_hash_size; - } + if (ret_root_hash) + *ret_root_hash = TAKE_STRUCT(root_hash); - if (ret_root_hash_sig) { - *ret_root_hash_sig = TAKE_PTR(root_hash_sig); - *ret_root_hash_sig_size = root_hash_sig_size; - } + if (ret_root_hash_sig) + *ret_root_hash_sig = TAKE_STRUCT(root_hash_sig); return 0; } @@ -828,9 +819,9 @@ static int dissect_image( assert(fd >= 0); assert(devname); assert(!verity || verity->designator < 0 || IN_SET(verity->designator, PARTITION_ROOT, PARTITION_USR)); - assert(!verity || verity->root_hash || verity->root_hash_size == 0); - assert(!verity || verity->root_hash_sig || verity->root_hash_sig_size == 0); - assert(!verity || (verity->root_hash || !verity->root_hash_sig)); + assert(!verity || iovec_is_valid(&verity->root_hash)); + assert(!verity || iovec_is_valid(&verity->root_hash_sig)); + assert(!verity || iovec_is_set(&verity->root_hash) || !iovec_is_set(&verity->root_hash_sig)); assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE))); assert(m->sector_size > 0); @@ -849,18 +840,18 @@ static int dissect_image( uint64_t diskseq = m->loop ? m->loop->diskseq : 0; - if (verity && verity->root_hash) { + if (verity && iovec_is_set(&verity->root_hash)) { sd_id128_t fsuuid, vuuid; /* If a root hash is supplied, then we use the root partition that has a UUID that match the * first 128-bit of the root hash. And we use the verity partition that has a UUID that match * the final 128-bit. */ - if (verity->root_hash_size < sizeof(sd_id128_t)) + if (verity->root_hash.iov_len < sizeof(sd_id128_t)) return -EINVAL; - memcpy(&fsuuid, verity->root_hash, sizeof(sd_id128_t)); - memcpy(&vuuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); + memcpy(&fsuuid, verity->root_hash.iov_base, sizeof(sd_id128_t)); + memcpy(&vuuid, (const uint8_t*) verity->root_hash.iov_base + verity->root_hash.iov_len - sizeof(sd_id128_t), sizeof(sd_id128_t)); if (sd_id128_is_null(fsuuid)) return -EINVAL; @@ -955,7 +946,7 @@ static int dissect_image( encrypted = streq_ptr(fstype, "crypto_LUKS"); if (verity_settings_data_covers(verity, PARTITION_ROOT)) - found_flags = verity->root_hash_sig_size > 0 ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY; + found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY; else found_flags = encrypted ? PARTITION_POLICY_ENCRYPTED : PARTITION_POLICY_UNPROTECTED; @@ -990,7 +981,7 @@ static int dissect_image( m->verity_ready = verity_settings_data_covers(verity, PARTITION_ROOT); m->has_verity_sig = false; /* signature not embedded, must be specified */ - m->verity_sig_ready = m->verity_ready && verity->root_hash_sig; + m->verity_sig_ready = m->verity_ready && iovec_is_set(&verity->root_hash); m->image_uuid = uuid; @@ -1236,26 +1227,23 @@ static int dissect_image( rw = false; } else if (type.designator == PARTITION_ROOT_VERITY_SIG) { - if (verity && verity->root_hash) { - _cleanup_free_ void *root_hash = NULL; - size_t root_hash_size; + if (verity && iovec_is_set(&verity->root_hash)) { + _cleanup_(iovec_done) struct iovec root_hash = {}; r = acquire_sig_for_roothash( fd, start * 512, size * 512, &root_hash, - &root_hash_size, - /* ret_root_hash_sig= */ NULL, - /* ret_root_hash_sig_size= */ NULL); + /* ret_root_hash_sig= */ NULL); if (r < 0) return r; - if (memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) { + if (iovec_memcmp(&verity->root_hash, &root_hash) != 0) { if (DEBUG_LOGGING) { _cleanup_free_ char *found = NULL, *expected = NULL; - found = hexmem(root_hash, root_hash_size); - expected = hexmem(verity->root_hash, verity->root_hash_size); + found = hexmem(root_hash.iov_base, root_hash.iov_len); + expected = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len); log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected)); } @@ -1305,26 +1293,23 @@ static int dissect_image( rw = false; } else if (type.designator == PARTITION_USR_VERITY_SIG) { - if (verity && verity->root_hash) { - _cleanup_free_ void *root_hash = NULL; - size_t root_hash_size; + if (verity && iovec_is_set(&verity->root_hash)) { + _cleanup_(iovec_done) struct iovec root_hash = {}; r = acquire_sig_for_roothash( fd, start * 512, size * 512, &root_hash, - &root_hash_size, - /* ret_root_hash_sig= */ NULL, - /* ret_root_hash_sig_size= */ NULL); + /* ret_root_hash_sig= */ NULL); if (r < 0) return r; - if (memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) { + if (iovec_memcmp(&verity->root_hash, &root_hash) != 0) { if (DEBUG_LOGGING) { _cleanup_free_ char *found = NULL, *expected = NULL; - found = hexmem(root_hash, root_hash_size); - expected = hexmem(verity->root_hash, verity->root_hash_size); + found = hexmem(root_hash.iov_base, root_hash.iov_len); + expected = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len); log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected)); } @@ -1609,7 +1594,7 @@ static int dissect_image( if (!m->partitions[PARTITION_ROOT].found && !m->partitions[PARTITION_USR].found && (flags & DISSECT_IMAGE_GENERIC_ROOT) && - (!verity || !verity->root_hash || verity->designator != PARTITION_USR)) { + (!verity || !iovec_is_set(&verity->root_hash) || verity->designator != PARTITION_USR)) { /* OK, we found nothing usable, then check if there's a single generic partition, and use * that. If the root hash was set however, then we won't fall back to a generic node, because @@ -1694,7 +1679,7 @@ static int dissect_image( partition_designator_to_string(verity->designator), partition_designator_to_string(verity->designator)); - if (verity->root_hash) { + if (iovec_is_set(&verity->root_hash)) { /* If we have an explicit root hash and found the partitions for it, then we are ready to use * Verity, set things up for it */ @@ -1730,7 +1715,7 @@ static int dissect_image( m->verity_ready = true; - if (verity->root_hash_sig) + if (iovec_is_set(&verity->root_hash_sig)) m->verity_sig_ready = true; } } @@ -2767,10 +2752,8 @@ static int verity_can_reuse( struct crypt_device **ret_cd) { /* If the same volume was already open, check that the root hashes match, and reuse it if they do */ - _cleanup_free_ char *root_hash_existing = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; struct crypt_params_verity crypt_params = {}; - size_t root_hash_existing_size; int r; assert(verity); @@ -2787,22 +2770,23 @@ static int verity_can_reuse( if (r < 0) return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m"); - root_hash_existing_size = verity->root_hash_size; - root_hash_existing = malloc0(root_hash_existing_size); - if (!root_hash_existing) + _cleanup_(iovec_done) struct iovec root_hash_existing = { + .iov_base = malloc0(verity->root_hash.iov_len), + .iov_len = verity->root_hash.iov_len, + }; + if (!root_hash_existing.iov_base) return -ENOMEM; - r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0); + r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing.iov_base, &root_hash_existing.iov_len, NULL, 0); if (r < 0) return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m"); - if (verity->root_hash_size != root_hash_existing_size || - memcmp(root_hash_existing, verity->root_hash, verity->root_hash_size) != 0) + if (iovec_memcmp(&verity->root_hash, &root_hash_existing) != 0) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but root hashes are different."); /* Ensure that, if signatures are supported, we only reuse the device if the previous mount used the * same settings, so that a previous unsigned mount will not be reused if the user asks to use * signing for the new one, and vice versa. */ - if (!!verity->root_hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) + if (iovec_is_set(&verity->root_hash_sig) != FLAGS_SET(crypt_params.flags, CRYPT_VERITY_ROOT_HASH_SIGNATURE)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but signature settings are not the same."); *ret_cd = TAKE_PTR(cd); @@ -2856,11 +2840,9 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma _cleanup_free_ char *s = NULL; _cleanup_(BIO_freep) BIO *bio = NULL; /* 'bio' must be freed first, 's' second, hence keep this order * of declaration in place, please */ - const unsigned char *d; - assert(verity); - assert(verity->root_hash); - assert(verity->root_hash_sig); + assert(iovec_is_set(&verity->root_hash)); + assert(iovec_is_set(&verity->root_hash_sig)); /* Because installing a signature certificate into the kernel chain is so messy, let's optionally do * userspace validation. */ @@ -2873,12 +2855,12 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma return 0; } - d = verity->root_hash_sig; - p7 = d2i_PKCS7(NULL, &d, (long) verity->root_hash_sig_size); + const unsigned char *d = verity->root_hash_sig.iov_base; + p7 = d2i_PKCS7(NULL, &d, (long) verity->root_hash_sig.iov_len); if (!p7) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PKCS7 DER signature data."); - s = hexmem(verity->root_hash, verity->root_hash_size); + s = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len); if (!s) return log_oom_debug(); @@ -2939,7 +2921,7 @@ static int do_crypt_activate_verity( assert(name); assert(verity); - if (verity->root_hash_sig && FLAGS_SET(policy_flags, PARTITION_POLICY_SIGNED)) { + if (iovec_is_set(&verity->root_hash_sig) && FLAGS_SET(policy_flags, PARTITION_POLICY_SIGNED)) { r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_SIGNATURE"); if (r < 0 && r != -ENXIO) log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_SIGNATURE"); @@ -2953,10 +2935,10 @@ static int do_crypt_activate_verity( r = sym_crypt_activate_by_signed_key( cd, name, - verity->root_hash, - verity->root_hash_size, - verity->root_hash_sig, - verity->root_hash_sig_size, + verity->root_hash.iov_base, + verity->root_hash.iov_len, + verity->root_hash_sig.iov_base, + verity->root_hash_sig.iov_len, CRYPT_ACTIVATE_READONLY); if (r >= 0) { log_debug("Verity activation via kernel signature logic worked."); @@ -3000,8 +2982,8 @@ static int do_crypt_activate_verity( r = sym_crypt_activate_by_volume_key( cd, name, - verity->root_hash, - verity->root_hash_size, + verity->root_hash.iov_base, + verity->root_hash.iov_len, CRYPT_ACTIVATE_READONLY); if (r < 0) return log_debug_errno(r, "Activation of Verity via root hash failed: %m"); @@ -3049,7 +3031,7 @@ static int verity_partition( assert(m); assert(v || (verity && verity->data_path)); - if (!verity || !verity->root_hash) + if (!verity || !iovec_is_set(&verity->root_hash)) return 0; if (!((verity->designator < 0 && designator == PARTITION_ROOT) || (verity->designator == designator))) @@ -3078,7 +3060,7 @@ static int verity_partition( /* Use the roothash, which is unique per volume, as the device node name, so that it can be reused */ _cleanup_free_ char *root_hash_encoded = NULL; - root_hash_encoded = hexmem(verity->root_hash, verity->root_hash_size); + root_hash_encoded = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len); if (!root_hash_encoded) return -ENOMEM; @@ -3246,7 +3228,8 @@ int dissected_image_decrypt( int r; assert(m); - assert(!verity || verity->root_hash || verity->root_hash_size == 0); + assert(!verity || iovec_is_valid(&verity->root_hash)); + assert(!verity || iovec_is_valid(&verity->root_hash_sig)); /* Returns: * @@ -3260,7 +3243,7 @@ int dissected_image_decrypt( * -EEXIST → DM device already exists under the specified name */ - if (verity && verity->root_hash && verity->root_hash_size < sizeof(sd_id128_t)) + if (verity && iovec_is_set(&verity->root_hash) && verity->root_hash.iov_len < sizeof(sd_id128_t)) return -EINVAL; if (!m->encrypted && !m->verity_ready) @@ -3487,12 +3470,8 @@ static char *build_auxiliary_path(const char *image, const char *suffix) { void verity_settings_done(VeritySettings *v) { assert(v); - v->root_hash = mfree(v->root_hash); - v->root_hash_size = 0; - - v->root_hash_sig = mfree(v->root_hash_sig); - v->root_hash_sig_size = 0; - + iovec_done(&v->root_hash); + iovec_done(&v->root_hash_sig); v->data_path = mfree(v->data_path); } @@ -3507,18 +3486,15 @@ VeritySettings* verity_settings_free(VeritySettings *v) { void verity_settings_hash_func(const VeritySettings *s, struct siphash *state) { assert(s); - siphash24_compress_typesafe(s->root_hash_size, state); - siphash24_compress(s->root_hash, s->root_hash_size, state); + siphash24_compress_typesafe(s->root_hash.iov_len, state); + siphash24_compress(s->root_hash.iov_base, s->root_hash.iov_len, state); } int verity_settings_compare_func(const VeritySettings *x, const VeritySettings *y) { - int r; + assert(x); + assert(y); - r = CMP(x->root_hash_size, y->root_hash_size); - if (r != 0) - return r; - - return memcmp(x->root_hash, y->root_hash, x->root_hash_size); + return iovec_memcmp(&x->root_hash, &y->root_hash); } DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(verity_settings_hash_ops, VeritySettings, verity_settings_hash_func, verity_settings_compare_func, VeritySettings, verity_settings_free); @@ -3529,9 +3505,6 @@ int verity_settings_load( const char *root_hash_path, const char *root_hash_sig_path) { - _cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL; - size_t root_hash_size = 0, root_hash_sig_size = 0; - _cleanup_free_ char *verity_data_path = NULL; PartitionDesignator designator; int r; @@ -3553,7 +3526,8 @@ int verity_settings_load( /* We only fill in what isn't already filled in */ - if (!verity->root_hash) { + _cleanup_(iovec_done) struct iovec root_hash = {}; + if (!iovec_is_set(&verity->root_hash)) { _cleanup_free_ char *text = NULL; if (root_hash_path) { @@ -3620,20 +3594,24 @@ int verity_settings_load( } if (text) { - r = unhexmem(text, &root_hash, &root_hash_size); + r = unhexmem(text, &root_hash.iov_base, &root_hash.iov_len); if (r < 0) return r; - if (root_hash_size < sizeof(sd_id128_t)) + if (root_hash.iov_len < sizeof(sd_id128_t)) return -EINVAL; } } - if ((root_hash || verity->root_hash) && !verity->root_hash_sig) { + _cleanup_(iovec_done) struct iovec root_hash_sig = {}; + if ((iovec_is_set(&root_hash) || iovec_is_set(&verity->root_hash)) && !iovec_is_set(&verity->root_hash_sig)) { if (root_hash_sig_path) { - r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len); if (r < 0 && r != -ENOENT) return r; + if (r >= 0 && root_hash_sig.iov_len == 0) /* refuse empty size signatures */ + return -EINVAL; + if (designator < 0) designator = PARTITION_ROOT; } else { @@ -3646,32 +3624,36 @@ int verity_settings_load( if (!p) return -ENOMEM; - r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(p, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len); if (r < 0 && r != -ENOENT) return r; - if (r >= 0) + if (r >= 0) { designator = PARTITION_ROOT; + if (root_hash_sig.iov_len == 0) /* refuse empty size signatures */ + return -EINVAL; + } } - if (!root_hash_sig && (designator < 0 || designator == PARTITION_USR)) { + if (!iovec_is_set(&root_hash_sig) && (designator < 0 || designator == PARTITION_USR)) { _cleanup_free_ char *p = NULL; p = build_auxiliary_path(image, ".usrhash.p7s"); if (!p) return -ENOMEM; - r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(p, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len); if (r < 0 && r != -ENOENT) return r; - if (r >= 0) + if (r >= 0) { designator = PARTITION_USR; + if (root_hash_sig.iov_len == 0) /* refuse empty size signatures */ + return -EINVAL; + } } } - - if (root_hash_sig && root_hash_sig_size == 0) /* refuse empty size signatures */ - return -EINVAL; } + _cleanup_free_ char *verity_data_path = NULL; if (!verity->data_path) { _cleanup_free_ char *p = NULL; @@ -3686,15 +3668,11 @@ int verity_settings_load( verity_data_path = TAKE_PTR(p); } - if (root_hash) { - verity->root_hash = TAKE_PTR(root_hash); - verity->root_hash_size = root_hash_size; - } + if (iovec_is_set(&root_hash)) + verity->root_hash = TAKE_STRUCT(root_hash); - if (root_hash_sig) { - verity->root_hash_sig = TAKE_PTR(root_hash_sig); - verity->root_hash_sig_size = root_hash_sig_size; - } + if (iovec_is_set(&root_hash_sig)) + verity->root_hash_sig = TAKE_STRUCT(root_hash_sig); if (verity_data_path) verity->data_path = TAKE_PTR(verity_data_path); @@ -3713,17 +3691,15 @@ int verity_settings_copy(VeritySettings *dest, const VeritySettings *source) { return 0; } - _cleanup_free_ void *rh = NULL; - if (source->root_hash_size > 0) { - rh = memdup(source->root_hash, source->root_hash_size); - if (!rh) + _cleanup_(iovec_done) struct iovec rh = {}; + if (iovec_is_set(&source->root_hash)) { + if (!iovec_memdup(&source->root_hash, &rh)) return log_oom_debug(); } - _cleanup_free_ void *sig = NULL; - if (source->root_hash_sig_size > 0) { - sig = memdup(source->root_hash_sig, source->root_hash_sig_size); - if (!sig) + _cleanup_(iovec_done) struct iovec sig = {}; + if (iovec_is_set(&source->root_hash_sig)) { + if (!iovec_memdup(&source->root_hash_sig, &sig)) return log_oom_debug(); } @@ -3735,10 +3711,8 @@ int verity_settings_copy(VeritySettings *dest, const VeritySettings *source) { } *dest = (VeritySettings) { - .root_hash = TAKE_PTR(rh), - .root_hash_size = source->root_hash_size, - .root_hash_sig = TAKE_PTR(sig), - .root_hash_sig_size = source->root_hash_sig_size, + .root_hash = TAKE_STRUCT(rh), + .root_hash_sig = TAKE_STRUCT(sig), .data_path = TAKE_PTR(p), .designator = source->designator, }; @@ -3757,7 +3731,7 @@ int dissected_image_load_verity_sig_partition( assert(fd >= 0); assert(verity); - if (verity->root_hash && verity->root_hash_sig) /* Already loaded? */ + if (iovec_is_set(&verity->root_hash) && iovec_is_set(&verity->root_hash_sig)) /* Already loaded? */ return 0; r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_EMBEDDED"); @@ -3791,29 +3765,32 @@ int dissected_image_load_verity_sig_partition( if (!p->found) return 0; - _cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL; - size_t root_hash_size, root_hash_sig_size; - - r = acquire_sig_for_roothash(fd, p->offset, p->size, &root_hash, &root_hash_size, &root_hash_sig, &root_hash_sig_size); + _cleanup_(iovec_done) struct iovec root_hash = {}, root_hash_sig = {}; + r = acquire_sig_for_roothash( + fd, + p->offset, + p->size, + &root_hash, + &root_hash_sig); if (r < 0) return r; /* Check if specified root hash matches if it is specified */ - if (verity->root_hash && - memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) { + if (iovec_is_set(&verity->root_hash) && + iovec_memcmp(&verity->root_hash, &root_hash) != 0) { _cleanup_free_ char *a = NULL, *b = NULL; - a = hexmem(root_hash, root_hash_size); - b = hexmem(verity->root_hash, verity->root_hash_size); + a = hexmem(root_hash.iov_base, root_hash.iov_len); + b = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len); return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(a), strna(b)); } - free_and_replace(verity->root_hash, root_hash); - verity->root_hash_size = root_hash_size; + iovec_done(&verity->root_hash); + verity->root_hash = TAKE_STRUCT(root_hash); - free_and_replace(verity->root_hash_sig, root_hash_sig); - verity->root_hash_sig_size = root_hash_sig_size; + iovec_done(&verity->root_hash_sig); + verity->root_hash_sig = TAKE_STRUCT(root_hash_sig); verity->designator = dd; @@ -3841,7 +3818,7 @@ int dissected_image_guess_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? */ + if (iovec_is_set(&verity->root_hash)) /* Already loaded? */ return 0; r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_GUESS"); @@ -3871,13 +3848,12 @@ int dissected_image_guess_verity_roothash( if (!p->found) return 0; - _cleanup_free_ uint8_t *rh = malloc(sizeof(sd_id128_t) * 2); + _cleanup_free_ void *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->root_hash = IOVEC_MAKE(TAKE_PTR(rh), sizeof(sd_id128_t) * 2); verity->designator = dd; @@ -4838,8 +4814,8 @@ int mountfsd_mount_image( SD_JSON_BUILD_PAIR_CONDITION(!!ps, "imagePolicy", SD_JSON_BUILD_STRING(ps)), SD_JSON_BUILD_PAIR("veritySharing", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))), SD_JSON_BUILD_PAIR_CONDITION(verity_data_fd >= 0, "verityDataFileDescriptor", SD_JSON_BUILD_UNSIGNED(userns_fd >= 0 ? 2 : 1)), - JSON_BUILD_PAIR_IOVEC_HEX("verityRootHash", &((struct iovec) { .iov_base = verity->root_hash, .iov_len = verity->root_hash_size })), - JSON_BUILD_PAIR_IOVEC_BASE64("verityRootHashSignature", &((struct iovec) { .iov_base = verity->root_hash_sig, .iov_len = verity->root_hash_sig_size })), + JSON_BUILD_PAIR_IOVEC_HEX("verityRootHash", &verity->root_hash), + JSON_BUILD_PAIR_IOVEC_BASE64("verityRootHashSignature", &verity->root_hash_sig), SD_JSON_BUILD_PAIR("allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH)))); if (r < 0) return r; diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 48d23599601..0e9732a923f 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -4,9 +4,10 @@ #include "sd-id128.h" #include "architecture.h" -#include "shared-forward.h" #include "gpt.h" +#include "iovec-util.h" #include "list.h" +#include "shared-forward.h" typedef struct DecryptedImage DecryptedImage; @@ -120,12 +121,10 @@ typedef struct MountOptions { typedef struct VeritySettings { /* Binary root hash for the Verity Merkle tree */ - void *root_hash; - size_t root_hash_size; + struct iovec root_hash; /* PKCS#7 signature of the above */ - void *root_hash_sig; - size_t root_hash_sig_size; + struct iovec root_hash_sig; /* Path to the verity data file, if stored externally */ char *data_path; @@ -206,9 +205,9 @@ int verity_settings_load(VeritySettings *verity, const char *image, const char * static inline bool verity_settings_set(const VeritySettings *settings) { return settings && - (settings->root_hash_size > 0 || - (settings->root_hash_sig_size > 0 || - settings->data_path)); + (iovec_is_set(&settings->root_hash) || + iovec_is_set(&settings->root_hash_sig) || + settings->data_path); } void verity_settings_done(VeritySettings *verity); @@ -223,7 +222,7 @@ static inline bool verity_settings_data_covers(const VeritySettings *verity, Par /* Returns true if the verity settings contain sufficient information to cover the specified partition */ return verity && ((d >= 0 && verity->designator == d) || (d == PARTITION_ROOT && verity->designator < 0)) && - verity->root_hash && + iovec_is_set(&verity->root_hash) && verity->data_path; } diff --git a/src/udev/udev-builtin-dissect_image.c b/src/udev/udev-builtin-dissect_image.c index 32aea19a6fb..1f3728d2293 100644 --- a/src/udev/udev-builtin-dissect_image.c +++ b/src/udev/udev-builtin-dissect_image.c @@ -74,7 +74,7 @@ static int acquire_verity_settings(VeritySettings *ret) { } if (h) { - r = unhexmem(h, &verity.root_hash, &verity.root_hash_size); + r = unhexmem(h, &verity.root_hash.iov_base, &verity.root_hash.iov_len); if (r < 0) return log_error_errno(r, "Failed to parse root hash from kernel command line switch: %m"); } @@ -301,25 +301,25 @@ static int verb_probe(UdevEvent *event, sd_device *dev) { } if (d == verity.designator) { - if (verity.root_hash_size > 0) { + if (iovec_is_set(&verity.root_hash)) { _cleanup_free_ char *f = NULL; if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH", p->partno) < 0) return log_oom_debug(); - _cleanup_free_ char *h = hexmem(verity.root_hash, verity.root_hash_size); + _cleanup_free_ char *h = hexmem(verity.root_hash.iov_base, verity.root_hash.iov_len); if (!h) return log_oom_debug(); (void) udev_builtin_add_property(event, f, h); } - if (verity.root_hash_sig_size > 0) { + if (iovec_is_set(&verity.root_hash_sig)) { _cleanup_free_ char *f = NULL; if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH_SIG", p->partno) < 0) return log_oom_debug(); _cleanup_free_ char *h = NULL; - if (base64mem(verity.root_hash_sig, verity.root_hash_sig_size, &h) < 0) + if (base64mem(verity.root_hash_sig.iov_base, verity.root_hash_sig.iov_len, &h) < 0) return log_oom_debug(); (void) udev_builtin_add_property(event, f, h);