mirror of
https://github.com/systemd/systemd
synced 2026-03-31 20:24:50 +02:00
Compare commits
No commits in common. "2fc4278b969f95949f872e07280f4c310c9d9924" and "ddc9677c4f23b9afc2edb3c1e2163587bd913a29" have entirely different histories.
2fc4278b96
...
ddc9677c4f
@ -444,7 +444,6 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron11-3168:pvr*
|
|||||||
|
|
||||||
# Dell Inspiron 1520 and Latitude 2110
|
# Dell Inspiron 1520 and Latitude 2110
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:*
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*3505:*
|
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*2110:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*2110:*
|
||||||
KEYBOARD_KEY_85=unknown # Brightness Down, also emitted by acpi-video, ignore
|
KEYBOARD_KEY_85=unknown # Brightness Down, also emitted by acpi-video, ignore
|
||||||
KEYBOARD_KEY_86=unknown # Brightness Up, also emitted by acpi-video, ignore
|
KEYBOARD_KEY_86=unknown # Brightness Up, also emitted by acpi-video, ignore
|
||||||
|
|||||||
@ -772,7 +772,7 @@ static int property_get_root_hash(
|
|||||||
assert(property);
|
assert(property);
|
||||||
assert(reply);
|
assert(reply);
|
||||||
|
|
||||||
return sd_bus_message_append_array(reply, 'y', c->root_hash.iov_base, c->root_hash.iov_len);
|
return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_get_root_hash_sig(
|
static int property_get_root_hash_sig(
|
||||||
@ -790,7 +790,7 @@ static int property_get_root_hash_sig(
|
|||||||
assert(property);
|
assert(property);
|
||||||
assert(reply);
|
assert(reply);
|
||||||
|
|
||||||
return sd_bus_message_append_array(reply, 'y', c->root_hash_sig.iov_base, c->root_hash_sig.iov_len);
|
return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int property_get_root_image_options(
|
static int property_get_root_image_options(
|
||||||
@ -1915,30 +1915,35 @@ int bus_exec_context_set_transient_property(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(name, "RootHash")) {
|
if (streq(name, "RootHash")) {
|
||||||
struct iovec roothash_decoded;
|
const void *roothash_decoded;
|
||||||
|
size_t roothash_decoded_size;
|
||||||
|
|
||||||
r = sd_bus_message_read_array(message, 'y', (const void**) &roothash_decoded.iov_base, &roothash_decoded.iov_len);
|
r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
|
||||||
if (!iovec_is_set(&roothash_decoded)) {
|
if (roothash_decoded_size == 0) {
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RootHash=");
|
unit_write_settingf(u, flags, name, "RootHash=");
|
||||||
} else {
|
} else {
|
||||||
_cleanup_free_ char *encoded = hexmem(roothash_decoded.iov_base, roothash_decoded.iov_len);
|
_cleanup_free_ void *p = NULL;
|
||||||
|
|
||||||
|
encoded = hexmem(roothash_decoded, roothash_decoded_size);
|
||||||
if (!encoded)
|
if (!encoded)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec p = {};
|
p = memdup(roothash_decoded, roothash_decoded_size);
|
||||||
if (!iovec_memdup(&roothash_decoded, &p))
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
iovec_done(&c->root_hash);
|
free_and_replace(c->root_hash, p);
|
||||||
c->root_hash = TAKE_STRUCT(p);
|
c->root_hash_size = roothash_decoded_size;
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
|
unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
|
||||||
@ -1949,35 +1954,43 @@ int bus_exec_context_set_transient_property(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(name, "RootHashPath")) {
|
if (streq(name, "RootHashPath")) {
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash_size = 0;
|
||||||
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
|
||||||
return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
|
return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(name, "RootHashSignature")) {
|
if (streq(name, "RootHashSignature")) {
|
||||||
struct iovec roothash_sig_decoded;
|
const void *roothash_sig_decoded;
|
||||||
|
size_t roothash_sig_decoded_size;
|
||||||
|
|
||||||
r = sd_bus_message_read_array(message, 'y', (const void**) &roothash_sig_decoded.iov_base, &roothash_sig_decoded.iov_len);
|
r = sd_bus_message_read_array(message, 'y', &roothash_sig_decoded, &roothash_sig_decoded_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
if (!iovec_is_set(&roothash_sig_decoded)) {
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
|
||||||
|
if (roothash_sig_decoded_size == 0) {
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RootHashSignature=");
|
unit_write_settingf(u, flags, name, "RootHashSignature=");
|
||||||
} else {
|
} else {
|
||||||
_cleanup_free_ char *encoded = NULL;
|
_cleanup_free_ void *p = NULL;
|
||||||
ssize_t len = base64mem(roothash_sig_decoded.iov_base, roothash_sig_decoded.iov_len, &encoded);
|
ssize_t len;
|
||||||
|
|
||||||
|
len = base64mem(roothash_sig_decoded, roothash_sig_decoded_size, &encoded);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec p = {};
|
p = memdup(roothash_sig_decoded, roothash_sig_decoded_size);
|
||||||
if (!iovec_memdup(&roothash_sig_decoded, &p))
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
iovec_done(&c->root_hash_sig);
|
free_and_replace(c->root_hash_sig, p);
|
||||||
c->root_hash_sig = TAKE_STRUCT(p);
|
c->root_hash_sig_size = roothash_sig_decoded_size;
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded);
|
unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded);
|
||||||
@ -1988,7 +2001,9 @@ int bus_exec_context_set_transient_property(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(name, "RootHashSignaturePath")) {
|
if (streq(name, "RootHashSignaturePath")) {
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig_size = 0;
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
|
||||||
return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error);
|
return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3583,9 +3583,11 @@ static int setup_ephemeral(
|
|||||||
static int verity_settings_prepare(
|
static int verity_settings_prepare(
|
||||||
VeritySettings *verity,
|
VeritySettings *verity,
|
||||||
const char *root_image,
|
const char *root_image,
|
||||||
const struct iovec *root_hash,
|
const void *root_hash,
|
||||||
|
size_t root_hash_size,
|
||||||
const char *root_hash_path,
|
const char *root_hash_path,
|
||||||
const struct iovec *root_hash_sig,
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
const char *root_hash_sig_path,
|
const char *root_hash_sig_path,
|
||||||
const char *verity_data_path) {
|
const char *verity_data_path) {
|
||||||
|
|
||||||
@ -3594,20 +3596,26 @@ static int verity_settings_prepare(
|
|||||||
assert(verity);
|
assert(verity);
|
||||||
|
|
||||||
if (root_hash) {
|
if (root_hash) {
|
||||||
iovec_done(&verity->root_hash);
|
void *d;
|
||||||
|
|
||||||
if (!iovec_memdup(root_hash, &verity->root_hash))
|
d = memdup(root_hash, root_hash_size);
|
||||||
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(verity->root_hash, d);
|
||||||
|
verity->root_hash_size = root_hash_size;
|
||||||
verity->designator = PARTITION_ROOT;
|
verity->designator = PARTITION_ROOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_hash_sig) {
|
if (root_hash_sig) {
|
||||||
iovec_done(&verity->root_hash_sig);
|
void *d;
|
||||||
|
|
||||||
if (!iovec_memdup(root_hash_sig, &verity->root_hash_sig))
|
d = memdup(root_hash_sig, root_hash_sig_size);
|
||||||
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(verity->root_hash_sig, d);
|
||||||
|
verity->root_hash_sig_size = root_hash_sig_size;
|
||||||
verity->designator = PARTITION_ROOT;
|
verity->designator = PARTITION_ROOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3837,8 +3845,8 @@ static int apply_mount_namespace(
|
|||||||
r = verity_settings_prepare(
|
r = verity_settings_prepare(
|
||||||
&verity,
|
&verity,
|
||||||
root_image,
|
root_image,
|
||||||
&context->root_hash, context->root_hash_path,
|
context->root_hash, context->root_hash_size, context->root_hash_path,
|
||||||
&context->root_hash_sig, context->root_hash_sig_path,
|
context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
|
||||||
context->root_verity);
|
context->root_verity);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -1662,11 +1662,11 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = serialize_item_hexmem(f, "exec-context-root-hash", c->root_hash.iov_base, c->root_hash.iov_len);
|
r = serialize_item_hexmem(f, "exec-context-root-hash", c->root_hash, c->root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = serialize_item_base64mem(f, "exec-context-root-hash-sig", c->root_hash_sig.iov_base, c->root_hash_sig.iov_len);
|
r = serialize_item_base64mem(f, "exec-context-root-hash-sig", c->root_hash_sig, c->root_hash_sig_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2616,13 +2616,13 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-root-hash="))) {
|
} else if ((val = startswith(l, "exec-context-root-hash="))) {
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
r = unhexmem(val, &c->root_hash.iov_base, &c->root_hash.iov_len);
|
r = unhexmem(val, &c->root_hash, &c->root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-root-hash-sig="))) {
|
} else if ((val = startswith(l, "exec-context-root-hash-sig="))) {
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
r= unbase64mem(val, &c->root_hash_sig.iov_base, &c->root_hash_sig.iov_len);
|
r= unbase64mem(val, &c->root_hash_sig, &c->root_hash_sig_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-context-root-ephemeral="))) {
|
} else if ((val = startswith(l, "exec-context-root-ephemeral="))) {
|
||||||
|
|||||||
@ -679,9 +679,11 @@ void exec_context_done(ExecContext *c) {
|
|||||||
c->root_directory = mfree(c->root_directory);
|
c->root_directory = mfree(c->root_directory);
|
||||||
c->root_image = mfree(c->root_image);
|
c->root_image = mfree(c->root_image);
|
||||||
c->root_image_options = mount_options_free_all(c->root_image_options);
|
c->root_image_options = mount_options_free_all(c->root_image_options);
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
c->root_verity = mfree(c->root_verity);
|
c->root_verity = mfree(c->root_verity);
|
||||||
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
|
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
|
||||||
@ -1176,9 +1178,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
|||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iovec_is_set(&c->root_hash)) {
|
if (c->root_hash) {
|
||||||
_cleanup_free_ char *encoded = NULL;
|
_cleanup_free_ char *encoded = NULL;
|
||||||
encoded = hexmem(c->root_hash.iov_base, c->root_hash.iov_len);
|
encoded = hexmem(c->root_hash, c->root_hash_size);
|
||||||
if (encoded)
|
if (encoded)
|
||||||
fprintf(f, "%sRootHash: %s\n", prefix, encoded);
|
fprintf(f, "%sRootHash: %s\n", prefix, encoded);
|
||||||
}
|
}
|
||||||
@ -1186,10 +1188,10 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
|||||||
if (c->root_hash_path)
|
if (c->root_hash_path)
|
||||||
fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
|
fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
|
||||||
|
|
||||||
if (iovec_is_set(&c->root_hash_sig)) {
|
if (c->root_hash_sig) {
|
||||||
_cleanup_free_ char *encoded = NULL;
|
_cleanup_free_ char *encoded = NULL;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
len = base64mem(c->root_hash_sig.iov_base, c->root_hash_sig.iov_len, &encoded);
|
len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
|
||||||
if (len)
|
if (len)
|
||||||
fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
|
fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "bus-unit-util.h"
|
#include "bus-unit-util.h"
|
||||||
@ -183,7 +181,8 @@ typedef struct ExecContext {
|
|||||||
|
|
||||||
struct rlimit *rlimit[_RLIMIT_MAX];
|
struct rlimit *rlimit[_RLIMIT_MAX];
|
||||||
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path;
|
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path;
|
||||||
struct iovec root_hash, root_hash_sig;
|
void *root_hash, *root_hash_sig;
|
||||||
|
size_t root_hash_size, root_hash_sig_size;
|
||||||
LIST_HEAD(MountOptions, root_image_options);
|
LIST_HEAD(MountOptions, root_image_options);
|
||||||
bool root_ephemeral;
|
bool root_ephemeral;
|
||||||
bool working_directory_missing_ok:1;
|
bool working_directory_missing_ok:1;
|
||||||
|
|||||||
@ -1714,7 +1714,9 @@ int config_parse_exec_root_hash(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
ExecContext *c = ASSERT_PTR(data);
|
ExecContext *c = ASSERT_PTR(data);
|
||||||
|
size_t roothash_decoded_size = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
@ -1724,7 +1726,8 @@ int config_parse_exec_root_hash(
|
|||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
/* Reset if the empty string is assigned */
|
/* Reset if the empty string is assigned */
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1737,24 +1740,24 @@ int config_parse_exec_root_hash(
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
free_and_replace(c->root_hash_path, p);
|
free_and_replace(c->root_hash_path, p);
|
||||||
iovec_done(&c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
|
c->root_hash_size = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have a roothash to decode, eg: RootHash=012345789abcdef */
|
/* We have a roothash to decode, eg: RootHash=012345789abcdef */
|
||||||
_cleanup_(iovec_done) struct iovec roothash_decoded = {};
|
r = unhexmem(rvalue, &roothash_decoded, &roothash_decoded_size);
|
||||||
r = unhexmem(rvalue, &roothash_decoded.iov_base, &roothash_decoded.iov_len);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (roothash_decoded.iov_len < sizeof(sd_id128_t)) {
|
if (roothash_decoded_size < sizeof(sd_id128_t)) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "RootHash= is too short, ignoring: %s", rvalue);
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "RootHash= is too short, ignoring: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec_done(&c->root_hash);
|
free_and_replace(c->root_hash, roothash_decoded);
|
||||||
c->root_hash = TAKE_STRUCT(roothash_decoded);
|
c->root_hash_size = roothash_decoded_size;
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1772,7 +1775,10 @@ int config_parse_exec_root_hash_sig(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
|
_cleanup_free_ void *roothash_sig_decoded = NULL;
|
||||||
|
char *value;
|
||||||
ExecContext *c = ASSERT_PTR(data);
|
ExecContext *c = ASSERT_PTR(data);
|
||||||
|
size_t roothash_sig_decoded_size = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
@ -1782,7 +1788,8 @@ int config_parse_exec_root_hash_sig(
|
|||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
/* Reset if the empty string is assigned */
|
/* Reset if the empty string is assigned */
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1795,27 +1802,26 @@ int config_parse_exec_root_hash_sig(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
free_and_replace(c->root_hash_sig_path, p);
|
free_and_replace(c->root_hash_sig_path, p);
|
||||||
iovec_done(&c->root_hash_sig);
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *value = startswith(rvalue, "base64:");
|
if (!(value = startswith(rvalue, "base64:"))) {
|
||||||
if (!value) {
|
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||||
"Failed to decode RootHashSignature=, not a path but doesn't start with 'base64:', ignoring: %s", rvalue);
|
"Failed to decode RootHashSignature=, not a path but doesn't start with 'base64:', ignoring: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
|
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
|
||||||
_cleanup_(iovec_done) struct iovec roothash_sig_decoded = {};
|
r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
|
||||||
r = unbase64mem(value, &roothash_sig_decoded.iov_base, &roothash_sig_decoded.iov_len);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHashSignature=, ignoring: %s", rvalue);
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode RootHashSignature=, ignoring: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec_done(&c->root_hash_sig);
|
free_and_replace(c->root_hash_sig, roothash_sig_decoded);
|
||||||
c->root_hash_sig = TAKE_STRUCT(roothash_sig_decoded);
|
c->root_hash_sig_size = roothash_sig_decoded_size;
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
#include "iovec-util.h"
|
|
||||||
#include "label-util.h"
|
#include "label-util.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "lock-util.h"
|
#include "lock-util.h"
|
||||||
@ -1020,7 +1019,7 @@ static bool verity_has_later_duplicates(MountList *ml, const MountEntry *needle)
|
|||||||
assert(needle >= ml->mounts && needle < ml->mounts + ml->n_mounts);
|
assert(needle >= ml->mounts && needle < ml->mounts + ml->n_mounts);
|
||||||
assert(needle->mode == MOUNT_EXTENSION_IMAGE);
|
assert(needle->mode == MOUNT_EXTENSION_IMAGE);
|
||||||
|
|
||||||
if (!iovec_is_set(&needle->verity.root_hash))
|
if (needle->verity.root_hash_size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Overlayfs rejects supplying the same directory inode twice as determined by filesystem UUID and
|
/* Overlayfs rejects supplying the same directory inode twice as determined by filesystem UUID and
|
||||||
@ -1033,7 +1032,10 @@ static bool verity_has_later_duplicates(MountList *ml, const MountEntry *needle)
|
|||||||
for (const MountEntry *m = needle + 1; m < ml->mounts + ml->n_mounts; m++) {
|
for (const MountEntry *m = needle + 1; m < ml->mounts + ml->n_mounts; m++) {
|
||||||
if (m->mode != MOUNT_EXTENSION_IMAGE)
|
if (m->mode != MOUNT_EXTENSION_IMAGE)
|
||||||
continue;
|
continue;
|
||||||
if (iovec_memcmp(&m->verity.root_hash, &needle->verity.root_hash) == 0)
|
if (memcmp_nn(m->verity.root_hash,
|
||||||
|
m->verity.root_hash_size,
|
||||||
|
needle->verity.root_hash,
|
||||||
|
needle->verity.root_hash_size) == 0)
|
||||||
return true;
|
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_STRING_NON_EMPTY("RootImage", c->root_image),
|
||||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("RootImageOptions", root_image_options_build_json, c->root_image_options),
|
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),
|
SD_JSON_BUILD_PAIR_BOOLEAN("RootEphemeral", c->root_ephemeral),
|
||||||
JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHash", c->root_hash.iov_base, c->root_hash.iov_len),
|
JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHash", c->root_hash, c->root_hash_size),
|
||||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashPath", c->root_hash_path),
|
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashPath", c->root_hash_path),
|
||||||
JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHashSignature", c->root_hash_sig.iov_base, c->root_hash_sig.iov_len),
|
JSON_BUILD_PAIR_BASE64_NON_EMPTY("RootHashSignature", c->root_hash_sig, c->root_hash_sig_size),
|
||||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashSignaturePath", c->root_hash_sig_path),
|
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootHashSignaturePath", c->root_hash_sig_path),
|
||||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootVerity", c->root_verity),
|
JSON_BUILD_PAIR_STRING_NON_EMPTY("RootVerity", c->root_verity),
|
||||||
SD_JSON_BUILD_PAIR_CALLBACK("RootImagePolicy", image_policy_build_json, c->root_image_policy),
|
SD_JSON_BUILD_PAIR_CALLBACK("RootImagePolicy", image_policy_build_json, c->root_image_policy),
|
||||||
|
|||||||
@ -474,22 +474,23 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
|
|
||||||
case ARG_ROOT_HASH:
|
case ARG_ROOT_HASH:
|
||||||
case ARG_USR_HASH: {
|
case ARG_USR_HASH: {
|
||||||
_cleanup_(iovec_done) struct iovec roothash = {};
|
_cleanup_free_ void *p = NULL;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
PartitionDesignator d = c == ARG_USR_HASH ? PARTITION_USR : PARTITION_ROOT;
|
PartitionDesignator d = c == ARG_USR_HASH ? PARTITION_USR : PARTITION_ROOT;
|
||||||
if (arg_verity_settings.designator >= 0 &&
|
if (arg_verity_settings.designator >= 0 &&
|
||||||
arg_verity_settings.designator != d)
|
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.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --root-hash=/--root-hash-sig= and --usr-hash=/--usr-hash-sig= options.");
|
||||||
|
|
||||||
r = unhexmem(optarg, &roothash.iov_base, &roothash.iov_len);
|
r = unhexmem(optarg, &p, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash '%s': %m", optarg);
|
return log_error_errno(r, "Failed to parse root hash '%s': %m", optarg);
|
||||||
if (roothash.iov_len < sizeof(sd_id128_t))
|
if (l < sizeof(sd_id128_t))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Root hash must be at least 128-bit long: %s", optarg);
|
"Root hash must be at least 128-bit long: %s", optarg);
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash);
|
free_and_replace(arg_verity_settings.root_hash, p);
|
||||||
arg_verity_settings.root_hash = TAKE_STRUCT(roothash);
|
arg_verity_settings.root_hash_size = l;
|
||||||
arg_verity_settings.designator = d;
|
arg_verity_settings.designator = d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -497,7 +498,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
case ARG_ROOT_HASH_SIG:
|
case ARG_ROOT_HASH_SIG:
|
||||||
case ARG_USR_HASH_SIG: {
|
case ARG_USR_HASH_SIG: {
|
||||||
char *value;
|
char *value;
|
||||||
_cleanup_(iovec_done) struct iovec sig = {};
|
size_t l;
|
||||||
|
void *p;
|
||||||
|
|
||||||
PartitionDesignator d = c == ARG_USR_HASH_SIG ? PARTITION_USR : PARTITION_ROOT;
|
PartitionDesignator d = c == ARG_USR_HASH_SIG ? PARTITION_USR : PARTITION_ROOT;
|
||||||
if (arg_verity_settings.designator >= 0 &&
|
if (arg_verity_settings.designator >= 0 &&
|
||||||
@ -505,17 +507,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.");
|
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:"))) {
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
r = unbase64mem(value, &sig.iov_base, &sig.iov_len);
|
r = unbase64mem(value, &p, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
} else {
|
} else {
|
||||||
r = read_full_file(optarg, (char**) &sig.iov_base, &sig.iov_len);
|
r = read_full_file(optarg, (char**) &p, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read root hash signature file '%s': %m", optarg);
|
return log_error_errno(r, "Failed to read root hash signature file '%s': %m", optarg);
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash_sig);
|
free_and_replace(arg_verity_settings.root_hash_sig, p);
|
||||||
arg_verity_settings.root_hash_sig = TAKE_STRUCT(sig);
|
arg_verity_settings.root_hash_sig_size = l;
|
||||||
arg_verity_settings.designator = d;
|
arg_verity_settings.designator = d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,5 +38,5 @@ static inline bool iovec_is_set(const struct iovec *iovec) {
|
|||||||
|
|
||||||
static inline bool iovec_is_valid(const struct iovec *iovec) {
|
static inline bool iovec_is_valid(const struct iovec *iovec) {
|
||||||
/* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
|
/* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
|
||||||
return !iovec || iovec->iov_base || iovec->iov_len == 0;
|
return !iovec || (iovec->iov_base || iovec->iov_len == 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1191,8 +1191,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
|||||||
|
|
||||||
arg_verity_settings.designator = PARTITION_ROOT;
|
arg_verity_settings.designator = PARTITION_ROOT;
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash);
|
free(arg_verity_settings.root_hash);
|
||||||
r = unhexmem(value, &arg_verity_settings.root_hash.iov_base, &arg_verity_settings.root_hash.iov_len);
|
r = unhexmem(value, &arg_verity_settings.root_hash, &arg_verity_settings.root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse roothash= from kernel command line: %m");
|
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;
|
arg_verity_settings.designator = PARTITION_USR;
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash);
|
free(arg_verity_settings.root_hash);
|
||||||
r = unhexmem(value, &arg_verity_settings.root_hash.iov_base, &arg_verity_settings.root_hash.iov_len);
|
r = unhexmem(value, &arg_verity_settings.root_hash, &arg_verity_settings.root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse usrhash= from kernel command line: %m");
|
return log_error_errno(r, "Failed to parse usrhash= from kernel command line: %m");
|
||||||
|
|
||||||
|
|||||||
@ -379,8 +379,14 @@ static int vl_method_mount_image(
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
verity.designator = PARTITION_ROOT;
|
verity.designator = PARTITION_ROOT;
|
||||||
verity.root_hash = TAKE_STRUCT(p.verity_root_hash);
|
|
||||||
verity.root_hash_sig = TAKE_STRUCT(p.verity_root_hash_sig);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *polkit_details[] = {
|
const char *polkit_details[] = {
|
||||||
|
|||||||
@ -1305,36 +1305,38 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARG_ROOT_HASH: {
|
case ARG_ROOT_HASH: {
|
||||||
_cleanup_(iovec_done) struct iovec k = {};
|
_cleanup_free_ void *k = NULL;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
r = unhexmem(optarg, &k.iov_base, &k.iov_len);
|
r = unhexmem(optarg, &k, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash: %s", optarg);
|
return log_error_errno(r, "Failed to parse root hash: %s", optarg);
|
||||||
if (k.iov_len < sizeof(sd_id128_t))
|
if (l < sizeof(sd_id128_t))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128-bit long: %s", optarg);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128-bit long: %s", optarg);
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash);
|
free_and_replace(arg_verity_settings.root_hash, k);
|
||||||
arg_verity_settings.root_hash = TAKE_STRUCT(k);
|
arg_verity_settings.root_hash_size = l;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ARG_ROOT_HASH_SIG: {
|
case ARG_ROOT_HASH_SIG: {
|
||||||
_cleanup_(iovec_done) struct iovec p = {};
|
|
||||||
char *value;
|
char *value;
|
||||||
|
size_t l;
|
||||||
|
void *p;
|
||||||
|
|
||||||
if ((value = startswith(optarg, "base64:"))) {
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
r = unbase64mem(value, &p.iov_base, &p.iov_len);
|
r = unbase64mem(value, &p, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
r = read_full_file(optarg, (char**) &p.iov_base, &p.iov_len);
|
r = read_full_file(optarg, (char**) &p, &l);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash signature file '%s': %m", optarg);
|
return log_error_errno(r, "Failed to parse root hash signature file '%s': %m", optarg);
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec_done(&arg_verity_settings.root_hash_sig);
|
free_and_replace(arg_verity_settings.root_hash_sig, p);
|
||||||
arg_verity_settings.root_hash_sig = TAKE_STRUCT(p);
|
arg_verity_settings.root_hash_sig_size = l;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6356,7 +6358,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dissected_image->has_verity && !iovec_is_set(&arg_verity_settings.root_hash))
|
if (dissected_image->has_verity && !arg_verity_settings.root_hash)
|
||||||
log_notice("Note: image %s contains verity information, but no root hash specified and no embedded "
|
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);
|
"root hash signature found! Proceeding without integrity checking.", arg_image);
|
||||||
|
|
||||||
|
|||||||
@ -5548,7 +5548,8 @@ 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));
|
memcpy(root_hash_key + sizeof(sd_id128_t), hash_uuid.bytes, sizeof(sd_id128_t));
|
||||||
|
|
||||||
VeritySettings key = {
|
VeritySettings key = {
|
||||||
.root_hash = IOVEC_MAKE(root_hash_key, sizeof(root_hash_key)),
|
.root_hash = &root_hash_key,
|
||||||
|
.root_hash_size = sizeof(root_hash_key),
|
||||||
};
|
};
|
||||||
|
|
||||||
return set_get(arg_verity_settings, &key);
|
return set_get(arg_verity_settings, &key);
|
||||||
@ -5556,8 +5557,10 @@ static const VeritySettings *lookup_verity_settings_by_uuid_pair(sd_id128_t data
|
|||||||
|
|
||||||
static int partition_format_verity_sig(Context *context, Partition *p) {
|
static int partition_format_verity_sig(Context *context, Partition *p) {
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||||
|
_cleanup_(iovec_done) struct iovec sig_free = {};
|
||||||
_cleanup_free_ char *text = NULL, *hint = NULL;
|
_cleanup_free_ char *text = NULL, *hint = NULL;
|
||||||
const VeritySettings *verity_settings;
|
const VeritySettings *verity_settings;
|
||||||
|
struct iovec roothash, sig;
|
||||||
Partition *hp, *rp;
|
Partition *hp, *rp;
|
||||||
uint8_t fp[X509_FINGERPRINT_SIZE];
|
uint8_t fp[X509_FINGERPRINT_SIZE];
|
||||||
int whole_fd, r;
|
int whole_fd, r;
|
||||||
@ -5597,18 +5600,22 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
|
|||||||
|
|
||||||
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
|
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) {
|
if (verity_settings) {
|
||||||
sig = &verity_settings->root_hash_sig;
|
sig = (struct iovec) {
|
||||||
roothash = &verity_settings->root_hash;
|
.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,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
r = sign_verity_roothash(context, &hp->roothash, &sig_free);
|
r = sign_verity_roothash(context, &hp->roothash, &sig_free);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
sig = &sig_free;
|
sig = sig_free;
|
||||||
roothash = &hp->roothash;
|
roothash = hp->roothash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
@ -5620,9 +5627,9 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
|
|||||||
|
|
||||||
r = sd_json_buildo(
|
r = sd_json_buildo(
|
||||||
&v,
|
&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_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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to build verity signature JSON object: %m");
|
return log_error_errno(r, "Failed to build verity signature JSON object: %m");
|
||||||
|
|
||||||
@ -8817,8 +8824,9 @@ static int parse_partition_types(const char *p, GptPartitionType **partitions, s
|
|||||||
static int parse_join_signature(const char *p, Set **verity_settings_map) {
|
static int parse_join_signature(const char *p, Set **verity_settings_map) {
|
||||||
_cleanup_(verity_settings_freep) VeritySettings *verity_settings = NULL;
|
_cleanup_(verity_settings_freep) VeritySettings *verity_settings = NULL;
|
||||||
_cleanup_free_ char *root_hash = NULL;
|
_cleanup_free_ char *root_hash = NULL;
|
||||||
|
_cleanup_free_ void *content = NULL;
|
||||||
const char *signature;
|
const char *signature;
|
||||||
_cleanup_(iovec_done) struct iovec content = {};
|
size_t len;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
@ -8830,17 +8838,17 @@ static int parse_join_signature(const char *p, Set **verity_settings_map) {
|
|||||||
if (!p)
|
if (!p)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected hash:sig");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected hash:sig");
|
||||||
if ((signature = startswith(p, "base64:"))) {
|
if ((signature = startswith(p, "base64:"))) {
|
||||||
r = unbase64mem(signature, &content.iov_base, &content.iov_len);
|
r = unbase64mem(signature, &content, &len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", signature);
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", signature);
|
||||||
} else {
|
} else {
|
||||||
r = read_full_file(p, (char**) &content.iov_base, &content.iov_len);
|
r = read_full_file(p, (char**) &content, &len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read root hash signature file '%s': %m", p);
|
return log_error_errno(r, "Failed to read root hash signature file '%s': %m", p);
|
||||||
}
|
}
|
||||||
if (!iovec_is_set(&content))
|
if (len == 0)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty verity signature specified.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty verity signature specified.");
|
||||||
if (content.iov_len > VERITY_SIG_SIZE)
|
if (len > VERITY_SIG_SIZE)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Verity signatures larger than %llu are not allowed.",
|
"Verity signatures larger than %llu are not allowed.",
|
||||||
VERITY_SIG_SIZE);
|
VERITY_SIG_SIZE);
|
||||||
@ -8850,17 +8858,21 @@ static int parse_join_signature(const char *p, Set **verity_settings_map) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
*verity_settings = (VeritySettings) {
|
*verity_settings = (VeritySettings) {
|
||||||
.root_hash_sig = TAKE_STRUCT(content),
|
.root_hash_sig = TAKE_PTR(content),
|
||||||
|
.root_hash_sig_size = len,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = unhexmem(root_hash, &verity_settings->root_hash.iov_base, &verity_settings->root_hash.iov_len);
|
r = unhexmem(root_hash, &content, &len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash '%s': %m", root_hash);
|
return log_error_errno(r, "Failed to parse root hash '%s': %m", root_hash);
|
||||||
if (verity_settings->root_hash.iov_len < sizeof(sd_id128_t))
|
if (len < sizeof(sd_id128_t))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Root hash must be at least 128-bit long: %s",
|
"Root hash must be at least 128-bit long: %s",
|
||||||
root_hash);
|
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);
|
r = set_ensure_put(verity_settings_map, &verity_settings_hash_ops, verity_settings);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to add entry to hashmap: %m");
|
return log_error_errno(r, "Failed to add entry to hashmap: %m");
|
||||||
|
|||||||
@ -47,7 +47,6 @@
|
|||||||
#include "image-policy.h"
|
#include "image-policy.h"
|
||||||
#include "import-util.h"
|
#include "import-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
#include "iovec-util.h"
|
|
||||||
#include "json-util.h"
|
#include "json-util.h"
|
||||||
#include "loop-util.h"
|
#include "loop-util.h"
|
||||||
#include "mkdir-label.h"
|
#include "mkdir-label.h"
|
||||||
@ -573,12 +572,16 @@ static int acquire_sig_for_roothash(
|
|||||||
int fd,
|
int fd,
|
||||||
uint64_t partition_offset,
|
uint64_t partition_offset,
|
||||||
uint64_t partition_size,
|
uint64_t partition_size,
|
||||||
struct iovec *ret_root_hash,
|
void **ret_root_hash,
|
||||||
struct iovec *ret_root_hash_sig) {
|
size_t *ret_root_hash_size,
|
||||||
|
void **ret_root_hash_sig,
|
||||||
|
size_t *ret_root_hash_sig_size) {
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
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)
|
if (partition_offset == UINT64_MAX || partition_size == UINT64_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -613,8 +616,9 @@ static int acquire_sig_for_roothash(
|
|||||||
if (!rh)
|
if (!rh)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'rootHash' field.");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'rootHash' field.");
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash = {};
|
_cleanup_free_ void *root_hash = NULL;
|
||||||
r = sd_json_variant_unhex(rh, &root_hash.iov_base, &root_hash.iov_len);
|
size_t root_hash_size;
|
||||||
|
r = sd_json_variant_unhex(rh, &root_hash, &root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to parse root hash field: %m");
|
return log_debug_errno(r, "Failed to parse root hash field: %m");
|
||||||
|
|
||||||
@ -622,16 +626,21 @@ static int acquire_sig_for_roothash(
|
|||||||
if (!sig)
|
if (!sig)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'signature' field.");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'signature' field.");
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash_sig = {};
|
_cleanup_free_ void *root_hash_sig = NULL;
|
||||||
r = sd_json_variant_unbase64(sig, &root_hash_sig.iov_base, &root_hash_sig.iov_len);
|
size_t root_hash_sig_size;
|
||||||
|
r = sd_json_variant_unbase64(sig, &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to parse signature field: %m");
|
return log_debug_errno(r, "Failed to parse signature field: %m");
|
||||||
|
|
||||||
if (ret_root_hash)
|
if (ret_root_hash) {
|
||||||
*ret_root_hash = TAKE_STRUCT(root_hash);
|
*ret_root_hash = TAKE_PTR(root_hash);
|
||||||
|
*ret_root_hash_size = root_hash_size;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret_root_hash_sig)
|
if (ret_root_hash_sig) {
|
||||||
*ret_root_hash_sig = TAKE_STRUCT(root_hash_sig);
|
*ret_root_hash_sig = TAKE_PTR(root_hash_sig);
|
||||||
|
*ret_root_hash_sig_size = root_hash_sig_size;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -819,9 +828,9 @@ static int dissect_image(
|
|||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(devname);
|
assert(devname);
|
||||||
assert(!verity || verity->designator < 0 || IN_SET(verity->designator, PARTITION_ROOT, PARTITION_USR));
|
assert(!verity || verity->designator < 0 || IN_SET(verity->designator, PARTITION_ROOT, PARTITION_USR));
|
||||||
assert(!verity || iovec_is_valid(&verity->root_hash));
|
assert(!verity || verity->root_hash || verity->root_hash_size == 0);
|
||||||
assert(!verity || iovec_is_valid(&verity->root_hash_sig));
|
assert(!verity || verity->root_hash_sig || verity->root_hash_sig_size == 0);
|
||||||
assert(!verity || iovec_is_set(&verity->root_hash) || !iovec_is_set(&verity->root_hash_sig));
|
assert(!verity || (verity->root_hash || !verity->root_hash_sig));
|
||||||
assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)));
|
assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)));
|
||||||
assert(m->sector_size > 0);
|
assert(m->sector_size > 0);
|
||||||
|
|
||||||
@ -840,18 +849,18 @@ static int dissect_image(
|
|||||||
|
|
||||||
uint64_t diskseq = m->loop ? m->loop->diskseq : 0;
|
uint64_t diskseq = m->loop ? m->loop->diskseq : 0;
|
||||||
|
|
||||||
if (verity && iovec_is_set(&verity->root_hash)) {
|
if (verity && verity->root_hash) {
|
||||||
sd_id128_t fsuuid, vuuid;
|
sd_id128_t fsuuid, vuuid;
|
||||||
|
|
||||||
/* If a root hash is supplied, then we use the root partition that has a UUID that match the
|
/* 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
|
* first 128-bit of the root hash. And we use the verity partition that has a UUID that match
|
||||||
* the final 128-bit. */
|
* the final 128-bit. */
|
||||||
|
|
||||||
if (verity->root_hash.iov_len < sizeof(sd_id128_t))
|
if (verity->root_hash_size < sizeof(sd_id128_t))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
memcpy(&fsuuid, verity->root_hash.iov_base, sizeof(sd_id128_t));
|
memcpy(&fsuuid, verity->root_hash, 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));
|
memcpy(&vuuid, (const uint8_t*) verity->root_hash + verity->root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
|
||||||
|
|
||||||
if (sd_id128_is_null(fsuuid))
|
if (sd_id128_is_null(fsuuid))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -946,7 +955,7 @@ static int dissect_image(
|
|||||||
encrypted = streq_ptr(fstype, "crypto_LUKS");
|
encrypted = streq_ptr(fstype, "crypto_LUKS");
|
||||||
|
|
||||||
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
||||||
found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
found_flags = verity->root_hash_sig_size > 0 ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
||||||
else
|
else
|
||||||
found_flags = encrypted ? PARTITION_POLICY_ENCRYPTED : PARTITION_POLICY_UNPROTECTED;
|
found_flags = encrypted ? PARTITION_POLICY_ENCRYPTED : PARTITION_POLICY_UNPROTECTED;
|
||||||
|
|
||||||
@ -981,7 +990,7 @@ static int dissect_image(
|
|||||||
m->verity_ready = verity_settings_data_covers(verity, PARTITION_ROOT);
|
m->verity_ready = verity_settings_data_covers(verity, PARTITION_ROOT);
|
||||||
|
|
||||||
m->has_verity_sig = false; /* signature not embedded, must be specified */
|
m->has_verity_sig = false; /* signature not embedded, must be specified */
|
||||||
m->verity_sig_ready = m->verity_ready && iovec_is_set(&verity->root_hash);
|
m->verity_sig_ready = m->verity_ready && verity->root_hash_sig;
|
||||||
|
|
||||||
m->image_uuid = uuid;
|
m->image_uuid = uuid;
|
||||||
|
|
||||||
@ -1227,23 +1236,26 @@ static int dissect_image(
|
|||||||
rw = false;
|
rw = false;
|
||||||
|
|
||||||
} else if (type.designator == PARTITION_ROOT_VERITY_SIG) {
|
} else if (type.designator == PARTITION_ROOT_VERITY_SIG) {
|
||||||
if (verity && iovec_is_set(&verity->root_hash)) {
|
if (verity && verity->root_hash) {
|
||||||
_cleanup_(iovec_done) struct iovec root_hash = {};
|
_cleanup_free_ void *root_hash = NULL;
|
||||||
|
size_t root_hash_size;
|
||||||
|
|
||||||
r = acquire_sig_for_roothash(
|
r = acquire_sig_for_roothash(
|
||||||
fd,
|
fd,
|
||||||
start * 512,
|
start * 512,
|
||||||
size * 512,
|
size * 512,
|
||||||
&root_hash,
|
&root_hash,
|
||||||
/* ret_root_hash_sig= */ NULL);
|
&root_hash_size,
|
||||||
|
/* ret_root_hash_sig= */ NULL,
|
||||||
|
/* ret_root_hash_sig_size= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (iovec_memcmp(&verity->root_hash, &root_hash) != 0) {
|
if (memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) {
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
_cleanup_free_ char *found = NULL, *expected = NULL;
|
_cleanup_free_ char *found = NULL, *expected = NULL;
|
||||||
|
|
||||||
found = hexmem(root_hash.iov_base, root_hash.iov_len);
|
found = hexmem(root_hash, root_hash_size);
|
||||||
expected = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len);
|
expected = hexmem(verity->root_hash, verity->root_hash_size);
|
||||||
|
|
||||||
log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected));
|
log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected));
|
||||||
}
|
}
|
||||||
@ -1293,23 +1305,26 @@ static int dissect_image(
|
|||||||
rw = false;
|
rw = false;
|
||||||
|
|
||||||
} else if (type.designator == PARTITION_USR_VERITY_SIG) {
|
} else if (type.designator == PARTITION_USR_VERITY_SIG) {
|
||||||
if (verity && iovec_is_set(&verity->root_hash)) {
|
if (verity && verity->root_hash) {
|
||||||
_cleanup_(iovec_done) struct iovec root_hash = {};
|
_cleanup_free_ void *root_hash = NULL;
|
||||||
|
size_t root_hash_size;
|
||||||
|
|
||||||
r = acquire_sig_for_roothash(
|
r = acquire_sig_for_roothash(
|
||||||
fd,
|
fd,
|
||||||
start * 512,
|
start * 512,
|
||||||
size * 512,
|
size * 512,
|
||||||
&root_hash,
|
&root_hash,
|
||||||
/* ret_root_hash_sig= */ NULL);
|
&root_hash_size,
|
||||||
|
/* ret_root_hash_sig= */ NULL,
|
||||||
|
/* ret_root_hash_sig_size= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (iovec_memcmp(&verity->root_hash, &root_hash) != 0) {
|
if (memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) {
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
_cleanup_free_ char *found = NULL, *expected = NULL;
|
_cleanup_free_ char *found = NULL, *expected = NULL;
|
||||||
|
|
||||||
found = hexmem(root_hash.iov_base, root_hash.iov_len);
|
found = hexmem(root_hash, root_hash_size);
|
||||||
expected = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len);
|
expected = hexmem(verity->root_hash, verity->root_hash_size);
|
||||||
|
|
||||||
log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected));
|
log_debug("Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(found), strna(expected));
|
||||||
}
|
}
|
||||||
@ -1594,7 +1609,7 @@ static int dissect_image(
|
|||||||
if (!m->partitions[PARTITION_ROOT].found &&
|
if (!m->partitions[PARTITION_ROOT].found &&
|
||||||
!m->partitions[PARTITION_USR].found &&
|
!m->partitions[PARTITION_USR].found &&
|
||||||
(flags & DISSECT_IMAGE_GENERIC_ROOT) &&
|
(flags & DISSECT_IMAGE_GENERIC_ROOT) &&
|
||||||
(!verity || !iovec_is_set(&verity->root_hash) || verity->designator != PARTITION_USR)) {
|
(!verity || !verity->root_hash || verity->designator != PARTITION_USR)) {
|
||||||
|
|
||||||
/* OK, we found nothing usable, then check if there's a single generic partition, and use
|
/* 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
|
* that. If the root hash was set however, then we won't fall back to a generic node, because
|
||||||
@ -1679,7 +1694,7 @@ static int dissect_image(
|
|||||||
partition_designator_to_string(verity->designator),
|
partition_designator_to_string(verity->designator),
|
||||||
partition_designator_to_string(verity->designator));
|
partition_designator_to_string(verity->designator));
|
||||||
|
|
||||||
if (iovec_is_set(&verity->root_hash)) {
|
if (verity->root_hash) {
|
||||||
/* If we have an explicit root hash and found the partitions for it, then we are ready to use
|
/* 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 */
|
* Verity, set things up for it */
|
||||||
|
|
||||||
@ -1715,7 +1730,7 @@ static int dissect_image(
|
|||||||
|
|
||||||
m->verity_ready = true;
|
m->verity_ready = true;
|
||||||
|
|
||||||
if (iovec_is_set(&verity->root_hash_sig))
|
if (verity->root_hash_sig)
|
||||||
m->verity_sig_ready = true;
|
m->verity_sig_ready = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2752,8 +2767,10 @@ static int verity_can_reuse(
|
|||||||
struct crypt_device **ret_cd) {
|
struct crypt_device **ret_cd) {
|
||||||
|
|
||||||
/* If the same volume was already open, check that the root hashes match, and reuse it if they do */
|
/* 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;
|
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
|
||||||
struct crypt_params_verity crypt_params = {};
|
struct crypt_params_verity crypt_params = {};
|
||||||
|
size_t root_hash_existing_size;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(verity);
|
assert(verity);
|
||||||
@ -2770,23 +2787,22 @@ static int verity_can_reuse(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
|
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash_existing = {
|
root_hash_existing_size = verity->root_hash_size;
|
||||||
.iov_base = malloc0(verity->root_hash.iov_len),
|
root_hash_existing = malloc0(root_hash_existing_size);
|
||||||
.iov_len = verity->root_hash.iov_len,
|
if (!root_hash_existing)
|
||||||
};
|
|
||||||
if (!root_hash_existing.iov_base)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing.iov_base, &root_hash_existing.iov_len, NULL, 0);
|
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m");
|
return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m");
|
||||||
if (iovec_memcmp(&verity->root_hash, &root_hash_existing) != 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.");
|
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
|
/* 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
|
* 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. */
|
* signing for the new one, and vice versa. */
|
||||||
if (iovec_is_set(&verity->root_hash_sig) != FLAGS_SET(crypt_params.flags, CRYPT_VERITY_ROOT_HASH_SIGNATURE))
|
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.");
|
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);
|
*ret_cd = TAKE_PTR(cd);
|
||||||
@ -2840,9 +2856,11 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma
|
|||||||
_cleanup_free_ char *s = NULL;
|
_cleanup_free_ char *s = NULL;
|
||||||
_cleanup_(BIO_freep) BIO *bio = NULL; /* 'bio' must be freed first, 's' second, hence keep this order
|
_cleanup_(BIO_freep) BIO *bio = NULL; /* 'bio' must be freed first, 's' second, hence keep this order
|
||||||
* of declaration in place, please */
|
* of declaration in place, please */
|
||||||
|
const unsigned char *d;
|
||||||
|
|
||||||
assert(verity);
|
assert(verity);
|
||||||
assert(iovec_is_set(&verity->root_hash));
|
assert(verity->root_hash);
|
||||||
assert(iovec_is_set(&verity->root_hash_sig));
|
assert(verity->root_hash_sig);
|
||||||
|
|
||||||
/* Because installing a signature certificate into the kernel chain is so messy, let's optionally do
|
/* Because installing a signature certificate into the kernel chain is so messy, let's optionally do
|
||||||
* userspace validation. */
|
* userspace validation. */
|
||||||
@ -2855,12 +2873,12 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char *d = verity->root_hash_sig.iov_base;
|
d = verity->root_hash_sig;
|
||||||
p7 = d2i_PKCS7(NULL, &d, (long) verity->root_hash_sig.iov_len);
|
p7 = d2i_PKCS7(NULL, &d, (long) verity->root_hash_sig_size);
|
||||||
if (!p7)
|
if (!p7)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PKCS7 DER signature data.");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PKCS7 DER signature data.");
|
||||||
|
|
||||||
s = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len);
|
s = hexmem(verity->root_hash, verity->root_hash_size);
|
||||||
if (!s)
|
if (!s)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
@ -2921,7 +2939,7 @@ static int do_crypt_activate_verity(
|
|||||||
assert(name);
|
assert(name);
|
||||||
assert(verity);
|
assert(verity);
|
||||||
|
|
||||||
if (iovec_is_set(&verity->root_hash_sig) && FLAGS_SET(policy_flags, PARTITION_POLICY_SIGNED)) {
|
if (verity->root_hash_sig && FLAGS_SET(policy_flags, PARTITION_POLICY_SIGNED)) {
|
||||||
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
||||||
if (r < 0 && r != -ENXIO)
|
if (r < 0 && r != -ENXIO)
|
||||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_SIGNATURE");
|
||||||
@ -2935,10 +2953,10 @@ static int do_crypt_activate_verity(
|
|||||||
r = sym_crypt_activate_by_signed_key(
|
r = sym_crypt_activate_by_signed_key(
|
||||||
cd,
|
cd,
|
||||||
name,
|
name,
|
||||||
verity->root_hash.iov_base,
|
verity->root_hash,
|
||||||
verity->root_hash.iov_len,
|
verity->root_hash_size,
|
||||||
verity->root_hash_sig.iov_base,
|
verity->root_hash_sig,
|
||||||
verity->root_hash_sig.iov_len,
|
verity->root_hash_sig_size,
|
||||||
CRYPT_ACTIVATE_READONLY);
|
CRYPT_ACTIVATE_READONLY);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
log_debug("Verity activation via kernel signature logic worked.");
|
log_debug("Verity activation via kernel signature logic worked.");
|
||||||
@ -2982,8 +3000,8 @@ static int do_crypt_activate_verity(
|
|||||||
r = sym_crypt_activate_by_volume_key(
|
r = sym_crypt_activate_by_volume_key(
|
||||||
cd,
|
cd,
|
||||||
name,
|
name,
|
||||||
verity->root_hash.iov_base,
|
verity->root_hash,
|
||||||
verity->root_hash.iov_len,
|
verity->root_hash_size,
|
||||||
CRYPT_ACTIVATE_READONLY);
|
CRYPT_ACTIVATE_READONLY);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Activation of Verity via root hash failed: %m");
|
return log_debug_errno(r, "Activation of Verity via root hash failed: %m");
|
||||||
@ -3031,7 +3049,7 @@ static int verity_partition(
|
|||||||
assert(m);
|
assert(m);
|
||||||
assert(v || (verity && verity->data_path));
|
assert(v || (verity && verity->data_path));
|
||||||
|
|
||||||
if (!verity || !iovec_is_set(&verity->root_hash))
|
if (!verity || !verity->root_hash)
|
||||||
return 0;
|
return 0;
|
||||||
if (!((verity->designator < 0 && designator == PARTITION_ROOT) ||
|
if (!((verity->designator < 0 && designator == PARTITION_ROOT) ||
|
||||||
(verity->designator == designator)))
|
(verity->designator == designator)))
|
||||||
@ -3060,7 +3078,7 @@ static int verity_partition(
|
|||||||
/* Use the roothash, which is unique per volume, as the device node name, so that it can be reused */
|
/* 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;
|
_cleanup_free_ char *root_hash_encoded = NULL;
|
||||||
|
|
||||||
root_hash_encoded = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len);
|
root_hash_encoded = hexmem(verity->root_hash, verity->root_hash_size);
|
||||||
if (!root_hash_encoded)
|
if (!root_hash_encoded)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -3228,8 +3246,7 @@ int dissected_image_decrypt(
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(!verity || iovec_is_valid(&verity->root_hash));
|
assert(!verity || verity->root_hash || verity->root_hash_size == 0);
|
||||||
assert(!verity || iovec_is_valid(&verity->root_hash_sig));
|
|
||||||
|
|
||||||
/* Returns:
|
/* Returns:
|
||||||
*
|
*
|
||||||
@ -3243,7 +3260,7 @@ int dissected_image_decrypt(
|
|||||||
* -EEXIST → DM device already exists under the specified name
|
* -EEXIST → DM device already exists under the specified name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (verity && iovec_is_set(&verity->root_hash) && verity->root_hash.iov_len < sizeof(sd_id128_t))
|
if (verity && verity->root_hash && verity->root_hash_size < sizeof(sd_id128_t))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!m->encrypted && !m->verity_ready)
|
if (!m->encrypted && !m->verity_ready)
|
||||||
@ -3470,8 +3487,12 @@ static char *build_auxiliary_path(const char *image, const char *suffix) {
|
|||||||
void verity_settings_done(VeritySettings *v) {
|
void verity_settings_done(VeritySettings *v) {
|
||||||
assert(v);
|
assert(v);
|
||||||
|
|
||||||
iovec_done(&v->root_hash);
|
v->root_hash = mfree(v->root_hash);
|
||||||
iovec_done(&v->root_hash_sig);
|
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);
|
v->data_path = mfree(v->data_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3486,15 +3507,18 @@ VeritySettings* verity_settings_free(VeritySettings *v) {
|
|||||||
void verity_settings_hash_func(const VeritySettings *s, struct siphash *state) {
|
void verity_settings_hash_func(const VeritySettings *s, struct siphash *state) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
siphash24_compress_typesafe(s->root_hash.iov_len, state);
|
siphash24_compress_typesafe(s->root_hash_size, state);
|
||||||
siphash24_compress(s->root_hash.iov_base, s->root_hash.iov_len, state);
|
siphash24_compress(s->root_hash, s->root_hash_size, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
int verity_settings_compare_func(const VeritySettings *x, const VeritySettings *y) {
|
int verity_settings_compare_func(const VeritySettings *x, const VeritySettings *y) {
|
||||||
assert(x);
|
int r;
|
||||||
assert(y);
|
|
||||||
|
|
||||||
return iovec_memcmp(&x->root_hash, &y->root_hash);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(verity_settings_hash_ops, VeritySettings, verity_settings_hash_func, verity_settings_compare_func, VeritySettings, verity_settings_free);
|
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(verity_settings_hash_ops, VeritySettings, verity_settings_hash_func, verity_settings_compare_func, VeritySettings, verity_settings_free);
|
||||||
@ -3505,6 +3529,9 @@ int verity_settings_load(
|
|||||||
const char *root_hash_path,
|
const char *root_hash_path,
|
||||||
const char *root_hash_sig_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;
|
PartitionDesignator designator;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -3526,8 +3553,7 @@ int verity_settings_load(
|
|||||||
|
|
||||||
/* We only fill in what isn't already filled in */
|
/* We only fill in what isn't already filled in */
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash = {};
|
if (!verity->root_hash) {
|
||||||
if (!iovec_is_set(&verity->root_hash)) {
|
|
||||||
_cleanup_free_ char *text = NULL;
|
_cleanup_free_ char *text = NULL;
|
||||||
|
|
||||||
if (root_hash_path) {
|
if (root_hash_path) {
|
||||||
@ -3594,24 +3620,20 @@ int verity_settings_load(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (text) {
|
if (text) {
|
||||||
r = unhexmem(text, &root_hash.iov_base, &root_hash.iov_len);
|
r = unhexmem(text, &root_hash, &root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (root_hash.iov_len < sizeof(sd_id128_t))
|
if (root_hash_size < sizeof(sd_id128_t))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash_sig = {};
|
if ((root_hash || verity->root_hash) && !verity->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) {
|
if (root_hash_sig_path) {
|
||||||
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len);
|
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (r >= 0 && root_hash_sig.iov_len == 0) /* refuse empty size signatures */
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (designator < 0)
|
if (designator < 0)
|
||||||
designator = PARTITION_ROOT;
|
designator = PARTITION_ROOT;
|
||||||
} else {
|
} else {
|
||||||
@ -3624,36 +3646,32 @@ int verity_settings_load(
|
|||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = read_full_file(p, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len);
|
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
if (r >= 0) {
|
if (r >= 0)
|
||||||
designator = PARTITION_ROOT;
|
designator = PARTITION_ROOT;
|
||||||
if (root_hash_sig.iov_len == 0) /* refuse empty size signatures */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iovec_is_set(&root_hash_sig) && (designator < 0 || designator == PARTITION_USR)) {
|
if (!root_hash_sig && (designator < 0 || designator == PARTITION_USR)) {
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
p = build_auxiliary_path(image, ".usrhash.p7s");
|
p = build_auxiliary_path(image, ".usrhash.p7s");
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = read_full_file(p, (char**) &root_hash_sig.iov_base, &root_hash_sig.iov_len);
|
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
if (r >= 0) {
|
if (r >= 0)
|
||||||
designator = PARTITION_USR;
|
designator = PARTITION_USR;
|
||||||
if (root_hash_sig.iov_len == 0) /* refuse empty size signatures */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_free_ char *verity_data_path = NULL;
|
if (root_hash_sig && root_hash_sig_size == 0) /* refuse empty size signatures */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!verity->data_path) {
|
if (!verity->data_path) {
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
@ -3668,11 +3686,15 @@ int verity_settings_load(
|
|||||||
verity_data_path = TAKE_PTR(p);
|
verity_data_path = TAKE_PTR(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iovec_is_set(&root_hash))
|
if (root_hash) {
|
||||||
verity->root_hash = TAKE_STRUCT(root_hash);
|
verity->root_hash = TAKE_PTR(root_hash);
|
||||||
|
verity->root_hash_size = root_hash_size;
|
||||||
|
}
|
||||||
|
|
||||||
if (iovec_is_set(&root_hash_sig))
|
if (root_hash_sig) {
|
||||||
verity->root_hash_sig = TAKE_STRUCT(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)
|
if (verity_data_path)
|
||||||
verity->data_path = TAKE_PTR(verity_data_path);
|
verity->data_path = TAKE_PTR(verity_data_path);
|
||||||
@ -3691,15 +3713,17 @@ int verity_settings_copy(VeritySettings *dest, const VeritySettings *source) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec rh = {};
|
_cleanup_free_ void *rh = NULL;
|
||||||
if (iovec_is_set(&source->root_hash)) {
|
if (source->root_hash_size > 0) {
|
||||||
if (!iovec_memdup(&source->root_hash, &rh))
|
rh = memdup(source->root_hash, source->root_hash_size);
|
||||||
|
if (!rh)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec sig = {};
|
_cleanup_free_ void *sig = NULL;
|
||||||
if (iovec_is_set(&source->root_hash_sig)) {
|
if (source->root_hash_sig_size > 0) {
|
||||||
if (!iovec_memdup(&source->root_hash_sig, &sig))
|
sig = memdup(source->root_hash_sig, source->root_hash_sig_size);
|
||||||
|
if (!sig)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3711,8 +3735,10 @@ int verity_settings_copy(VeritySettings *dest, const VeritySettings *source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*dest = (VeritySettings) {
|
*dest = (VeritySettings) {
|
||||||
.root_hash = TAKE_STRUCT(rh),
|
.root_hash = TAKE_PTR(rh),
|
||||||
.root_hash_sig = TAKE_STRUCT(sig),
|
.root_hash_size = source->root_hash_size,
|
||||||
|
.root_hash_sig = TAKE_PTR(sig),
|
||||||
|
.root_hash_sig_size = source->root_hash_sig_size,
|
||||||
.data_path = TAKE_PTR(p),
|
.data_path = TAKE_PTR(p),
|
||||||
.designator = source->designator,
|
.designator = source->designator,
|
||||||
};
|
};
|
||||||
@ -3731,7 +3757,7 @@ int dissected_image_load_verity_sig_partition(
|
|||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(verity);
|
assert(verity);
|
||||||
|
|
||||||
if (iovec_is_set(&verity->root_hash) && iovec_is_set(&verity->root_hash_sig)) /* Already loaded? */
|
if (verity->root_hash && verity->root_hash_sig) /* Already loaded? */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_EMBEDDED");
|
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_EMBEDDED");
|
||||||
@ -3765,32 +3791,29 @@ int dissected_image_load_verity_sig_partition(
|
|||||||
if (!p->found)
|
if (!p->found)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec root_hash = {}, root_hash_sig = {};
|
_cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL;
|
||||||
r = acquire_sig_for_roothash(
|
size_t root_hash_size, root_hash_sig_size;
|
||||||
fd,
|
|
||||||
p->offset,
|
r = acquire_sig_for_roothash(fd, p->offset, p->size, &root_hash, &root_hash_size, &root_hash_sig, &root_hash_sig_size);
|
||||||
p->size,
|
|
||||||
&root_hash,
|
|
||||||
&root_hash_sig);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Check if specified root hash matches if it is specified */
|
/* Check if specified root hash matches if it is specified */
|
||||||
if (iovec_is_set(&verity->root_hash) &&
|
if (verity->root_hash &&
|
||||||
iovec_memcmp(&verity->root_hash, &root_hash) != 0) {
|
memcmp_nn(verity->root_hash, verity->root_hash_size, root_hash, root_hash_size) != 0) {
|
||||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||||
|
|
||||||
a = hexmem(root_hash.iov_base, root_hash.iov_len);
|
a = hexmem(root_hash, root_hash_size);
|
||||||
b = hexmem(verity->root_hash.iov_base, verity->root_hash.iov_len);
|
b = hexmem(verity->root_hash, verity->root_hash_size);
|
||||||
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(a), strna(b));
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(a), strna(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec_done(&verity->root_hash);
|
free_and_replace(verity->root_hash, root_hash);
|
||||||
verity->root_hash = TAKE_STRUCT(root_hash);
|
verity->root_hash_size = root_hash_size;
|
||||||
|
|
||||||
iovec_done(&verity->root_hash_sig);
|
free_and_replace(verity->root_hash_sig, root_hash_sig);
|
||||||
verity->root_hash_sig = TAKE_STRUCT(root_hash_sig);
|
verity->root_hash_sig_size = root_hash_sig_size;
|
||||||
|
|
||||||
verity->designator = dd;
|
verity->designator = dd;
|
||||||
|
|
||||||
@ -3818,7 +3841,7 @@ int dissected_image_guess_verity_roothash(
|
|||||||
* Note of course that relying on this guesswork is mostly useful for later attestation, not so much
|
* Note of course that relying on this guesswork is mostly useful for later attestation, not so much
|
||||||
* for a-priori security. */
|
* for a-priori security. */
|
||||||
|
|
||||||
if (iovec_is_set(&verity->root_hash)) /* Already loaded? */
|
if (verity->root_hash) /* Already loaded? */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_GUESS");
|
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_GUESS");
|
||||||
@ -3848,12 +3871,13 @@ int dissected_image_guess_verity_roothash(
|
|||||||
if (!p->found)
|
if (!p->found)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_cleanup_free_ void *rh = malloc(sizeof(sd_id128_t) * 2);
|
_cleanup_free_ uint8_t *rh = malloc(sizeof(sd_id128_t) * 2);
|
||||||
if (!rh)
|
if (!rh)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
memcpy(mempcpy(rh, &d->uuid, sizeof(sd_id128_t)), &p->uuid, sizeof(sd_id128_t));
|
memcpy(mempcpy(rh, &d->uuid, sizeof(sd_id128_t)), &p->uuid, sizeof(sd_id128_t));
|
||||||
verity->root_hash = IOVEC_MAKE(TAKE_PTR(rh), sizeof(sd_id128_t) * 2);
|
verity->root_hash = TAKE_PTR(rh);
|
||||||
|
verity->root_hash_size = sizeof(sd_id128_t) * 2;
|
||||||
|
|
||||||
verity->designator = dd;
|
verity->designator = dd;
|
||||||
|
|
||||||
@ -4814,8 +4838,8 @@ int mountfsd_mount_image(
|
|||||||
SD_JSON_BUILD_PAIR_CONDITION(!!ps, "imagePolicy", SD_JSON_BUILD_STRING(ps)),
|
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("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)),
|
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", &verity->root_hash),
|
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", &verity->root_hash_sig),
|
JSON_BUILD_PAIR_IOVEC_BASE64("verityRootHashSignature", &((struct iovec) { .iov_base = verity->root_hash_sig, .iov_len = verity->root_hash_sig_size })),
|
||||||
SD_JSON_BUILD_PAIR("allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH))));
|
SD_JSON_BUILD_PAIR("allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH))));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -4,10 +4,9 @@
|
|||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "architecture.h"
|
#include "architecture.h"
|
||||||
#include "gpt.h"
|
|
||||||
#include "iovec-util.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "shared-forward.h"
|
#include "shared-forward.h"
|
||||||
|
#include "gpt.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
typedef struct DecryptedImage DecryptedImage;
|
typedef struct DecryptedImage DecryptedImage;
|
||||||
|
|
||||||
@ -121,10 +120,12 @@ typedef struct MountOptions {
|
|||||||
|
|
||||||
typedef struct VeritySettings {
|
typedef struct VeritySettings {
|
||||||
/* Binary root hash for the Verity Merkle tree */
|
/* Binary root hash for the Verity Merkle tree */
|
||||||
struct iovec root_hash;
|
void *root_hash;
|
||||||
|
size_t root_hash_size;
|
||||||
|
|
||||||
/* PKCS#7 signature of the above */
|
/* PKCS#7 signature of the above */
|
||||||
struct iovec root_hash_sig;
|
void *root_hash_sig;
|
||||||
|
size_t root_hash_sig_size;
|
||||||
|
|
||||||
/* Path to the verity data file, if stored externally */
|
/* Path to the verity data file, if stored externally */
|
||||||
char *data_path;
|
char *data_path;
|
||||||
@ -205,9 +206,9 @@ int verity_settings_load(VeritySettings *verity, const char *image, const char *
|
|||||||
|
|
||||||
static inline bool verity_settings_set(const VeritySettings *settings) {
|
static inline bool verity_settings_set(const VeritySettings *settings) {
|
||||||
return settings &&
|
return settings &&
|
||||||
(iovec_is_set(&settings->root_hash) ||
|
(settings->root_hash_size > 0 ||
|
||||||
iovec_is_set(&settings->root_hash_sig) ||
|
(settings->root_hash_sig_size > 0 ||
|
||||||
settings->data_path);
|
settings->data_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void verity_settings_done(VeritySettings *verity);
|
void verity_settings_done(VeritySettings *verity);
|
||||||
@ -222,7 +223,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 */
|
/* Returns true if the verity settings contain sufficient information to cover the specified partition */
|
||||||
return verity &&
|
return verity &&
|
||||||
((d >= 0 && verity->designator == d) || (d == PARTITION_ROOT && verity->designator < 0)) &&
|
((d >= 0 && verity->designator == d) || (d == PARTITION_ROOT && verity->designator < 0)) &&
|
||||||
iovec_is_set(&verity->root_hash) &&
|
verity->root_hash &&
|
||||||
verity->data_path;
|
verity->data_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ static int acquire_verity_settings(VeritySettings *ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (h) {
|
if (h) {
|
||||||
r = unhexmem(h, &verity.root_hash.iov_base, &verity.root_hash.iov_len);
|
r = unhexmem(h, &verity.root_hash, &verity.root_hash_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash from kernel command line switch: %m");
|
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 (d == verity.designator) {
|
||||||
if (iovec_is_set(&verity.root_hash)) {
|
if (verity.root_hash_size > 0) {
|
||||||
_cleanup_free_ char *f = NULL;
|
_cleanup_free_ char *f = NULL;
|
||||||
if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH", p->partno) < 0)
|
if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH", p->partno) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
_cleanup_free_ char *h = hexmem(verity.root_hash.iov_base, verity.root_hash.iov_len);
|
_cleanup_free_ char *h = hexmem(verity.root_hash, verity.root_hash_size);
|
||||||
if (!h)
|
if (!h)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
(void) udev_builtin_add_property(event, f, h);
|
(void) udev_builtin_add_property(event, f, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iovec_is_set(&verity.root_hash_sig)) {
|
if (verity.root_hash_sig_size > 0) {
|
||||||
_cleanup_free_ char *f = NULL;
|
_cleanup_free_ char *f = NULL;
|
||||||
if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH_SIG", p->partno) < 0)
|
if (asprintf(&f, "ID_DISSECT_PART%i_ROOTHASH_SIG", p->partno) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
_cleanup_free_ char *h = NULL;
|
_cleanup_free_ char *h = NULL;
|
||||||
if (base64mem(verity.root_hash_sig.iov_base, verity.root_hash_sig.iov_len, &h) < 0)
|
if (base64mem(verity.root_hash_sig, verity.root_hash_sig_size, &h) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
(void) udev_builtin_add_property(event, f, h);
|
(void) udev_builtin_add_property(event, f, h);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user