diff --git a/src/core/namespace.c b/src/core/namespace.c index 5a5095ee0a5..8932785239d 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -942,32 +942,51 @@ static int mount_images(const MountEntry *m) { _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; - _cleanup_free_ void *root_hash_decoded = NULL; - _cleanup_free_ char *verity_data = NULL, *hash_sig = NULL; - DissectImageFlags dissect_image_flags = m->read_only ? DISSECT_IMAGE_READ_ONLY : 0; - size_t root_hash_size = 0; + _cleanup_(verity_settings_done) VeritySettings verity = {}; + DissectImageFlags dissect_image_flags; int r; - r = verity_metadata_load(mount_entry_source(m), NULL, &root_hash_decoded, &root_hash_size, &verity_data, &hash_sig); + assert(m); + + r = verity_settings_load(&verity, mount_entry_source(m), NULL, NULL); if (r < 0) return log_debug_errno(r, "Failed to load root hash: %m"); - dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0; - r = loop_device_make_by_path(mount_entry_source(m), - m->read_only ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */, - verity_data ? 0 : LO_FLAGS_PARTSCAN, - &loop_device); + dissect_image_flags = + (m->read_only ? DISSECT_IMAGE_READ_ONLY : 0) | + (verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0); + + r = loop_device_make_by_path( + mount_entry_source(m), + m->read_only ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */, + verity.data_path ? 0 : LO_FLAGS_PARTSCAN, + &loop_device); if (r < 0) return log_debug_errno(r, "Failed to create loop device for image: %m"); - r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, m->image_options, dissect_image_flags, &dissected_image); + r = dissect_image( + loop_device->fd, + &verity, + m->image_options, + dissect_image_flags, + &dissected_image); /* No partition table? Might be a single-filesystem image, try again */ - if (!verity_data && r < 0 && r == -ENOPKG) - r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, m->image_options, dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, &dissected_image); + if (!verity.data_path && r == -ENOPKG) + r = dissect_image( + loop_device->fd, + &verity, + m->image_options, + dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, + &dissected_image); if (r < 0) return log_debug_errno(r, "Failed to dissect image: %m"); - r = dissected_image_decrypt(dissected_image, NULL, root_hash_decoded, root_hash_size, verity_data, hash_sig, NULL, 0, dissect_image_flags, &decrypted_image); + r = dissected_image_decrypt( + dissected_image, + NULL, + &verity, + dissect_image_flags, + &decrypted_image); if (r < 0) return log_debug_errno(r, "Failed to decrypt dissected image: %m"); @@ -1374,6 +1393,60 @@ static bool home_read_only( return false; } +static int verity_settings_prepare( + VeritySettings *verity, + const char *root_image, + const void *root_hash, + size_t root_hash_size, + const char *root_hash_path, + const void *root_hash_sig, + size_t root_hash_sig_size, + const char *root_hash_sig_path, + const char *verity_data_path) { + + int r; + + assert(verity); + + if (root_hash) { + void *d; + + d = memdup(root_hash, root_hash_size); + if (!d) + return -ENOMEM; + + free_and_replace(verity->root_hash, d); + verity->root_hash_size = root_hash_size; + } + + if (root_hash_sig) { + void *d; + + d = memdup(root_hash_sig, root_hash_sig_size); + if (!d) + return -ENOMEM; + + free_and_replace(verity->root_hash_sig, d); + verity->root_hash_sig_size = root_hash_sig_size; + } + + if (verity_data_path) { + r = free_and_strdup(&verity->data_path, verity_data_path); + if (r < 0) + return r; + } + + r = verity_settings_load( + verity, + root_image, + root_hash_path, + root_hash_sig_path); + if (r < 0) + return log_debug_errno(r, "Failed to load root hash: %m"); + + return 0; +} + int setup_namespace( const char* root_directory, const char* root_image, @@ -1400,20 +1473,19 @@ int setup_namespace( const void *root_hash_sig, size_t root_hash_sig_size, const char *root_hash_sig_path, - const char *root_verity, + const char *verity_data_path, DissectImageFlags dissect_image_flags, char **error_path) { _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; - _cleanup_free_ void *root_hash_decoded = NULL; - _cleanup_free_ char *verity_data = NULL, *hash_sig_path = NULL; + _cleanup_(verity_settings_done) VeritySettings verity = {}; MountEntry *m = NULL, *mounts = NULL; - size_t n_mounts; bool require_prefix = false; const char *root; - int r = 0; + size_t n_mounts; + int r; assert(ns_info); @@ -1432,43 +1504,40 @@ int setup_namespace( strv_isempty(read_write_paths)) dissect_image_flags |= DISSECT_IMAGE_READ_ONLY; - r = loop_device_make_by_path(root_image, - FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */, - LO_FLAGS_PARTSCAN, - &loop_device); + r = verity_settings_prepare( + &verity, + root_image, + root_hash, root_hash_size, root_hash_path, + root_hash_sig, root_hash_sig_size, root_hash_sig_path, + verity_data_path); + if (r < 0) + return r; + + SET_FLAG(dissect_image_flags, DISSECT_IMAGE_NO_PARTITION_TABLE, verity.data_path); + + r = loop_device_make_by_path( + root_image, + FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */, + FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN, + &loop_device); if (r < 0) return log_debug_errno(r, "Failed to create loop device for root image: %m"); - r = verity_metadata_load(root_image, - root_hash_path, - root_hash ? NULL : &root_hash_decoded, - root_hash ? NULL : &root_hash_size, - root_verity ? NULL : &verity_data, - root_hash_sig || root_hash_sig_path ? NULL : &hash_sig_path); - if (r < 0) - return log_debug_errno(r, "Failed to load root hash: %m"); - dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0; - - r = dissect_image(loop_device->fd, - root_hash ?: root_hash_decoded, - root_hash_size, - root_verity ?: verity_data, - root_image_options, - dissect_image_flags, - &dissected_image); + r = dissect_image( + loop_device->fd, + &verity, + root_image_options, + dissect_image_flags, + &dissected_image); if (r < 0) return log_debug_errno(r, "Failed to dissect image: %m"); - r = dissected_image_decrypt(dissected_image, - NULL, - root_hash ?: root_hash_decoded, - root_hash_size, - root_verity ?: verity_data, - root_hash_sig_path ?: hash_sig_path, - root_hash_sig, - root_hash_sig_size, - dissect_image_flags, - &decrypted_image); + r = dissected_image_decrypt( + dissected_image, + NULL, + &verity, + dissect_image_flags, + &decrypted_image); if (r < 0) return log_debug_errno(r, "Failed to decrypt dissected image: %m"); } diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 239bddc9c73..14cdad82b5f 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -11,6 +11,7 @@ #include "copy.h" #include "dissect-image.h" #include "fd-util.h" +#include "fileio.h" #include "format-table.h" #include "format-util.h" #include "fs-util.h" @@ -43,19 +44,11 @@ static const char *arg_path = NULL; static const char *arg_source = NULL; static const char *arg_target = NULL; static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK; -static void *arg_root_hash = NULL; -static char *arg_verity_data = NULL; -static size_t arg_root_hash_size = 0; -static char *arg_root_hash_sig_path = NULL; -static void *arg_root_hash_sig = NULL; -static size_t arg_root_hash_sig_size = 0; +static VeritySettings arg_verity_settings = {}; static bool arg_json = false; static JsonFormatFlags arg_json_format_flags = 0; -STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep); -STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep); -STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep); -STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep); +STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done); static int help(void) { _cleanup_free_ char *link = NULL; @@ -105,10 +98,10 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_DISCARD, - ARG_ROOT_HASH, ARG_FSCK, - ARG_VERITY_DATA, + ARG_ROOT_HASH, ARG_ROOT_HASH_SIG, + ARG_VERITY_DATA, ARG_MKDIR, ARG_JSON, }; @@ -119,10 +112,10 @@ static int parse_argv(int argc, char *argv[]) { { "mount", no_argument, NULL, 'm' }, { "read-only", no_argument, NULL, 'r' }, { "discard", required_argument, NULL, ARG_DISCARD }, - { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, { "fsck", required_argument, NULL, ARG_FSCK }, - { "verity-data", required_argument, NULL, ARG_VERITY_DATA }, + { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG }, + { "verity-data", required_argument, NULL, ARG_VERITY_DATA }, { "mkdir", no_argument, NULL, ARG_MKDIR }, { "copy-from", no_argument, NULL, 'x' }, { "copy-to", no_argument, NULL, 'a' }, @@ -199,55 +192,47 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_ROOT_HASH: { - void *p; + _cleanup_free_ void *p = NULL; size_t l; r = unhexmem(optarg, strlen(optarg), &p, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash '%s': %m", optarg); - if (l < sizeof(sd_id128_t)) { - log_error("Root hash must be at least 128bit long: %s", optarg); - free(p); - return -EINVAL; + if (l < sizeof(sd_id128_t)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Root hash must be at least 128bit long: %s", optarg); + + free_and_replace(arg_verity_settings.root_hash, p); + arg_verity_settings.root_hash_size = l; + break; + } + + case ARG_ROOT_HASH_SIG: { + char *value; + size_t l; + void *p; + + if ((value = startswith(optarg, "base64:"))) { + r = unbase64mem(value, strlen(value), &p, &l); + 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); + if (r < 0) + return log_error_errno(r, "Failed to read root hash signature file '%s': %m", optarg); } - free(arg_root_hash); - arg_root_hash = p; - arg_root_hash_size = l; + free_and_replace(arg_verity_settings.root_hash_sig, p); + arg_verity_settings.root_hash_sig_size = l; break; } case ARG_VERITY_DATA: - r = parse_path_argument_and_warn(optarg, false, &arg_verity_data); + r = parse_path_argument_and_warn(optarg, false, &arg_verity_settings.data_path); if (r < 0) return r; break; - case ARG_ROOT_HASH_SIG: { - char *value; - - if ((value = startswith(optarg, "base64:"))) { - void *p; - size_t l; - - r = unbase64mem(value, strlen(value), &p, &l); - if (r < 0) - return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg); - - free_and_replace(arg_root_hash_sig, p); - arg_root_hash_sig_size = l; - arg_root_hash_sig_path = mfree(arg_root_hash_sig_path); - } else { - r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path); - if (r < 0) - return r; - arg_root_hash_sig = mfree(arg_root_hash_sig); - arg_root_hash_sig_size = 0; - } - - break; - } - case ARG_FSCK: r = parse_boolean(optarg); if (r < 0) @@ -483,7 +468,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { if (r < 0) return table_log_add_error(r); - if (arg_verity_data) + if (arg_verity_settings.data_path) r = table_add_cell(t, NULL, TABLE_STRING, "external"); else if (dissected_image_can_do_verity(m, i)) r = table_add_cell(t, NULL, TABLE_STRING, yes_no(dissected_image_has_verity(m, i))); @@ -539,9 +524,7 @@ static int action_mount(DissectedImage *m, LoopDevice *d) { r = dissected_image_decrypt_interactively( m, NULL, - arg_root_hash, arg_root_hash_size, - arg_verity_data, - arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, + &arg_verity_settings, arg_flags, &di); if (r < 0) @@ -573,9 +556,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) { r = dissected_image_decrypt_interactively( m, NULL, - arg_root_hash, arg_root_hash_size, - arg_verity_data, - arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, + &arg_verity_settings, arg_flags, &di); if (r < 0) @@ -739,34 +720,30 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - r = verity_metadata_load( - arg_image, NULL, - arg_root_hash ? NULL : &arg_root_hash, - &arg_root_hash_size, - arg_verity_data ? NULL : &arg_verity_data, - arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path); + r = verity_settings_load( + &arg_verity_settings, + arg_image, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to read verity artifacts for %s: %m", arg_image); - r = loop_device_make_by_path( - arg_image, - (arg_flags & DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR, - arg_verity_data ? 0 : LO_FLAGS_PARTSCAN, - &d); - if (r < 0) - return log_error_errno(r, "Failed to set up loopback device: %m"); - - if (arg_verity_data) + if (arg_verity_settings.data_path) arg_flags |= DISSECT_IMAGE_NO_PARTITION_TABLE; /* We only support Verity per file system, * hence if there's external Verity data * available we turn off partition table * support */ + + r = loop_device_make_by_path( + arg_image, + FLAGS_SET(arg_flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR, + FLAGS_SET(arg_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN, + &d); + if (r < 0) + return log_error_errno(r, "Failed to set up loopback device: %m"); + r = dissect_image_and_warn( d->fd, arg_image, - arg_root_hash, - arg_root_hash_size, - arg_verity_data, + &arg_verity_settings, NULL, arg_flags, &m); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 16086c8b86c..0d18c91c629 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -665,7 +665,7 @@ static int enumerate_partitions(dev_t devnum) { if (r <= 0) return r; - r = dissect_image(fd, NULL, 0, NULL, NULL, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m); + r = dissect_image(fd, NULL, NULL, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m); if (r == -ENOPKG) { log_debug_errno(r, "No suitable partition table found, ignoring."); return 0; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 26469759d90..38339478e00 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -199,12 +199,7 @@ static bool arg_notify_ready = false; static bool arg_use_cgns = true; static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS; static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP; -static void *arg_root_hash = NULL; -static char *arg_verity_data = NULL; -static char *arg_root_hash_sig_path = NULL; -static void *arg_root_hash_sig = NULL; -static size_t arg_root_hash_sig_size = 0; -static size_t arg_root_hash_size = 0; +static VeritySettings arg_verity_settings = {}; static char **arg_syscall_allow_list = NULL; static char **arg_syscall_deny_list = NULL; #if HAVE_SECCOMP @@ -248,10 +243,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_oci_bundle, freep); STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp); STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep); -STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep); -STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep); -STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep); -STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep); +STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done); STATIC_DESTRUCTOR_REGISTER(arg_syscall_allow_list, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_syscall_deny_list, strv_freep); #if HAVE_SECCOMP @@ -672,6 +664,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_PRIVATE_USERS_CHOWN, ARG_NOTIFY_READY, ARG_ROOT_HASH, + ARG_ROOT_HASH_SIG, + ARG_VERITY_DATA, ARG_SYSTEM_CALL_FILTER, ARG_RLIMIT, ARG_HOSTNAME, @@ -684,8 +678,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_PIPE, ARG_OCI_BUNDLE, ARG_NO_PAGER, - ARG_VERITY_DATA, - ARG_ROOT_HASH_SIG, ARG_SET_CREDENTIAL, ARG_LOAD_CREDENTIAL, }; @@ -743,6 +735,8 @@ static int parse_argv(int argc, char *argv[]) { { "pivot-root", required_argument, NULL, ARG_PIVOT_ROOT }, { "notify-ready", required_argument, NULL, ARG_NOTIFY_READY }, { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, + { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG }, + { "verity-data", required_argument, NULL, ARG_VERITY_DATA }, { "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER }, { "rlimit", required_argument, NULL, ARG_RLIMIT }, { "oom-score-adjust", required_argument, NULL, ARG_OOM_SCORE_ADJUST }, @@ -753,8 +747,6 @@ static int parse_argv(int argc, char *argv[]) { { "pipe", no_argument, NULL, ARG_PIPE }, { "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "verity-data", required_argument, NULL, ARG_VERITY_DATA }, - { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG }, { "set-credential", required_argument, NULL, ARG_SET_CREDENTIAL }, { "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL }, {} @@ -1328,54 +1320,47 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT_HASH: { - void *k; + _cleanup_free_ void *k = NULL; size_t l; r = unhexmem(optarg, strlen(optarg), &k, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash: %s", optarg); - if (l < sizeof(sd_id128_t)) { - free(k); + if (l < sizeof(sd_id128_t)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128bit long: %s", optarg); - } - free(arg_root_hash); - arg_root_hash = k; - arg_root_hash_size = l; + free_and_replace(arg_verity_settings.root_hash, k); + arg_verity_settings.root_hash_size = l; break; } - case ARG_VERITY_DATA: - r = parse_path_argument_and_warn(optarg, false, &arg_verity_data); - if (r < 0) - return r; - break; - case ARG_ROOT_HASH_SIG: { char *value; + size_t l; + void *p; if ((value = startswith(optarg, "base64:"))) { - void *p; - size_t l; - r = unbase64mem(value, strlen(value), &p, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg); - free_and_replace(arg_root_hash_sig, p); - arg_root_hash_sig_size = l; - arg_root_hash_sig_path = mfree(arg_root_hash_sig_path); } else { - r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path); + r = read_full_file(optarg, (char**) &p, &l); if (r < 0) - return r; - arg_root_hash_sig = mfree(arg_root_hash_sig); - arg_root_hash_sig_size = 0; + return log_error_errno(r, "Failed 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; break; } + case ARG_VERITY_DATA: + r = parse_path_argument_and_warn(optarg, false, &arg_verity_settings.data_path); + if (r < 0) + return r; + break; + case ARG_SYSTEM_CALL_FILTER: { bool negative; const char *items; @@ -5375,14 +5360,16 @@ static int run(int argc, char *argv[]) { goto finish; } - r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size, - arg_verity_data ? NULL : &arg_verity_data, - arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path); + r = verity_settings_load( + &arg_verity_settings, + arg_image, NULL, NULL); if (r < 0) { log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image); goto finish; } - dissect_image_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0; + + if (arg_verity_settings.data_path) + dissect_image_flags |= DISSECT_IMAGE_NO_PARTITION_TABLE; } if (!mkdtemp(tmprootdir)) { @@ -5398,7 +5385,11 @@ static int run(int argc, char *argv[]) { goto finish; } - r = loop_device_make_by_path(arg_image, arg_read_only ? O_RDONLY : O_RDWR, LO_FLAGS_PARTSCAN, &loop); + r = loop_device_make_by_path( + arg_image, + arg_read_only ? O_RDONLY : O_RDWR, + FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN, + &loop); if (r < 0) { log_error_errno(r, "Failed to set up loopback block device: %m"); goto finish; @@ -5407,8 +5398,7 @@ static int run(int argc, char *argv[]) { r = dissect_image_and_warn( loop->fd, arg_image, - arg_root_hash, arg_root_hash_size, - arg_verity_data, + &arg_verity_settings, NULL, dissect_image_flags, &dissected_image); @@ -5425,10 +5415,15 @@ static int run(int argc, char *argv[]) { if (r < 0) goto finish; - if (!arg_root_hash && dissected_image->can_verity) + if (!arg_verity_settings.root_hash && dissected_image->can_verity) log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image); - r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, 0, &decrypted_image); + r = dissected_image_decrypt_interactively( + dissected_image, + NULL, + &arg_verity_settings, + 0, + &decrypted_image); if (r < 0) goto finish; diff --git a/src/portable/portable.c b/src/portable/portable.c index e55a8116c6c..d74331df3ea 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -379,7 +379,7 @@ static int portable_extract_by_path( if (r < 0) return log_debug_errno(r, "Failed to create temporary directory: %m"); - r = dissect_image(d->fd, NULL, 0, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m); + r = dissect_image(d->fd, NULL, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m); if (r == -ENOPKG) sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path); else if (r == -EADDRNOTAVAIL) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 28053130ef0..2b76bcd17a9 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -304,9 +304,7 @@ static void check_partition_flags( int dissect_image( int fd, - const void *root_hash, - size_t root_hash_size, - const char *verity_data, + const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret) { @@ -328,7 +326,7 @@ int dissect_image( assert(fd >= 0); assert(ret); - assert(root_hash || root_hash_size == 0); + assert(!verity || verity->root_hash || verity->root_hash_size == 0); assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE))); /* Probes a disk image, and returns information about what it found in *ret. @@ -336,16 +334,16 @@ int dissect_image( * Returns -ENOPKG if no suitable partition table or file system could be found. * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */ - if (root_hash) { + if (verity && verity->root_hash) { /* If a root hash is supplied, then we use the root partition that has a UUID that match the first * 128bit of the root hash. And we use the verity partition that has a UUID that match the final * 128bit. */ - if (root_hash_size < sizeof(sd_id128_t)) + if (verity->root_hash_size < sizeof(sd_id128_t)) return -EINVAL; - memcpy(&root_uuid, root_hash, sizeof(sd_id128_t)); - memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); + memcpy(&root_uuid, verity->root_hash, sizeof(sd_id128_t)); + memcpy(&verity_uuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); if (sd_id128_is_null(root_uuid)) return -EINVAL; @@ -416,8 +414,8 @@ int dissect_image( return r; m->single_file_system = true; - m->verity = root_hash && verity_data; - m->can_verity = !!verity_data; + m->verity = verity && verity->root_hash && verity->data_path; + m->can_verity = verity && verity->data_path; options = mount_options_from_designator(mount_options, PARTITION_ROOT); if (options) { @@ -815,7 +813,7 @@ int dissect_image( /* If the root hash was set, then we won't fall back to a generic node, because the * root hash decides. */ - if (root_hash) + if (verity && verity->root_hash) return -EADDRNOTAVAIL; /* If we didn't find a generic node, then we can't fix this up either */ @@ -846,7 +844,7 @@ int dissect_image( } } - if (root_hash) { + if (verity && verity->root_hash) { if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found) return -EADDRNOTAVAIL; @@ -1333,14 +1331,20 @@ static int decrypt_partition( return 0; } -static int verity_can_reuse(const void *root_hash, size_t root_hash_size, bool has_sig, const char *name, struct crypt_device **ret_cd) { +static int verity_can_reuse( + const VeritySettings *verity, + const char *name, + 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 = root_hash_size; + size_t root_hash_existing_size; int r; + assert(verity); + assert(name); assert(ret_cd); r = sym_crypt_init_by_name(&cd, name); @@ -1351,20 +1355,23 @@ static int verity_can_reuse(const void *root_hash, size_t root_hash_size, bool h if (r < 0) return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m"); - root_hash_existing = malloc0(root_hash_size); + root_hash_existing_size = verity->root_hash_size; + root_hash_existing = malloc0(root_hash_existing_size); if (!root_hash_existing) return -ENOMEM; r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0); if (r < 0) return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m"); - if (root_hash_size != root_hash_existing_size || memcmp(root_hash_existing, root_hash, root_hash_size) != 0) + if (verity->root_hash_size != root_hash_existing_size || + memcmp(root_hash_existing, verity->root_hash, verity->root_hash_size) != 0) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but root hashes are different."); + #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY - /* 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 viceversa. */ - if (has_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) + /* 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 viceversa. */ + if (!!verity->root_hash_sig != !!(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."); #endif @@ -1384,29 +1391,24 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean); static int verity_partition( DissectedPartition *m, DissectedPartition *v, - const void *root_hash, - size_t root_hash_size, - const char *verity_data, - const char *root_hash_sig_path, - const void *root_hash_sig, - size_t root_hash_sig_size, + const VeritySettings *verity, DissectImageFlags flags, DecryptedImage *d) { - _cleanup_free_ char *node = NULL, *name = NULL, *hash_sig_from_file = NULL; _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; _cleanup_(dm_deferred_remove_cleanp) char *restore_deferred_remove = NULL; + _cleanup_free_ char *node = NULL, *name = NULL; int r; assert(m); - assert(v || verity_data); + assert(v || (verity && verity->data_path)); - if (!root_hash) + if (!verity || !verity->root_hash) return 0; if (!m->found || !m->node || !m->fstype) return 0; - if (!verity_data) { + if (!verity->data_path) { if (!v->found || !v->node || !v->fstype) return 0; @@ -1422,7 +1424,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(root_hash, root_hash_size); + root_hash_encoded = hexmem(verity->root_hash, verity->root_hash_size); if (!root_hash_encoded) return -ENOMEM; @@ -1432,13 +1434,7 @@ static int verity_partition( if (r < 0) return r; - if (!root_hash_sig && root_hash_sig_path) { - r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, &hash_sig_from_file, &root_hash_sig_size); - if (r < 0) - return r; - } - - r = sym_crypt_init(&cd, verity_data ?: v->node); + r = sym_crypt_init(&cd, verity->data_path ?: v->node); if (r < 0) return r; @@ -1459,20 +1455,33 @@ static int verity_partition( * In case of ENODEV/ENOENT, which can happen if another process is activating at the exact same time, * retry a few times before giving up. */ for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) { - if (root_hash_sig || hash_sig_from_file) { + if (verity->root_hash_sig) { #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY - r = sym_crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, CRYPT_ACTIVATE_READONLY); + 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, + CRYPT_ACTIVATE_READONLY); #else r = log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()"); #endif } else - r = sym_crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY); + r = sym_crypt_activate_by_volume_key( + cd, + name, + verity->root_hash, + verity->root_hash_size, + CRYPT_ACTIVATE_READONLY); /* libdevmapper can return EINVAL when the device is already in the activation stage. * There's no way to distinguish this situation from a genuine error due to invalid * parameters, so immediately fall back to activating the device with a unique name. - * Improvements in libcrypsetup can ensure this never happens: https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */ + * Improvements in libcrypsetup can ensure this never happens: + * https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */ if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE)) - return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); + return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); if (!IN_SET(r, 0, /* Success */ -EEXIST, /* Volume is already open and ready to be used */ @@ -1495,10 +1504,10 @@ static int verity_partition( } } - r = verity_can_reuse(root_hash, root_hash_size, !!root_hash_sig || !!hash_sig_from_file, name, &existing_cd); + r = verity_can_reuse(verity, name, &existing_cd); /* Same as above, -EINVAL can randomly happen when it actually means -EEXIST */ if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE)) - return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); + return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); if (!IN_SET(r, 0, -ENODEV, -ENOENT, -EBUSY)) return log_debug_errno(r, "Checking whether existing verity device %s can be reused failed: %m", node); if (r == 0) { @@ -1526,7 +1535,7 @@ static int verity_partition( /* An existing verity device was reported by libcryptsetup/libdevmapper, but we can't use it at this time. * Fall back to activating it with a unique device name. */ if (r != 0 && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE)) - return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); + return verity_partition(m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, d); /* Everything looks good and we'll be able to mount the device, so deferred remove will be re-enabled at that point. */ restore_deferred_remove = mfree(restore_deferred_remove); @@ -1544,12 +1553,7 @@ static int verity_partition( int dissected_image_decrypt( DissectedImage *m, const char *passphrase, - const void *root_hash, - size_t root_hash_size, - const char *verity_data, - const char *root_hash_sig_path, - const void *root_hash_sig, - size_t root_hash_sig_size, + const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret) { @@ -1559,7 +1563,7 @@ int dissected_image_decrypt( #endif assert(m); - assert(root_hash || root_hash_size == 0); + assert(!verity || verity->root_hash || verity->root_hash_size == 0); /* Returns: * @@ -1569,7 +1573,7 @@ int dissected_image_decrypt( * -EKEYREJECTED → Passed key was not correct */ - if (root_hash && root_hash_size < sizeof(sd_id128_t)) + if (verity && verity->root_hash && verity->root_hash_size < sizeof(sd_id128_t)) return -EINVAL; if (!m->encrypted && !m->verity) { @@ -1595,7 +1599,7 @@ int dissected_image_decrypt( k = PARTITION_VERITY_OF(i); if (k >= 0) { - r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags | DISSECT_IMAGE_VERITY_SHARE, d); + r = verity_partition(p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d); if (r < 0) return r; } @@ -1618,12 +1622,7 @@ int dissected_image_decrypt( int dissected_image_decrypt_interactively( DissectedImage *m, const char *passphrase, - const void *root_hash, - size_t root_hash_size, - const char *verity_data, - const char *root_hash_sig_path, - const void *root_hash_sig, - size_t root_hash_sig_size, + const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret) { @@ -1634,7 +1633,7 @@ int dissected_image_decrypt_interactively( n--; for (;;) { - r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, ret); + r = dissected_image_decrypt(m, passphrase, verity, flags, ret); if (r >= 0) return r; if (r == -EKEYREJECTED) @@ -1686,126 +1685,138 @@ int decrypted_image_relinquish(DecryptedImage *d) { return 0; } -int verity_metadata_load( - const char *image, - const char *root_hash_path, - void **ret_roothash, - size_t *ret_roothash_size, - char **ret_verity_data, - char **ret_roothashsig) { - - _cleanup_free_ char *verity_filename = NULL, *roothashsig_filename = NULL; - _cleanup_free_ void *roothash_decoded = NULL; - size_t roothash_decoded_size = 0; - int r; +static char *build_auxiliary_path(const char *image, const char *suffix) { + const char *e; + char *n; assert(image); + assert(suffix); - if (is_device_path(image)) { - /* If we are asked to load the root hash for a device node, exit early */ - if (ret_roothash) - *ret_roothash = NULL; - if (ret_roothash_size) - *ret_roothash_size = 0; - if (ret_verity_data) - *ret_verity_data = NULL; - if (ret_roothashsig) - *ret_roothashsig = NULL; + e = endswith(image, ".raw"); + if (!e) + return strjoin(e, suffix); + + n = new(char, e - image + strlen(suffix) + 1); + if (!n) + return NULL; + + strcpy(mempcpy(n, image, e - image), suffix); + return n; +} + +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; + + v->data_path = mfree(v->data_path); +} + +int verity_settings_load( + VeritySettings *verity, + const char *image, + 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; + int r; + + assert(verity); + assert(image); + + /* If we are asked to load the root hash for a device node, exit early */ + if (is_device_path(image)) return 0; - } - if (ret_verity_data) { - char *e; + /* We only fill in what isn't already filled in */ - verity_filename = new(char, strlen(image) + STRLEN(".verity") + 1); - if (!verity_filename) - return -ENOMEM; - strcpy(verity_filename, image); - e = endswith(verity_filename, ".raw"); - if (e) - strcpy(e, ".verity"); - else - strcat(verity_filename, ".verity"); - - r = access(verity_filename, F_OK); - if (r < 0) { - if (errno != ENOENT) - return -errno; - verity_filename = mfree(verity_filename); - } - } - - if (ret_roothashsig) { - char *e; - - /* Follow naming convention recommended by the relevant RFC: - * https://tools.ietf.org/html/rfc5751#section-3.2.1 */ - roothashsig_filename = new(char, strlen(image) + STRLEN(".roothash.p7s") + 1); - if (!roothashsig_filename) - return -ENOMEM; - strcpy(roothashsig_filename, image); - e = endswith(roothashsig_filename, ".raw"); - if (e) - strcpy(e, ".roothash.p7s"); - else - strcat(roothashsig_filename, ".roothash.p7s"); - - r = access(roothashsig_filename, R_OK); - if (r < 0) { - if (errno != ENOENT) - return -errno; - roothashsig_filename = mfree(roothashsig_filename); - } - } - - if (ret_roothash) { + if (!verity->root_hash) { _cleanup_free_ char *text = NULL; - assert(ret_roothash_size); if (root_hash_path) { - /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */ r = read_one_line_file(root_hash_path, &text); if (r < 0) return r; } else { r = getxattr_malloc(image, "user.verity.roothash", &text, true); if (r < 0) { - char *fn, *e, *n; + _cleanup_free_ char *p = NULL; - if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)) + if (!IN_SET(r, -ENODATA, -ENOENT) && !ERRNO_IS_NOT_SUPPORTED(r)) return r; - fn = newa(char, strlen(image) + STRLEN(".roothash") + 1); - n = stpcpy(fn, image); - e = endswith(fn, ".raw"); - if (e) - n = e; + p = build_auxiliary_path(image, ".roothash"); + if (!p) + return -ENOMEM; - strcpy(n, ".roothash"); - - r = read_one_line_file(fn, &text); + r = read_one_line_file(p, &text); if (r < 0 && r != -ENOENT) return r; } } if (text) { - r = unhexmem(text, strlen(text), &roothash_decoded, &roothash_decoded_size); + r = unhexmem(text, strlen(text), &root_hash, &root_hash_size); if (r < 0) return r; - if (roothash_decoded_size < sizeof(sd_id128_t)) + if (root_hash_size < sizeof(sd_id128_t)) return -EINVAL; } } - if (ret_roothash) { - *ret_roothash = TAKE_PTR(roothash_decoded); - *ret_roothash_size = roothash_decoded_size; + if (!verity->root_hash_sig) { + _cleanup_free_ char *p = NULL; + + if (!root_hash_sig_path) { + /* Follow naming convention recommended by the relevant RFC: + * https://tools.ietf.org/html/rfc5751#section-3.2.1 */ + p = build_auxiliary_path(image, ".roothash.p7s"); + if (!p) + return -ENOMEM; + + root_hash_sig_path = p; + } + + r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, (char**) &root_hash_sig, &root_hash_sig_size); + if (r < 0) { + if (r != -ENOENT) + return r; + } else if (root_hash_sig_size == 0) /* refuse empty size signatures */ + return -EINVAL; } - if (ret_verity_data) - *ret_verity_data = TAKE_PTR(verity_filename); - if (roothashsig_filename) - *ret_roothashsig = TAKE_PTR(roothashsig_filename); + + if (!verity->data_path) { + _cleanup_free_ char *p = NULL; + + p = build_auxiliary_path(image, ".verity"); + if (!p) + return -ENOMEM; + + if (access(p, F_OK) < 0) { + if (errno != ENOENT) + return -errno; + } else + verity_data_path = TAKE_PTR(p); + } + + if (root_hash) { + verity->root_hash = TAKE_PTR(root_hash); + verity->root_hash_size = root_hash_size; + } + + if (root_hash_sig) { + verity->root_hash_sig = TAKE_PTR(root_hash_sig); + verity->root_hash_sig_size = root_hash_sig_size; + } + + if (verity_data_path) + verity->data_path = TAKE_PTR(verity_data_path); return 1; } @@ -1988,9 +1999,7 @@ finish: int dissect_image_and_warn( int fd, const char *name, - const void *root_hash, - size_t root_hash_size, - const char *verity_data, + const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret) { @@ -2006,7 +2015,7 @@ int dissect_image_and_warn( name = buffer; } - r = dissect_image(fd, root_hash, root_hash_size, verity_data, mount_options, flags, ret); + r = dissect_image(fd, verity, mount_options, flags, ret); switch (r) { @@ -2110,11 +2119,11 @@ int mount_image_privately_interactively( if (r < 0) return log_error_errno(r, "Failed to set up loopback device: %m"); - r = dissect_image_and_warn(d->fd, image, NULL, 0, NULL, NULL, flags, &dissected_image); + r = dissect_image_and_warn(d->fd, image, NULL, NULL, flags, &dissected_image); if (r < 0) return r; - r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, flags, &decrypted_image); + r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, flags, &decrypted_image); if (r < 0) return r; diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 520d8ab10e8..5c1f5bd7b54 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -13,6 +13,7 @@ typedef struct DissectedImage DissectedImage; typedef struct DissectedPartition DissectedPartition; typedef struct DecryptedImage DecryptedImage; typedef struct MountOptions MountOptions; +typedef struct VeritySettings VeritySettings; struct DissectedPartition { bool found:1; @@ -92,19 +93,32 @@ struct MountOptions { LIST_FIELDS(MountOptions, mount_options); }; +struct VeritySettings { + /* Binary root hash for the Verity Merkle tree */ + void *root_hash; + size_t root_hash_size; + + /* PKCS#7 signature of the above */ + void *root_hash_sig; + size_t root_hash_sig_size; + + /* Path to the verity data file, if stored externally */ + char *data_path; +}; + MountOptions* mount_options_free_all(MountOptions *options); DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all); const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator); int probe_filesystem(const char *node, char **ret_fstype); -int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); -int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); +int dissect_image(int fd, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); +int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m); DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); -int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret); -int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret); +int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret); +int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret); int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags); int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags); @@ -117,7 +131,9 @@ int decrypted_image_relinquish(DecryptedImage *d); const char* partition_designator_to_string(PartitionDesignator d) _const_; PartitionDesignator partition_designator_from_string(const char *name) _pure_; -int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig); +int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path); +void verity_settings_done(VeritySettings *verity); + bool dissected_image_can_do_verity(const DissectedImage *image, PartitionDesignator d); bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator d); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index c6ff41898b2..71d6a2c80bc 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) { if (r < 0) return r; - r = dissect_image(d->fd, NULL, 0, NULL, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m); + r = dissect_image(d->fd, NULL, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m); if (r < 0) return r;