diff options
Diffstat (limited to 'src/shared/dissect-image.c')
-rw-r--r-- | src/shared/dissect-image.c | 161 |
1 files changed, 110 insertions, 51 deletions
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 8decac94b2..2c8a5d85bf 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -307,6 +307,7 @@ int dissect_image( int fd, const void *root_hash, size_t root_hash_size, + const char *verity_data, DissectImageFlags flags, DissectedImage **ret) { @@ -329,6 +330,7 @@ int dissect_image( assert(fd >= 0); assert(ret); assert(root_hash || root_hash_size == 0); + assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE))); /* Probes a disk image, and returns information about what it found in *ret. * @@ -391,8 +393,9 @@ int dissect_image( if (r < 0) return r; - if (!(flags & DISSECT_IMAGE_GPT_ONLY) && - (flags & DISSECT_IMAGE_REQUIRE_ROOT)) { + if ((!(flags & DISSECT_IMAGE_GPT_ONLY) && + (flags & DISSECT_IMAGE_REQUIRE_ROOT)) || + (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) { const char *usage = NULL; (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); @@ -413,9 +416,13 @@ int dissect_image( if (r < 0) return r; + m->single_file_system = true; + m->verity = root_hash && verity_data; + m->can_verity = !!verity_data; + m->partitions[PARTITION_ROOT] = (DissectedPartition) { .found = true, - .rw = true, + .rw = !m->verity, .partno = -1, .architecture = _ARCHITECTURE_INVALID, .fstype = TAKE_PTR(t), @@ -424,11 +431,11 @@ int dissect_image( m->encrypted = streq_ptr(fstype, "crypto_LUKS"); - if (!streq(usage, "filesystem")) { - r = loop_wait_for_partitions_to_appear(fd, d, 0, flags, &e); - if (r < 0) - return r; - } + /* Even on a single partition we need to wait for udev to create the + * /dev/block/X:Y symlink to /dev/loopZ */ + r = loop_wait_for_partitions_to_appear(fd, d, 0, flags, &e); + if (r < 0) + return r; *ret = TAKE_PTR(m); return 0; @@ -1215,6 +1222,7 @@ static int verity_partition( DissectedPartition *v, const void *root_hash, size_t root_hash_size, + const char *verity_data, DissectImageFlags flags, DecryptedImage *d) { @@ -1223,18 +1231,20 @@ static int verity_partition( int r; assert(m); - assert(v); + assert(v || verity_data); if (!root_hash) return 0; if (!m->found || !m->node || !m->fstype) return 0; - if (!v->found || !v->node || !v->fstype) - return 0; + if (!verity_data) { + if (!v->found || !v->node || !v->fstype) + return 0; - if (!streq(v->fstype, "DM_verity_hash")) - return 0; + if (!streq(v->fstype, "DM_verity_hash")) + return 0; + } r = make_dm_name_and_node(m->node, "-verity", &name, &node); if (r < 0) @@ -1243,7 +1253,7 @@ static int verity_partition( if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1)) return -ENOMEM; - r = crypt_init(&cd, v->node); + r = crypt_init(&cd, verity_data ?: v->node); if (r < 0) return r; @@ -1276,6 +1286,7 @@ int dissected_image_decrypt( const char *passphrase, const void *root_hash, size_t root_hash_size, + const char *verity_data, DissectImageFlags flags, DecryptedImage **ret) { @@ -1322,7 +1333,7 @@ int dissected_image_decrypt( k = PARTITION_VERITY_OF(i); if (k >= 0) { - r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d); + r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, flags, d); if (r < 0) return r; } @@ -1347,6 +1358,7 @@ int dissected_image_decrypt_interactively( const char *passphrase, const void *root_hash, size_t root_hash_size, + const char *verity_data, DissectImageFlags flags, DecryptedImage **ret) { @@ -1357,7 +1369,7 @@ int dissected_image_decrypt_interactively( n--; for (;;) { - r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret); + r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, flags, ret); if (r >= 0) return r; if (r == -EKEYREJECTED) @@ -1409,56 +1421,85 @@ int decrypted_image_relinquish(DecryptedImage *d) { return 0; } -int root_hash_load(const char *image, void **ret, size_t *ret_size) { - _cleanup_free_ char *text = NULL; - _cleanup_free_ void *k = NULL; - size_t l; +int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) { + _cleanup_free_ char *verity_filename = NULL; + _cleanup_free_ void *roothash_decoded = NULL; + size_t roothash_decoded_size = 0; int r; assert(image); - assert(ret); - assert(ret_size); if (is_device_path(image)) { /* If we are asked to load the root hash for a device node, exit early */ - *ret = NULL; - *ret_size = 0; + if (ret_roothash) + *ret_roothash = NULL; + if (ret_roothash_size) + *ret_roothash_size = 0; + if (ret_verity_data) + *ret_verity_data = NULL; return 0; } - r = getxattr_malloc(image, "user.verity.roothash", &text, true); - if (r < 0) { - char *fn, *e, *n; - - if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)) - return r; + if (ret_verity_data) { + char *e; - fn = newa(char, strlen(image) + STRLEN(".roothash") + 1); - n = stpcpy(fn, image); - e = endswith(fn, ".raw"); + verity_filename = new(char, strlen(image) + STRLEN(".verity") + 1); + if (!verity_filename) + return -ENOMEM; + strcpy(verity_filename, image); + e = endswith(verity_filename, ".raw"); if (e) - n = e; - - strcpy(n, ".roothash"); + strcpy(e, ".verity"); + else + strcat(verity_filename, ".verity"); - r = read_one_line_file(fn, &text); - if (r == -ENOENT) { - *ret = NULL; - *ret_size = 0; - return 0; + r = access(verity_filename, F_OK); + if (r < 0) { + if (errno != ENOENT) + return -errno; + verity_filename = mfree(verity_filename); } - if (r < 0) - return r; } - r = unhexmem(text, strlen(text), &k, &l); - if (r < 0) - return r; - if (l < sizeof(sd_id128_t)) - return -EINVAL; + if (ret_roothash) { + _cleanup_free_ char *text = NULL; + assert(ret_roothash_size); + + r = getxattr_malloc(image, "user.verity.roothash", &text, true); + if (r < 0) { + char *fn, *e, *n; + + if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT)) + return r; + + fn = newa(char, strlen(image) + STRLEN(".roothash") + 1); + n = stpcpy(fn, image); + e = endswith(fn, ".raw"); + if (e) + n = e; - *ret = TAKE_PTR(k); - *ret_size = l; + strcpy(n, ".roothash"); + + r = read_one_line_file(fn, &text); + if (r < 0 && r != -ENOENT) + return r; + } + + if (text) { + r = unhexmem(text, strlen(text), &roothash_decoded, &roothash_decoded_size); + if (r < 0) + return r; + if (roothash_decoded_size < sizeof(sd_id128_t)) + return -EINVAL; + } + } + + if (ret_roothash) { + *ret_roothash = TAKE_PTR(roothash_decoded); + *ret_roothash_size = roothash_decoded_size; + } + if (ret_verity_data) + *ret_verity_data = TAKE_PTR(verity_filename); return 1; } @@ -1617,6 +1658,7 @@ int dissect_image_and_warn( const char *name, const void *root_hash, size_t root_hash_size, + const char *verity_data, DissectImageFlags flags, DissectedImage **ret) { @@ -1631,7 +1673,7 @@ int dissect_image_and_warn( name = buffer; } - r = dissect_image(fd, root_hash, root_hash_size, flags, ret); + r = dissect_image(fd, root_hash, root_hash_size, verity_data, flags, ret); switch (r) { @@ -1661,6 +1703,23 @@ int dissect_image_and_warn( } } +bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator) { + if (image->single_file_system) + return partition_designator == PARTITION_ROOT && image->can_verity; + + return PARTITION_VERITY_OF(partition_designator) >= 0; +} + +bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator) { + int k; + + if (image->single_file_system) + return partition_designator == PARTITION_ROOT && image->verity; + + k = PARTITION_VERITY_OF(partition_designator); + return k >= 0 && image->partitions[k].found; +} + static const char *const partition_designator_table[] = { [PARTITION_ROOT] = "root", [PARTITION_ROOT_SECONDARY] = "root-secondary", |