From 6eccec00fb50e1a35f5a11e3339d634541bcc3a8 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 16 Mar 2023 22:10:50 +0100 Subject: [PATCH 1/3] repart: Make sure we seek to beginning of partition target before copy --- src/partition/repart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/partition/repart.c b/src/partition/repart.c index 2b1fbbdae2..e631464998 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3266,6 +3266,9 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) return log_error_errno(errno, "Failed to seek to partition offset: %m"); + if (lseek(t->fd, 0, SEEK_SET) == (off_t) -1) + return log_error_errno(errno, "Failed to seek to start of temporary file: %m"); + r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC); if (r < 0) return log_error_errno(r, "Failed to copy bytes to partition: %m"); From d28c6ce62c4915ec5f7e10dc49be5e51c2356dad Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 16 Mar 2023 22:11:31 +0100 Subject: [PATCH 2/3] repart: Zero full verity signature partition size systemd-dissect requires the entirety of the partition following the signature to be zeroed, so let's do just that. --- src/partition/repart.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index e631464998..c53bf98fb2 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3656,7 +3656,7 @@ static int partition_format_verity_sig(Context *context, Partition *p) { _cleanup_free_ char *text = NULL; Partition *hp; uint8_t fp[X509_FINGERPRINT_SIZE]; - size_t sigsz = 0, padsz; /* avoid false maybe-uninitialized warning */ + size_t sigsz = 0; /* avoid false maybe-uninitialized warning */ int whole_fd, r; assert(p->verity == VERITY_SIG); @@ -3702,17 +3702,14 @@ static int partition_format_verity_sig(Context *context, Partition *p) { if (r < 0) return log_error_errno(r, "Failed to format JSON object: %m"); - padsz = round_up_size(strlen(text), 4096); - assert_se(padsz <= p->new_size); - - r = strgrowpad0(&text, padsz); + r = strgrowpad0(&text, p->new_size); if (r < 0) - return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(padsz)); + return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(p->new_size)); if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) return log_error_errno(errno, "Failed to seek to partition offset: %m"); - r = loop_write(whole_fd, text, padsz, /*do_poll=*/ false); + r = loop_write(whole_fd, text, p->new_size, /*do_poll=*/ false); if (r < 0) return log_error_errno(r, "Failed to write verity signature to partition: %m"); From e21be7976aba577e0ba66300e631c5ae7feb02d9 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 16 Mar 2023 23:15:19 +0100 Subject: [PATCH 3/3] repart: Report better errors if partition sizes are too small --- src/partition/repart.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index c53bf98fb2..44c8384e1c 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3263,12 +3263,22 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget if (r < 0) return log_error_errno(r, "Failed to sync loopback device: %m"); } else if (t->fd >= 0) { + struct stat st; + if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) return log_error_errno(errno, "Failed to seek to partition offset: %m"); if (lseek(t->fd, 0, SEEK_SET) == (off_t) -1) return log_error_errno(errno, "Failed to seek to start of temporary file: %m"); + if (fstat(t->fd, &st) < 0) + return log_error_errno(errno, "Failed to stat temporary file: %m"); + + if (st.st_size > (off_t) p->new_size) + return log_error_errno(SYNTHETIC_ERRNO(ENOSPC), + "Partition %" PRIu64 "'s contents (%s) don't fit in the partition (%s)", + p->partno, FORMAT_BYTES(st.st_size), FORMAT_BYTES(p->new_size)); + r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC); if (r < 0) return log_error_errno(r, "Failed to copy bytes to partition: %m"); @@ -3553,6 +3563,8 @@ static int partition_format_verity_hash( if (r < 0) return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); + cryptsetup_enable_logging(cd); + r = sym_crypt_format( cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &(struct crypt_params_verity){ @@ -3564,8 +3576,17 @@ static int partition_format_verity_hash( .hash_block_size = context->sector_size, .salt_size = 32, }); - if (r < 0) + if (r < 0) { + /* libcryptsetup reports non-descriptive EIO errors for every I/O failure. Luckily, it + * doesn't clobber errno so let's check for ENOSPC so we can report a better error if the + * partition is too small. */ + if (r == -EIO && errno == ENOSPC) + return log_error_errno(errno, + "Verity hash data does not fit in partition %"PRIu64" with size %s", + p->partno, FORMAT_BYTES(p->new_size)); + return log_error_errno(r, "Failed to setup verity hash data: %m"); + } r = partition_target_sync(context, p, t); if (r < 0)