summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dissect/dissect.c43
-rw-r--r--src/machine/image-dbus.c2
-rw-r--r--src/nspawn/nspawn.c88
-rw-r--r--src/shared/dissect-image.c245
-rw-r--r--src/shared/dissect-image.h20
-rw-r--r--src/shared/gpt.h17
-rw-r--r--src/test/test-dissect-image.c2
7 files changed, 378 insertions, 39 deletions
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;
@@ -710,11 +820,78 @@ 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;
+}
#endif
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;