1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-01 09:21:26 +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:
Lennart Poettering 2021-09-09 13:46:01 +02:00
parent 8ee9615e10
commit 88b3300fdc
6 changed files with 167 additions and 0 deletions

View File

@ -1913,6 +1913,13 @@ int setup_namespace(
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m"); 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( r = dissected_image_decrypt(
dissected_image, dissected_image,
NULL, NULL,

View File

@ -805,6 +805,13 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
return r; return r;
r = dissected_image_load_verity_sig_partition(
m,
d->fd,
&arg_verity_settings);
if (r < 0)
return r;
switch (arg_action) { switch (arg_action) {
case ACTION_DISSECT: case ACTION_DISSECT:

View File

@ -5710,6 +5710,13 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
goto finish; 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) 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 " 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);

View File

@ -27,6 +27,7 @@
#include "dissect-image.h" #include "dissect-image.h"
#include "dm-util.h" #include "dm-util.h"
#include "env-file.h" #include "env-file.h"
#include "env-util.h"
#include "extension-release.h" #include "extension-release.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
@ -826,6 +827,8 @@ int dissect_image(
.fstype = TAKE_PTR(t), .fstype = TAKE_PTR(t),
.node = TAKE_PTR(n), .node = TAKE_PTR(n),
.mount_options = TAKE_PTR(o), .mount_options = TAKE_PTR(o),
.offset = 0,
.size = UINT64_MAX,
}; };
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
@ -869,6 +872,7 @@ int dissect_image(
for (int i = 0; i < n_partitions; i++) { for (int i = 0; i < n_partitions; i++) {
_cleanup_(sd_device_unrefp) sd_device *q = NULL; _cleanup_(sd_device_unrefp) sd_device *q = NULL;
unsigned long long pflags; unsigned long long pflags;
blkid_loff_t start, size;
blkid_partition pp; blkid_partition pp;
const char *node; const char *node;
int nr; int nr;
@ -893,6 +897,20 @@ int dissect_image(
if (nr < 0) if (nr < 0)
return errno_or_else(EIO); 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) { if (is_gpt) {
PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID; PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
int architecture = _ARCHITECTURE_INVALID; int architecture = _ARCHITECTURE_INVALID;
@ -1337,6 +1355,8 @@ int dissect_image(
.label = TAKE_PTR(l), .label = TAKE_PTR(l),
.uuid = id, .uuid = id,
.mount_options = TAKE_PTR(o), .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), .node = TAKE_PTR(n),
.uuid = id, .uuid = id,
.mount_options = TAKE_PTR(o), .mount_options = TAKE_PTR(o),
.offset = (uint64_t) start * 512,
.size = (uint64_t) size * 512,
}; };
break; break;
@ -1515,6 +1537,8 @@ int dissect_image(
.node = TAKE_PTR(generic_node), .node = TAKE_PTR(generic_node),
.uuid = generic_uuid, .uuid = generic_uuid,
.mount_options = TAKE_PTR(o), .mount_options = TAKE_PTR(o),
.offset = UINT64_MAX,
.size = UINT64_MAX,
}; };
} }
} }
@ -2741,6 +2765,109 @@ int verity_settings_load(
return 1; 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) { int dissected_image_acquire_metadata(DissectedImage *m) {
enum { enum {
@ -3131,6 +3258,10 @@ int mount_image_privately_interactively(
if (r < 0) if (r < 0)
return r; 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); r = dissected_image_decrypt_interactively(dissected_image, NULL, &verity, flags, &decrypted_image);
if (r < 0) if (r < 0)
return r; return r;
@ -3241,6 +3372,10 @@ int verity_dissect_and_mount(
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m"); 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( r = dissected_image_decrypt(
dissected_image, dissected_image,
NULL, NULL,

View File

@ -28,6 +28,8 @@ struct DissectedPartition {
char *decrypted_node; char *decrypted_node;
char *decrypted_fstype; char *decrypted_fstype;
char *mount_options; char *mount_options;
uint64_t size;
uint64_t offset;
}; };
typedef enum PartitionDesignator { 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); 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); 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_candidate(const DissectedImage *image, PartitionDesignator d);
bool dissected_image_verity_ready(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); bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d);

View File

@ -540,6 +540,13 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
if (r < 0) if (r < 0)
return r; return r;
r = dissected_image_load_verity_sig_partition(
m,
d->fd,
&verity_settings);
if (r < 0)
return r;
r = dissected_image_decrypt_interactively( r = dissected_image_decrypt_interactively(
m, NULL, m, NULL,
&verity_settings, &verity_settings,