From: Luca Boccassi Date: Wed, 22 Apr 2026 14:38:10 +0000 (+0100) Subject: repart: trim NUL bytes from verity sig split artifact X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b54ef83414234ac0a742895dd645632662b5aa77;p=thirdparty%2Fsystemd.git repart: trim NUL bytes from verity sig split artifact The verity signature partition content is a bare JSON object. Repart pads it with zeros to fill the GPT partition. But when splitting out the content as an individual file, the padding remains, so it's not a valid text file. jq started rejecting files with NUL bytes to fix a security issue: https://github.com/jqlang/jq/commit/6374ae0bcdfe33a18eb0ae6db28493b1f34a0a5b Trim the output when writing these files out. --- diff --git a/src/repart/repart.c b/src/repart/repart.c index 91cd77b448f..75fb79c48a9 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -7754,9 +7754,30 @@ static int context_split(Context *context) { if (lseek(fd, p->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to partition offset: %m"); - r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES|COPY_TRUNCATE); - if (r < 0) - return log_error_errno(r, "Failed to copy to split partition %s: %m", p->split_path); + /* Verity signature partitions contain a JSON object NUL-padded out to the partition + * size. The on-disk partition must keep the padding, but the split-out file is a + * standalone artifact, so trim the trailing NUL bytes there to avoid tripping jq. */ + if (partition_designator_is_verity_sig(p->type.designator)) { + _cleanup_free_ char *buf = malloc(p->new_size); + if (!buf) + return log_oom(); + + r = loop_read_exact(fd, buf, p->new_size, /* do_poll= */ false); + if (r < 0) + return log_error_errno(r, "Failed to read verity signature partition: %m"); + + size_t len = strnlen(buf, p->new_size); + if (len == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Verity signature partition is empty"); + + r = loop_write(fdt, buf, len); + if (r < 0) + return log_error_errno(r, "Failed to write to split partition %s: %m", p->split_path); + } else { + r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES|COPY_TRUNCATE); + if (r < 0) + return log_error_errno(r, "Failed to copy to split partition %s: %m", p->split_path); + } } return 0; diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index fb3dbcfad5d..7b536fa0920 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -941,6 +941,7 @@ EOF --dry-run=no \ --empty=create \ --size=auto \ + --split=yes \ --json=pretty \ --private-key="$defs/verity.key" \ --certificate="$defs/verity.crt" \ @@ -953,6 +954,13 @@ EOF assert_eq "$drh" "$hrh" assert_eq "$hrh" "$srh" + # The split-out verity signature file should be a valid JSON document (i.e. trailing NUL padding + # from the on-disk partition must be trimmed when writing the split file). + sig_split=$(jq -r ".[] | select(.type == \"root-${architecture}-verity-sig\") | .split_path" <<<"$output") + assert_neq "$sig_split" "" + assert_neq "$sig_split" "null" + jq . "$sig_split" >/dev/null + # Check that offline signing works and the resulting image is valid output=$(systemd-repart --offline="$OFFLINE" \