diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 5e6848acb4..e3c96b7407 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -23,6 +23,7 @@ #include "architecture.h" #include "dissect-image.h" +#include "hexdecoct.h" #include "log.h" #include "loop-util.h" #include "string-util.h" @@ -35,6 +36,8 @@ static enum { static const char *arg_image = NULL; static const char *arg_path = NULL; static DissectImageFlags arg_flags = DISSECT_IMAGE_DISCARD_ON_LOOP; +static void *arg_root_hash = NULL; +static size_t arg_root_hash_size = 0; static void help(void) { printf("%s [OPTIONS...] IMAGE\n" @@ -44,7 +47,8 @@ static void help(void) { " --version Show package version\n" " -m --mount Mount the image to the specified directory\n" " -r --read-only Mount read-only\n" - " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n", + " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n" + " --root-hash=HASH Specify root hash for verity\n", program_invocation_short_name, program_invocation_short_name); } @@ -54,6 +58,7 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_DISCARD, + ARG_ROOT_HASH, }; static const struct option options[] = { @@ -62,10 +67,11 @@ static int parse_argv(int argc, char *argv[]) { { "mount", no_argument, NULL, 'm' }, { "read-only", no_argument, NULL, 'r' }, { "discard", required_argument, NULL, ARG_DISCARD }, + { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -105,6 +111,25 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_ROOT_HASH: { + void *p; + size_t l; + + r = unhexmem(optarg, strlen(optarg), &p, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse root hash: %s", optarg); + if (l < sizeof(sd_id128_t)) { + log_error("Root hash must be at least 128bit long: %s", optarg); + free(p); + return -EINVAL; + } + + free(arg_root_hash); + arg_root_hash = p; + arg_root_hash_size = l; + break; + } + case '?': return -EINVAL; @@ -162,11 +187,15 @@ int main(int argc, char *argv[]) { goto finish; } - r = dissect_image(d->fd, &m); + r = dissect_image(d->fd, arg_root_hash, arg_root_hash_size, &m); if (r == -ENOPKG) { log_error_errno(r, "Couldn't identify a suitable partition table or file system in %s.", arg_image); goto finish; } + if (r == -EADDRNOTAVAIL) { + log_error_errno(r, "No root partition for specified root hash found in %s.", arg_image); + goto finish; + } if (r < 0) { log_error_errno(r, "Failed to dissect image: %m"); goto finish; @@ -179,6 +208,7 @@ int main(int argc, char *argv[]) { for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) { DissectedPartition *p = m->partitions + i; + int k; if (!p->found) continue; @@ -193,6 +223,10 @@ int main(int argc, char *argv[]) { if (p->architecture != _ARCHITECTURE_INVALID) printf(" for %s", architecture_to_string(p->architecture)); + k = PARTITION_VERITY_OF(i); + if (k >= 0) + printf(" %s verity", m->partitions[k].found ? "with" : "without"); + if (p->partno >= 0) printf(" on partition #%i", p->partno); @@ -206,7 +240,7 @@ int main(int argc, char *argv[]) { } case ACTION_MOUNT: - r = dissected_image_decrypt_interactively(m, NULL, arg_flags, &di); + r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_flags, &di); if (r < 0) goto finish; @@ -232,5 +266,6 @@ int main(int argc, char *argv[]) { } finish: + free(arg_root_hash); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 65953b368f..e2fb882393 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -336,7 +336,7 @@ static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *err if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to set up loop block device for %s: %m", image->path); - r = dissect_image(d->fd, &m); + r = dissect_image(d->fd, NULL, 0, &m); if (r == -ENOPKG) return sd_bus_error_set_errnof(error, r, "Disk image %s not understood: %m", image->path); if (r < 0) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9168228f4a..de05b6c5ef 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -61,6 +61,7 @@ #include "format-util.h" #include "fs-util.h" #include "gpt.h" +#include "hexdecoct.h" #include "hostname-util.h" #include "id128-util.h" #include "log.h" @@ -200,6 +201,8 @@ static bool arg_notify_ready = false; static bool arg_use_cgns = true; static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS; static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO; +static void *arg_root_hash = NULL; +static size_t arg_root_hash_size = 0; static void help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" @@ -213,6 +216,7 @@ static void help(void) { " -x --ephemeral Run container with snapshot of root directory, and\n" " remove it after exit\n" " -i --image=PATH File system device or disk image for the container\n" + " --root-hash=HASH Specify verity root hash\n" " -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n" " -b --boot Boot up full system (i.e. invoke init)\n" " --chdir=PATH Set working directory in the container\n" @@ -424,6 +428,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_CHDIR, ARG_PRIVATE_USERS_CHOWN, ARG_NOTIFY_READY, + ARG_ROOT_HASH, }; static const struct option options[] = { @@ -473,6 +478,7 @@ static int parse_argv(int argc, char *argv[]) { { "settings", required_argument, NULL, ARG_SETTINGS }, { "chdir", required_argument, NULL, ARG_CHDIR }, { "notify-ready", required_argument, NULL, ARG_NOTIFY_READY }, + { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, {} }; @@ -1016,6 +1022,25 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_NOTIFY_READY; break; + case ARG_ROOT_HASH: { + void *k; + size_t l; + + r = unhexmem(optarg, strlen(optarg), &k, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse root hash: %s", optarg); + if (l < sizeof(sd_id128_t)) { + log_error("Root hash must be at least 128bit long: %s", optarg); + free(k); + return -EINVAL; + } + + free(arg_root_hash); + arg_root_hash = k; + arg_root_hash_size = l; + break; + } + case '?': return -EINVAL; @@ -3409,6 +3434,53 @@ static int run(int master, return 1; /* loop again */ } +static int load_root_hash(const char *image) { + _cleanup_free_ char *text = NULL; + char *fn, *n, *e; + void *k; + size_t l; + int r; + + assert_se(image); + + /* Try to load the root hash from a file next to the image file if it exists. */ + + if (arg_root_hash) + return 0; + + fn = new(char, strlen(image) + strlen(".roothash") + 1); + if (!fn) + return log_oom(); + + n = stpcpy(fn, image); + e = endswith(fn, ".raw"); + if (e) + n = e; + + strcpy(n, ".roothash"); + + r = read_one_line_file(fn, &text); + if (r == -ENOENT) + return 0; + if (r < 0) { + log_warning_errno(r, "Failed to read %s, ignoring: %m", fn); + return 0; + } + + r = unhexmem(text, strlen(text), &k, &l); + if (r < 0) + return log_error_errno(r, "Invalid root hash: %s", text); + if (l < sizeof(sd_id128_t)) { + free(k); + return log_error_errno(r, "Root hash too short: %s", text); + } + + arg_root_hash = k; + arg_root_hash_size = l; + + return 0; +} + int main(int argc, char *argv[]) { _cleanup_free_ char *console = NULL; @@ -3623,6 +3695,10 @@ int main(int argc, char *argv[]) { r = log_error_errno(r, "Failed to create image lock: %m"); goto finish; } + + r = load_root_hash(arg_image); + if (r < 0) + goto finish; } if (!mkdtemp(tmprootdir)) { @@ -3644,7 +3720,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = dissect_image(loop->fd, &dissected_image); + r = dissect_image(loop->fd, arg_root_hash, arg_root_hash_size, &dissected_image); if (r == -ENOPKG) { log_error_errno(r, "Could not find a suitable file system or partition table in image: %s", arg_image); @@ -3656,6 +3732,10 @@ int main(int argc, char *argv[]) { "in order to be bootable with systemd-nspawn."); goto finish; } + if (r == -EADDRNOTAVAIL) { + log_error_errno(r, "No root partition for specified root hash found."); + goto finish; + } if (r == -EOPNOTSUPP) { log_error_errno(r, "--image= is not supported, compiled without blkid support."); goto finish; @@ -3665,7 +3745,10 @@ int main(int argc, char *argv[]) { goto finish; } - r = dissected_image_decrypt_interactively(dissected_image, NULL, 0, &decrypted_image); + if (!arg_root_hash && dissected_image->can_verity) + log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image); + + r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, 0, &decrypted_image); if (r < 0) goto finish; @@ -3792,6 +3875,7 @@ finish: strv_free(arg_parameters); custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts); expose_port_free_all(arg_expose_ports); + free(arg_root_hash); return r < 0 ? EXIT_FAILURE : ret; } diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index bc4e45be6e..257af78781 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -84,9 +84,10 @@ not_found: #endif } -int dissect_image(int fd, DissectedImage **ret) { +int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret) { #ifdef HAVE_BLKID + sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL; _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; bool is_gpt, is_mbr, generic_rw, multiple_generic = false; _cleanup_udev_device_unref_ struct udev_device *d = NULL; @@ -103,10 +104,29 @@ int dissect_image(int fd, DissectedImage **ret) { assert(fd >= 0); assert(ret); + assert(root_hash || root_hash_size == 0); /* Probes a disk image, and returns information about what it found in *ret. * - * Returns -ENOPKG if no suitable partition table or file system could be found. */ + * Returns -ENOPKG if no suitable partition table or file system could be found. + * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */ + + if (root_hash) { + /* If a root hash is supplied, then we use the root partition that has a UUID that match the first + * 128bit of the root hash. And we use the verity partition that has a UUID that match the final + * 128bit. */ + + if (root_hash_size < sizeof(sd_id128_t)) + return -EINVAL; + + memcpy(&root_uuid, root_hash, sizeof(sd_id128_t)); + memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); + + if (sd_id128_is_null(root_uuid)) + return -EINVAL; + if (sd_id128_is_null(verity_uuid)) + return -EINVAL; + } if (fstat(fd, &st) < 0) return -errno; @@ -313,17 +333,22 @@ int dissect_image(int fd, DissectedImage **ret) { if (is_gpt) { int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID; - const char *stype, *fstype = NULL; - sd_id128_t type_id; + const char *stype, *sid, *fstype = NULL; + sd_id128_t type_id, id; bool rw = true; if (flags & GPT_FLAG_NO_AUTO) continue; + sid = blkid_partition_get_uuid(pp); + if (!sid) + continue; + if (sd_id128_from_string(sid, &id) < 0) + continue; + stype = blkid_partition_get_type_string(pp); if (!stype) continue; - if (sd_id128_from_string(stype, &type_id) < 0) continue; @@ -339,17 +364,57 @@ int dissect_image(int fd, DissectedImage **ret) { } #ifdef GPT_ROOT_NATIVE else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) { + + /* If a root ID is specified, ignore everything but the root id */ + if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) + continue; + designator = PARTITION_ROOT; architecture = native_architecture(); rw = !(flags & GPT_FLAG_READ_ONLY); } +#ifdef GPT_ROOT_NATIVE_VERITY + else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { + + m->can_verity = true; + + /* Ignore verity unless a root hash is specified */ + if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) + continue; + + designator = PARTITION_ROOT_VERITY; + fstype = "DM_verity_hash"; + architecture = native_architecture(); + rw = false; + } +#endif #endif #ifdef GPT_ROOT_SECONDARY else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) { + + /* If a root ID is specified, ignore everything but the root id */ + if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) + continue; + designator = PARTITION_ROOT_SECONDARY; architecture = SECONDARY_ARCHITECTURE; rw = !(flags & GPT_FLAG_READ_ONLY); } +#ifdef GPT_ROOT_SECONDARY_VERITY + else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { + + m->can_verity = true; + + /* Ignore verity unless root has is specified */ + if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) + continue; + + designator = PARTITION_ROOT_SECONDARY_VERITY; + fstype = "DM_verity_hash"; + architecture = SECONDARY_ARCHITECTURE; + rw = false; + } +#endif #endif else if (sd_id128_equal(type_id, GPT_SWAP)) { designator = PARTITION_SWAP; @@ -420,10 +485,17 @@ int dissect_image(int fd, DissectedImage **ret) { /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not * either, then check if there's a single generic one, and use that. */ + if (m->partitions[PARTITION_ROOT_VERITY].found) + return -ENXIO; + if (m->partitions[PARTITION_ROOT_SECONDARY].found) { m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY]; zero(m->partitions[PARTITION_ROOT_SECONDARY]); - } else if (generic_node) { + + m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY]; + zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]); + + } else if (generic_node && !root_hash) { if (multiple_generic) return -ENOTUNIQ; @@ -441,6 +513,24 @@ int dissect_image(int fd, DissectedImage **ret) { return -ENXIO; } + assert(m->partitions[PARTITION_ROOT].found); + + if (root_hash) { + if (!m->partitions[PARTITION_ROOT_VERITY].found) + return -EADDRNOTAVAIL; + + /* If we found the primary root with the hash, then we definitely want to suppress any secondary root + * (which would be weird, after all the root hash should only be assigned to one pair of + * partitions... */ + m->partitions[PARTITION_ROOT_SECONDARY].found = false; + m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false; + + /* If we found a verity setup, then the root partition is necessarily read-only. */ + m->partitions[PARTITION_ROOT].rw = false; + + m->verity = true; + } + blkid_free_probe(b); b = NULL; @@ -637,6 +727,40 @@ DecryptedImage* decrypted_image_unref(DecryptedImage* d) { } #ifdef HAVE_LIBCRYPTSETUP + +static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) { + _cleanup_free_ char *name = NULL, *node = NULL; + const char *base; + + assert(original_node); + assert(suffix); + assert(ret_name); + assert(ret_node); + + base = strrchr(original_node, '/'); + if (!base) + return -EINVAL; + base++; + if (isempty(base)) + return -EINVAL; + + name = strjoin(base, suffix); + if (!name) + return -ENOMEM; + if (!filename_is_valid(name)) + return -EINVAL; + + node = strjoin(crypt_get_dir(), "/", name); + if (!node) + return -ENOMEM; + + *ret_name = name; + *ret_node = node; + + name = node = NULL; + return 0; +} + static int decrypt_partition( DissectedPartition *m, const char *passphrase, @@ -645,7 +769,6 @@ static int decrypt_partition( _cleanup_free_ char *node = NULL, *name = NULL; struct crypt_device *cd; - const char *suffix; int r; assert(m); @@ -657,22 +780,9 @@ static int decrypt_partition( if (!streq(m->fstype, "crypto_LUKS")) return 0; - suffix = strrchr(m->node, '/'); - if (!suffix) - return -EINVAL; - suffix++; - if (isempty(suffix)) - return -EINVAL; - - name = strjoin(suffix, "-decrypted"); - if (!name) - return -ENOMEM; - if (!filename_is_valid(name)) - return -EINVAL; - - node = strjoin(crypt_get_dir(), "/", name); - if (!node) - return -ENOMEM; + r = make_dm_name_and_node(m->node, "-decrypted", &name, &node); + if (r < 0) + return r; if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1)) return -ENOMEM; @@ -706,6 +816,71 @@ static int decrypt_partition( return 0; +fail: + crypt_free(cd); + return r; +} + +static int verity_partition( + DissectedPartition *m, + DissectedPartition *v, + const void *root_hash, + size_t root_hash_size, + DissectImageFlags flags, + DecryptedImage *d) { + + _cleanup_free_ char *node = NULL, *name = NULL; + struct crypt_device *cd; + int r; + + assert(m); + assert(v); + + if (!root_hash) + return 0; + + if (!m->found || !m->node || !m->fstype) + return 0; + if (!v->found || !v->node || !v->fstype) + 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) + return r; + + if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1)) + return -ENOMEM; + + r = crypt_init(&cd, v->node); + if (r < 0) + return r; + + r = crypt_load(cd, CRYPT_VERITY, NULL); + if (r < 0) + goto fail; + + r = crypt_set_data_device(cd, m->node); + if (r < 0) + goto fail; + + r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY); + if (r < 0) + goto fail; + + d->decrypted[d->n_decrypted].name = name; + name = NULL; + + d->decrypted[d->n_decrypted].device = cd; + d->n_decrypted++; + + m->decrypted_node = node; + node = NULL; + + return 0; + fail: crypt_free(cd); return r; @@ -715,6 +890,8 @@ fail: int dissected_image_decrypt( DissectedImage *m, const char *passphrase, + const void *root_hash, + size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret) { @@ -725,6 +902,7 @@ int dissected_image_decrypt( #endif assert(m); + assert(root_hash || root_hash_size == 0); /* Returns: * @@ -734,13 +912,16 @@ int dissected_image_decrypt( * -EKEYREJECTED → Passed key was not correct */ - if (!m->encrypted) { + if (root_hash && root_hash_size < sizeof(sd_id128_t)) + return -EINVAL; + + if (!m->encrypted && !m->verity) { *ret = NULL; return 0; } #ifdef HAVE_LIBCRYPTSETUP - if (!passphrase) + if (m->encrypted && !passphrase) return -ENOKEY; d = new0(DecryptedImage, 1); @@ -749,6 +930,7 @@ int dissected_image_decrypt( for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) { DissectedPartition *p = m->partitions + i; + int k; if (!p->found) continue; @@ -757,6 +939,13 @@ int dissected_image_decrypt( if (r < 0) return r; + k = PARTITION_VERITY_OF(i); + if (k >= 0) { + r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d); + if (r < 0) + return r; + } + if (!p->decrypted_fstype && p->decrypted_node) { r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype); if (r < 0) @@ -776,6 +965,8 @@ int dissected_image_decrypt( int dissected_image_decrypt_interactively( DissectedImage *m, const char *passphrase, + const void *root_hash, + size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret) { @@ -786,7 +977,7 @@ int dissected_image_decrypt_interactively( n--; for (;;) { - r = dissected_image_decrypt(m, passphrase, flags, ret); + r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret); if (r >= 0) return r; if (r == -EKEYREJECTED) @@ -880,6 +1071,8 @@ static const char *const partition_designator_table[] = { [PARTITION_SRV] = "srv", [PARTITION_ESP] = "esp", [PARTITION_SWAP] = "swap", + [PARTITION_ROOT_VERITY] = "root-verity", + [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity", }; DEFINE_STRING_TABLE_LOOKUP(partition_designator, int); diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 69484eb32c..902c8d4a37 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -45,10 +45,20 @@ enum { PARTITION_SRV, PARTITION_ESP, PARTITION_SWAP, + PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */ + PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */ _PARTITION_DESIGNATOR_MAX, _PARTITION_DESIGNATOR_INVALID = -1 }; +static inline int PARTITION_VERITY_OF(int p) { + if (p == PARTITION_ROOT) + return PARTITION_ROOT_VERITY; + if (p == PARTITION_ROOT_SECONDARY) + return PARTITION_ROOT_SECONDARY_VERITY; + return _PARTITION_DESIGNATOR_INVALID; +} + typedef enum DissectImageFlags { DISSECT_IMAGE_READ_ONLY = 1, DISSECT_IMAGE_DISCARD_ON_LOOP = 2, /* Turn on "discard" if on loop device and file system supports it */ @@ -57,17 +67,19 @@ typedef enum DissectImageFlags { } DissectImageFlags; struct DissectedImage { - bool encrypted; + bool encrypted:1; + bool verity:1; /* verity available and usable */ + bool can_verity:1; /* verity available, but not necessarily used */ DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX]; }; -int dissect_image(int fd, DissectedImage **ret); +int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m); DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); -int dissected_image_decrypt(DissectedImage *m, const char *passphrase, DissectImageFlags flags, DecryptedImage **ret); -int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, DissectImageFlags flags, DecryptedImage **ret); +int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret); +int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret); int dissected_image_mount(DissectedImage *m, const char *dest, DissectImageFlags flags); DecryptedImage* decrypted_image_unref(DecryptedImage *p); diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 55b41bbcd8..13d80d611c 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -32,28 +32,43 @@ #define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3) #define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae) #define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97) - #define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b) #define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f) #define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15) #define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8) +/* Verity partitions for the root partitions above (we only define them for the root partitions, because only they are + * are commonly read-only and hence suitable for verity). */ +#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76) +#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5) +#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6) +#define GPT_ROOT_ARM_64_VERITY SD_ID128_MAKE(df,33,00,ce,d6,9f,4c,92,97,8c,9b,fb,0f,38,d8,20) +#define GPT_ROOT_IA64_VERITY SD_ID128_MAKE(86,ed,10,d5,b6,07,45,bb,89,57,d3,50,f2,3d,05,71) + + #if defined(__x86_64__) # define GPT_ROOT_NATIVE GPT_ROOT_X86_64 # define GPT_ROOT_SECONDARY GPT_ROOT_X86 +# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_64_VERITY +# define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_X86_VERITY #elif defined(__i386__) # define GPT_ROOT_NATIVE GPT_ROOT_X86 +# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_X86_VERITY #endif #if defined(__ia64__) # define GPT_ROOT_NATIVE GPT_ROOT_IA64 +# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_IA64_VERITY #endif #if defined(__aarch64__) && (__BYTE_ORDER != __BIG_ENDIAN) # define GPT_ROOT_NATIVE GPT_ROOT_ARM_64 # define GPT_ROOT_SECONDARY GPT_ROOT_ARM +# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_64_VERITY +# define GPT_ROOT_SECONDARY_VERITY GPT_ROOT_ARM_VERITY #elif defined(__arm__) && (__BYTE_ORDER != __BIG_ENDIAN) # define GPT_ROOT_NATIVE GPT_ROOT_ARM +# define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY #endif /* Flags we recognize on the root, swap, home and srv partitions when diff --git a/src/test/test-dissect-image.c b/src/test/test-dissect-image.c index 0363ef8eb6..0512a15e88 100644 --- a/src/test/test-dissect-image.c +++ b/src/test/test-dissect-image.c @@ -43,7 +43,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = dissect_image(d->fd, &m); + r = dissect_image(d->fd, NULL, 0, &m); if (r < 0) { log_error_errno(r, "Failed to dissect image: %m"); return EXIT_FAILURE;