From: Daan De Meyer Date: Sun, 9 Oct 2022 20:26:10 +0000 (+0200) Subject: repart: Move verity hash formatting into data partition functions X-Git-Tag: v253-rc1~520^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2b392d860e7fe1fcf9845d918ecacc9cbf464158;p=thirdparty%2Fsystemd.git repart: Move verity hash formatting into data partition functions Refactoring to make implementing rootless repart easier. --- diff --git a/src/partition/repart.c b/src/partition/repart.c index 1ecfc6b8fd6..6056655f474 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3210,6 +3210,102 @@ static int partition_encrypt(Context *context, Partition *p, const char *node) { #endif } +static int partition_format_verity_hash( + Context *context, + Partition *p, + const char *data_node) { + +#if HAVE_LIBCRYPTSETUP + Partition *dp; + _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; + _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; + _cleanup_free_ uint8_t *rh = NULL; + size_t rhs; + int whole_fd, r; + + assert(context); + assert(p); + assert(data_node); + + if (p->dropped) + return 0; + + if (PARTITION_EXISTS(p)) /* Never format existing partitions */ + return 0; + + if (p->verity != VERITY_HASH) + return 0; + + if (partition_skip(p)) + return 0; + + assert_se(dp = p->siblings[VERITY_DATA]); + assert(!dp->dropped); + + assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0); + + r = dlopen_cryptsetup(); + if (r < 0) + return log_error_errno(r, "libcryptsetup not found, cannot setup verity: %m"); + + r = loop_device_make(whole_fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &d); + if (r < 0) + return log_error_errno(r, + "Failed to make loopback device of verity hash partition %" PRIu64 ": %m", + p->partno); + + r = sym_crypt_init(&cd, d->node); + if (r < 0) + return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); + + r = sym_crypt_format( + cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, + &(struct crypt_params_verity){ + .data_device = data_node, + .flags = CRYPT_VERITY_CREATE_HASH, + .hash_name = "sha256", + .hash_type = 1, + .data_block_size = context->sector_size, + .hash_block_size = context->sector_size, + .salt_size = 32, + }); + if (r < 0) + return log_error_errno(r, "Failed to setup verity hash data: %m"); + + r = sym_crypt_get_volume_key_size(cd); + if (r < 0) + return log_error_errno(r, "Failed to determine verity root hash size: %m"); + rhs = (size_t) r; + + rh = malloc(rhs); + if (!rh) + return log_oom(); + + r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) rh, &rhs, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to get verity root hash: %m"); + + assert(rhs >= sizeof(sd_id128_t) * 2); + + if (!dp->new_uuid_is_set) { + memcpy_safe(dp->new_uuid.bytes, rh, sizeof(sd_id128_t)); + dp->new_uuid_is_set = true; + } + + if (!p->new_uuid_is_set) { + memcpy_safe(p->new_uuid.bytes, rh + rhs - sizeof(sd_id128_t), sizeof(sd_id128_t)); + p->new_uuid_is_set = true; + } + + p->roothash = TAKE_PTR(rh); + p->roothash_size = rhs; + + return 0; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libcryptsetup is not supported, cannot setup verity hashes: %m"); +#endif +} + static int context_copy_blocks(Context *context) { int whole_fd = -1, r; @@ -3270,6 +3366,12 @@ static int context_copy_blocks(Context *context) { return log_error_errno(errno, "Failed to synchronize copied data blocks: %m"); log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path); + + if (p->siblings[VERITY_HASH]) { + r = partition_format_verity_hash(context, p->siblings[VERITY_HASH], d->node); + if (r < 0) + return r; + } } return 0; @@ -3629,133 +3731,12 @@ static int context_mkfs(Context *context) { r = loop_device_sync(d); if (r < 0) return log_error_errno(r, "Failed to sync loopback device: %m"); - } - - return 0; -} - -static int do_verity_format( - LoopDevice *data_device, - LoopDevice *hash_device, - uint64_t sector_size, - uint8_t **ret_roothash, - size_t *ret_roothash_size) { - -#if HAVE_LIBCRYPTSETUP - _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; - _cleanup_free_ uint8_t *rh = NULL; - size_t rhs; - int r; - - assert(data_device); - assert(hash_device); - assert(sector_size > 0); - assert(ret_roothash); - assert(ret_roothash_size); - - r = dlopen_cryptsetup(); - if (r < 0) - return log_error_errno(r, "libcryptsetup not found, cannot setup verity: %m"); - - r = sym_crypt_init(&cd, hash_device->node); - if (r < 0) - return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); - - r = sym_crypt_format( - cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, - &(struct crypt_params_verity){ - .data_device = data_device->node, - .flags = CRYPT_VERITY_CREATE_HASH, - .hash_name = "sha256", - .hash_type = 1, - .data_block_size = sector_size, - .hash_block_size = sector_size, - .salt_size = 32, - }); - if (r < 0) - return log_error_errno(r, "Failed to setup verity hash data: %m"); - - r = sym_crypt_get_volume_key_size(cd); - if (r < 0) - return log_error_errno(r, "Failed to determine verity root hash size: %m"); - rhs = (size_t) r; - - rh = malloc(rhs); - if (!rh) - return log_oom(); - - r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) rh, &rhs, NULL, 0); - if (r < 0) - return log_error_errno(r, "Failed to get verity root hash: %m"); - - *ret_roothash = TAKE_PTR(rh); - *ret_roothash_size = rhs; - - return 0; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libcryptsetup is not supported, cannot setup verity hashes: %m"); -#endif -} - -static int context_verity_hash(Context *context) { - int fd = -1, r; - - assert(context); - - LIST_FOREACH(partitions, p, context->partitions) { - Partition *dp; - _cleanup_(loop_device_unrefp) LoopDevice *hash_device = NULL, *data_device = NULL; - _cleanup_free_ uint8_t *rh = NULL; - size_t rhs = 0; /* Initialize to work around for GCC false positive. */ - - if (p->dropped) - continue; - - if (PARTITION_EXISTS(p)) /* Never format existing partitions */ - continue; - - if (p->verity != VERITY_HASH) - continue; - - if (partition_skip(p)) - continue; - - assert_se(dp = p->siblings[VERITY_DATA]); - assert(!dp->dropped); - if (fd < 0) - assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0); - - r = loop_device_make(fd, O_RDONLY, dp->offset, dp->new_size, 0, 0, LOCK_EX, &data_device); - if (r < 0) - return log_error_errno(r, - "Failed to make loopback device of verity data partition %" PRIu64 ": %m", - p->partno); - - r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &hash_device); - if (r < 0) - return log_error_errno(r, - "Failed to make loopback device of verity hash partition %" PRIu64 ": %m", - p->partno); - - r = do_verity_format(data_device, hash_device, context->sector_size, &rh, &rhs); - if (r < 0) - return r; - - assert(rhs >= sizeof(sd_id128_t) * 2); - - if (!dp->new_uuid_is_set) { - memcpy_safe(dp->new_uuid.bytes, rh, sizeof(sd_id128_t)); - dp->new_uuid_is_set = true; - } - - if (!p->new_uuid_is_set) { - memcpy_safe(p->new_uuid.bytes, rh + rhs - sizeof(sd_id128_t), sizeof(sd_id128_t)); - p->new_uuid_is_set = true; + if (p->siblings[VERITY_HASH]) { + r = partition_format_verity_hash(context, p->siblings[VERITY_HASH], d->node); + if (r < 0) + return r; } - - p->roothash = TAKE_PTR(rh); - p->roothash_size = rhs; } return 0; @@ -4510,10 +4491,6 @@ static int context_write_partition_table( if (r < 0) return r; - r = context_verity_hash(context); - if (r < 0) - return r; - r = context_verity_sig(context); if (r < 0) return r;