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.
This commit is contained in:
+23
-38
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+8
-16
@@ -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;
|
||||
|
||||
@@ -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="))) {
|
||||
|
||||
+6
-8
@@ -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);
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,6 +1,8 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
#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;
|
||||
|
||||
+15
-21
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
+10
-12
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
+11
-13
@@ -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);
|
||||
|
||||
|
||||
+17
-29
@@ -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");
|
||||
|
||||
+122
-146
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user