pull-job: port .payload field to struct iovec

struct iovec is really how we should encode any form of arbitrary blob
data
This commit is contained in:
Lennart Poettering
2025-11-07 13:52:38 +01:00
parent 33f49312f8
commit 729e1f24c5
3 changed files with 42 additions and 51 deletions

View File

@@ -380,8 +380,8 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
if (!line)
return log_oom();
p = memmem_safe(checksum_job->payload,
checksum_job->payload_size,
p = memmem_safe(checksum_job->payload.iov_base,
checksum_job->payload.iov_len,
line,
strlen(line));
if (p)
@@ -389,7 +389,7 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
}
/* Only counts if found at beginning of a line */
if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n'))
if (!p || (p != (char*) checksum_job->payload.iov_base && p[-1] != '\n'))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"DOWNLOAD INVALID: Checksum of %s file did not check out, file has been tampered with.", fn);
@@ -398,8 +398,8 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
}
static int verify_gpg(
const void *payload, size_t payload_size,
const void *signature, size_t signature_size) {
const struct iovec *payload,
const struct iovec *signature) {
_cleanup_close_pair_ int gpg_pipe[2] = EBADF_PAIR;
_cleanup_(rm_rf_physical_and_freep) char *gpg_home = NULL;
@@ -407,21 +407,21 @@ static int verify_gpg(
_cleanup_(sigkill_waitp) pid_t pid = 0;
int r;
assert(payload || payload_size == 0);
assert(signature || signature_size == 0);
assert(iovec_is_valid(payload));
assert(iovec_is_valid(signature));
r = pipe2(gpg_pipe, O_CLOEXEC);
if (r < 0)
return log_error_errno(errno, "Failed to create pipe for gpg: %m");
if (signature_size > 0) {
if (iovec_is_set(signature)) {
_cleanup_close_ int sig_file = -EBADF;
sig_file = mkostemp(sig_file_path, O_RDWR);
if (sig_file < 0)
return log_error_errno(errno, "Failed to create temporary file: %m");
r = loop_write(sig_file, signature, signature_size);
r = loop_write(sig_file, signature->iov_base, signature->iov_len);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
@@ -487,10 +487,12 @@ static int verify_gpg(
gpg_pipe[0] = safe_close(gpg_pipe[0]);
r = loop_write(gpg_pipe[1], payload, payload_size);
if (r < 0) {
log_error_errno(r, "Failed to write to pipe: %m");
goto finish;
if (iovec_is_set(payload)) {
r = loop_write(gpg_pipe[1], payload->iov_base, payload->iov_len);
if (r < 0) {
log_error_errno(r, "Failed to write to pipe: %m");
goto finish;
}
}
gpg_pipe[1] = safe_close(gpg_pipe[1]);
@@ -507,7 +509,7 @@ static int verify_gpg(
}
finish:
if (signature_size > 0)
if (iovec_is_set(signature))
(void) unlink(sig_file_path);
return r;
@@ -553,7 +555,7 @@ int pull_verify(ImportVerify verify,
assert(checksum_job);
assert(checksum_job->state == PULL_JOB_DONE);
if (!checksum_job->payload || checksum_job->payload_size <= 0)
if (!iovec_is_set(&checksum_job->payload))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
@@ -579,11 +581,11 @@ int pull_verify(ImportVerify verify,
assert(signature_job);
assert(signature_job->state == PULL_JOB_DONE);
if (!signature_job->payload || signature_job->payload_size <= 0)
if (!iovec_is_set(&signature_job->payload))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
return verify_gpg(verify_job->payload, verify_job->payload_size, signature_job->payload, signature_job->payload_size);
return verify_gpg(&verify_job->payload, &signature_job->payload);
}
int verification_style_from_url(const char *url, VerificationStyle *ret) {

View File

@@ -57,7 +57,7 @@ PullJob* pull_job_unref(PullJob *j) {
free(j->url);
free(j->etag);
strv_free(j->old_etags);
free(j->payload);
iovec_done(&j->payload);
iovec_done(&j->checksum);
iovec_done(&j->expected_checksum);
@@ -95,8 +95,7 @@ static int pull_job_restart(PullJob *j, const char *new_url) {
j->state = PULL_JOB_INIT;
j->error = 0;
j->payload = mfree(j->payload);
j->payload_size = 0;
iovec_done(&j->payload);
j->written_compressed = 0;
j->written_uncompressed = 0;
j->content_length = UINT64_MAX;
@@ -381,11 +380,14 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata)
}
if (j->disk_fd < 0 || j->force_memory) {
if (!GREEDY_REALLOC(j->payload, j->payload_size + sz + 1))
uint8_t *a = j->payload.iov_base;
if (!GREEDY_REALLOC(a, j->payload.iov_len + sz + 1))
return log_oom();
*((char*) mempcpy(j->payload + j->payload_size, p, sz)) = 0;
j->payload_size += sz;
*((uint8_t*) mempcpy(a + j->payload.iov_len, p, sz)) = 0;
j->payload.iov_base = a;
j->payload.iov_len += sz;
}
j->written_uncompressed += sz;
@@ -397,39 +399,39 @@ finish:
return 0;
}
static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
static int pull_job_write_compressed(PullJob *j, const struct iovec *data) {
int r;
assert(j);
assert(p);
assert(iovec_is_valid(data));
if (sz <= 0)
if (!iovec_is_set(data))
return 0;
if (j->written_compressed + sz < j->written_compressed)
if (j->written_compressed + data->iov_len < j->written_compressed)
return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "File too large, overflow");
if (j->written_compressed + sz > j->compressed_max)
if (j->written_compressed + data->iov_len > j->compressed_max)
return log_error_errno(SYNTHETIC_ERRNO(EFBIG), "File overly large, refusing.");
uint64_t cl = pull_job_content_length_effective(j);
if (cl != UINT64_MAX &&
j->written_compressed + sz > cl)
j->written_compressed + data->iov_len > cl)
return log_error_errno(SYNTHETIC_ERRNO(EFBIG),
"Content length incorrect.");
if (j->checksum_ctx) {
r = EVP_DigestUpdate(j->checksum_ctx, p, sz);
r = EVP_DigestUpdate(j->checksum_ctx, data->iov_base, data->iov_len);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Could not hash chunk.");
}
r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
r = import_uncompress(&j->compress, data->iov_base, data->iov_len, pull_job_write_uncompressed, j);
if (r < 0)
return r;
j->written_compressed += sz;
j->written_compressed += data->iov_len;
return 0;
}
@@ -470,14 +472,11 @@ static int pull_job_open_disk(PullJob *j) {
}
static int pull_job_detect_compression(PullJob *j) {
_cleanup_free_ uint8_t *stub = NULL;
size_t stub_size;
int r;
assert(j);
r = import_uncompress_detect(&j->compress, j->payload, j->payload_size);
r = import_uncompress_detect(&j->compress, j->payload.iov_base, j->payload.iov_len);
if (r < 0)
return log_error_errno(r, "Failed to initialize compressor: %m");
if (r == 0)
@@ -490,15 +489,11 @@ static int pull_job_detect_compression(PullJob *j) {
return r;
/* Now, take the payload we read so far, and decompress it */
stub = j->payload;
stub_size = j->payload_size;
j->payload = NULL;
j->payload_size = 0;
_cleanup_(iovec_done) struct iovec stub = TAKE_STRUCT(j->payload);
j->state = PULL_JOB_RUNNING;
r = pull_job_write_compressed(j, stub, stub_size);
r = pull_job_write_compressed(j, &stub);
if (r < 0)
return r;
@@ -516,15 +511,11 @@ static size_t pull_job_write_callback(void *contents, size_t size, size_t nmemb,
case PULL_JOB_ANALYZING:
/* Let's first check what it actually is */
if (!GREEDY_REALLOC(j->payload, j->payload_size + sz)) {
if (!iovec_append(&j->payload, &IOVEC_MAKE(contents, sz))) {
r = log_oom();
goto fail;
}
memcpy(j->payload + j->payload_size, contents, sz);
j->payload_size += sz;
r = pull_job_detect_compression(j);
if (r < 0)
goto fail;
@@ -532,8 +523,7 @@ static size_t pull_job_write_callback(void *contents, size_t size, size_t nmemb,
break;
case PULL_JOB_RUNNING:
r = pull_job_write_compressed(j, contents, sz);
r = pull_job_write_compressed(j, &IOVEC_MAKE(contents, sz));
if (r < 0)
goto fail;

View File

@@ -60,8 +60,7 @@ typedef struct PullJob {
uint64_t expected_content_length;
uint8_t *payload;
size_t payload_size;
struct iovec payload;
int disk_fd;
bool close_disk_fd;