mirror of
https://github.com/systemd/systemd.git
synced 2024-11-01 00:51:24 +03:00
dissect-image: load embedded verity signature info from image
This adds support for actually using embedded signature data from partitions.
This commit is contained in:
parent
8ee9615e10
commit
88b3300fdc
@ -1913,6 +1913,13 @@ int setup_namespace(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
dissected_image,
|
||||
loop_device->fd,
|
||||
&verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
@ -805,6 +805,13 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
m,
|
||||
d->fd,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch (arg_action) {
|
||||
|
||||
case ACTION_DISSECT:
|
||||
|
@ -5710,6 +5710,13 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
dissected_image,
|
||||
loop->fd,
|
||||
&arg_verity_settings);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (dissected_image->has_verity && !arg_verity_settings.root_hash && !dissected_image->has_verity_sig)
|
||||
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);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "dissect-image.h"
|
||||
#include "dm-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "extension-release.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -826,6 +827,8 @@ int dissect_image(
|
||||
.fstype = TAKE_PTR(t),
|
||||
.node = TAKE_PTR(n),
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = 0,
|
||||
.size = UINT64_MAX,
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
@ -869,6 +872,7 @@ int dissect_image(
|
||||
for (int i = 0; i < n_partitions; i++) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *q = NULL;
|
||||
unsigned long long pflags;
|
||||
blkid_loff_t start, size;
|
||||
blkid_partition pp;
|
||||
const char *node;
|
||||
int nr;
|
||||
@ -893,6 +897,20 @@ int dissect_image(
|
||||
if (nr < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
errno = 0;
|
||||
start = blkid_partition_get_start(pp);
|
||||
if (start < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
assert((uint64_t) start < UINT64_MAX/512);
|
||||
|
||||
errno = 0;
|
||||
size = blkid_partition_get_size(pp);
|
||||
if (size < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
assert((uint64_t) size < UINT64_MAX/512);
|
||||
|
||||
if (is_gpt) {
|
||||
PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
|
||||
int architecture = _ARCHITECTURE_INVALID;
|
||||
@ -1337,6 +1355,8 @@ int dissect_image(
|
||||
.label = TAKE_PTR(l),
|
||||
.uuid = id,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = (uint64_t) start * 512,
|
||||
.size = (uint64_t) size * 512,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1395,6 +1415,8 @@ int dissect_image(
|
||||
.node = TAKE_PTR(n),
|
||||
.uuid = id,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = (uint64_t) start * 512,
|
||||
.size = (uint64_t) size * 512,
|
||||
};
|
||||
|
||||
break;
|
||||
@ -1515,6 +1537,8 @@ int dissect_image(
|
||||
.node = TAKE_PTR(generic_node),
|
||||
.uuid = generic_uuid,
|
||||
.mount_options = TAKE_PTR(o),
|
||||
.offset = UINT64_MAX,
|
||||
.size = UINT64_MAX,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -2741,6 +2765,109 @@ int verity_settings_load(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_load_verity_sig_partition(
|
||||
DissectedImage *m,
|
||||
int fd,
|
||||
VeritySettings *verity) {
|
||||
|
||||
_cleanup_free_ void *root_hash = NULL, *root_hash_sig = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
size_t root_hash_size, root_hash_sig_size;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
PartitionDesignator d;
|
||||
DissectedPartition *p;
|
||||
JsonVariant *rh, *sig;
|
||||
ssize_t n;
|
||||
char *e;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(fd >= 0);
|
||||
assert(verity);
|
||||
|
||||
if (verity->root_hash && verity->root_hash_sig) /* Already loaded? */
|
||||
return 0;
|
||||
|
||||
r = getenv_bool_secure("SYSTEMD_DISSECT_VERITY_EMBEDDED");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DISSECT_VERITY_EMBEDDED, ignoring: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
d = PARTITION_VERITY_SIG_OF(verity->designator < 0 ? PARTITION_ROOT : verity->designator);
|
||||
assert(d >= 0);
|
||||
|
||||
p = m->partitions + d;
|
||||
if (!p->found)
|
||||
return 0;
|
||||
if (p->offset == UINT64_MAX || p->size == UINT64_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->size > 4*1024*1024) /* Signature data cannot possible be larger than 4M, refuse that */
|
||||
return -EFBIG;
|
||||
|
||||
buf = new(char, p->size+1);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
n = pread(fd, buf, p->size, p->offset);
|
||||
if (n < 0)
|
||||
return -ENOMEM;
|
||||
if ((uint64_t) n != p->size)
|
||||
return -EIO;
|
||||
|
||||
e = memchr(buf, 0, p->size);
|
||||
if (e) {
|
||||
/* If we found a NUL byte then the rest of the data must be NUL too */
|
||||
if (!memeqzero(e, p->size - (e - buf)))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature data contains embedded NUL byte.");
|
||||
} else
|
||||
buf[p->size] = 0;
|
||||
|
||||
r = json_parse(buf, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse signature JSON data: %m");
|
||||
|
||||
rh = json_variant_by_key(v, "rootHash");
|
||||
if (!rh)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'rootHash' field.");
|
||||
if (!json_variant_is_string(rh))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "'rootHash' field of signature JSON object is not a string.");
|
||||
|
||||
r = unhexmem(json_variant_string(rh), SIZE_MAX, &root_hash, &root_hash_size);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse root hash field: %m");
|
||||
|
||||
/* 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) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
|
||||
a = hexmem(root_hash, root_hash_size);
|
||||
b = hexmem(verity->root_hash, verity->root_hash_size);
|
||||
|
||||
return log_debug_errno(r, "Root hash in signature JSON data (%s) doesn't match configured hash (%s).", strna(a), strna(b));
|
||||
}
|
||||
|
||||
sig = json_variant_by_key(v, "signature");
|
||||
if (!sig)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature JSON object lacks 'signature' field.");
|
||||
if (!json_variant_is_string(sig))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "'signature' field of signature JSON object is not a string.");
|
||||
|
||||
r = unbase64mem(json_variant_string(sig), SIZE_MAX, &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse signature field: %m");
|
||||
|
||||
free_and_replace(verity->root_hash, root_hash);
|
||||
verity->root_hash_size = root_hash_size;
|
||||
|
||||
free_and_replace(verity->root_hash_sig, root_hash_sig);
|
||||
verity->root_hash_sig_size = root_hash_sig_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_acquire_metadata(DissectedImage *m) {
|
||||
|
||||
enum {
|
||||
@ -3131,6 +3258,10 @@ int mount_image_privately_interactively(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(dissected_image, d->fd, &verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, &verity, flags, &decrypted_image);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -3241,6 +3372,10 @@ int verity_dissect_and_mount(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(dissected_image, loop_device->fd, &verity);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
|
@ -28,6 +28,8 @@ struct DissectedPartition {
|
||||
char *decrypted_node;
|
||||
char *decrypted_fstype;
|
||||
char *mount_options;
|
||||
uint64_t size;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
typedef enum PartitionDesignator {
|
||||
@ -217,6 +219,8 @@ PartitionDesignator partition_designator_from_string(const char *name) _pure_;
|
||||
int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
|
||||
void verity_settings_done(VeritySettings *verity);
|
||||
|
||||
int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity);
|
||||
|
||||
bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
|
||||
bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d);
|
||||
bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d);
|
||||
|
@ -540,6 +540,13 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_load_verity_sig_partition(
|
||||
m,
|
||||
d->fd,
|
||||
&verity_settings);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_decrypt_interactively(
|
||||
m, NULL,
|
||||
&verity_settings,
|
||||
|
Loading…
Reference in New Issue
Block a user