import: various smaller tweaks and fixes, preparation for OCI download support in importd (#39620)

This commit is contained in:
Lennart Poettering
2025-11-08 18:31:11 +01:00
committed by GitHub
9 changed files with 159 additions and 162 deletions

View File

@@ -6,6 +6,7 @@
#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "log.h"
#include "memory-util.h"
@@ -247,7 +248,6 @@ int pull_make_verification_jobs(
PullJob **ret_checksum_job,
PullJob **ret_signature_job,
ImportVerify verify,
const char *checksum, /* set if literal checksum verification is requested, in which case 'verify' is set to _IMPORT_VERIFY_INVALID */
const char *url,
CurlGlue *glue,
PullJobFinished on_finished,
@@ -261,13 +261,13 @@ int pull_make_verification_jobs(
assert(ret_signature_job);
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
assert(url);
assert(glue);
/* If verification is turned off, or if the checksum to validate is already specified we don't need
* to download a checksum file or signature, hence shortcut things */
if (verify == IMPORT_VERIFY_NO || checksum) {
if (verify < 0 || /* verification already done (via literal checksum) */
verify == IMPORT_VERIFY_NO) { /* verification turned off */
*ret_checksum_job = *ret_signature_job = NULL;
return 0;
}
@@ -351,7 +351,7 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
return 0;
assert(job->calc_checksum);
assert(job->checksum);
assert(iovec_is_set(&job->checksum));
r = import_url_last_component(job->url, &fn);
if (r < 0)
@@ -365,6 +365,10 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
return log_error_errno(SYNTHETIC_ERRNO(ELOOP),
"Cannot verify checksum/signature files via themselves.");
_cleanup_free_ char *cs = hexmem(job->checksum.iov_base, job->checksum.iov_len);
if (!cs)
return log_oom();
const char *p = NULL;
FOREACH_STRING(separator,
" *", /* separator for binary mode */
@@ -372,12 +376,12 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
" " /* non-standard separator used by linuxcontainers.org */) {
_cleanup_free_ char *line = NULL;
line = strjoin(job->checksum, separator, fn, "\n");
line = strjoin(cs, separator, fn, "\n");
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)
@@ -385,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);
@@ -394,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;
@@ -403,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;
@@ -483,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]);
@@ -503,14 +509,13 @@ static int verify_gpg(
}
finish:
if (signature_size > 0)
if (iovec_is_set(signature))
(void) unlink(sig_file_path);
return r;
}
int pull_verify(ImportVerify verify,
const char *checksum, /* Verify with literal checksum */
PullJob *main_job,
PullJob *checksum_job,
PullJob *signature_job,
@@ -526,33 +531,13 @@ int pull_verify(ImportVerify verify,
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
assert(main_job);
assert(main_job->state == PULL_JOB_DONE);
if (verify == IMPORT_VERIFY_NO) /* verification turned off */
if (verify < 0 || /* verification already done (via literal checksum) */
verify == IMPORT_VERIFY_NO) /* verification turned off */
return 0;
if (checksum) {
/* Verification by literal checksum */
assert(!checksum_job);
assert(!signature_job);
assert(!settings_job);
assert(!roothash_job);
assert(!roothash_signature_job);
assert(!verity_job);
assert(main_job->calc_checksum);
assert(main_job->checksum);
if (!strcaseeq(checksum, main_job->checksum))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"DOWNLOAD INVALID: Checksum of %s file did not check out, file has been tampered with.",
main_job->url);
return 0;
}
r = import_url_last_component(main_job->url, &fn);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from URL '%s': %m", main_job->url);
@@ -566,11 +551,11 @@ int pull_verify(ImportVerify verify,
verify_job = main_job;
} else {
assert(main_job->calc_checksum);
assert(main_job->checksum);
assert(iovec_is_set(&main_job->checksum));
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.");
@@ -596,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

@@ -14,9 +14,9 @@ int pull_find_old_etags(const char *url, const char *root, int dt, const char *p
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
int pull_make_auxiliary_job(PullJob **ret, const char *url, int (*strip_suffixes)(const char *name, char **ret), const char *suffix, ImportVerify verify, CurlGlue *glue, PullJobOpenDisk on_open_disk, PullJobFinished on_finished, void *userdata);
int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *checksum, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
int pull_verify(ImportVerify verify, const char *checksum, PullJob *main_job, PullJob *checksum_job, PullJob *signature_job, PullJob *settings_job, PullJob *roothash_job, PullJob *roothash_signature_job, PullJob *verity_job);
int pull_verify(ImportVerify verify, PullJob *main_job, PullJob *checksum_job, PullJob *signature_job, PullJob *settings_job, PullJob *roothash_job, PullJob *roothash_signature_job, PullJob *verity_job);
typedef enum VerificationStyle {
VERIFICATION_PER_FILE, /* SUSE-style ".sha256" files with detached gpg signature */

View File

@@ -20,6 +20,16 @@
#include "time-util.h"
#include "xattr-util.h"
static int http_status_ok(CURLcode status) {
/* Consider all HTTP status code in the 2xx range as OK */
return status >= 200 && status <= 299;
}
static int http_status_etag_exists(CURLcode status) {
/* This one is special, it's triggered by our etag mgmt logic */
return status == 304;
}
void pull_job_close_disk_fd(PullJob *j) {
if (!j)
return;
@@ -47,8 +57,9 @@ PullJob* pull_job_unref(PullJob *j) {
free(j->url);
free(j->etag);
strv_free(j->old_etags);
free(j->payload);
free(j->checksum);
iovec_done(&j->payload);
iovec_done(&j->checksum);
iovec_done(&j->expected_checksum);
return mfree(j);
}
@@ -84,15 +95,16 @@ 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;
j->etag = mfree(j->etag);
j->etag_exists = false;
j->mtime = 0;
j->checksum = mfree(j->checksum);
iovec_done(&j->checksum);
iovec_done(&j->expected_checksum);
j->expected_content_length = UINT64_MAX;
curl_glue_remove_and_free(j->glue, j->curl);
j->curl = NULL;
@@ -114,6 +126,15 @@ static int pull_job_restart(PullJob *j, const char *new_url) {
return 0;
}
static uint64_t pull_job_content_length_effective(PullJob *j) {
assert(j);
if (j->expected_content_length != UINT64_MAX)
return j->expected_content_length;
return j->content_length;
}
void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
PullJob *j = NULL;
char *scheme = NULL;
@@ -166,7 +187,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
if (status == 304) {
if (http_status_etag_exists(status)) {
log_info("Image already downloaded. Skipping download.");
j->etag_exists = true;
r = 0;
@@ -214,30 +235,46 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
if (j->content_length != UINT64_MAX &&
j->content_length != j->written_compressed) {
uint64_t cl = pull_job_content_length_effective(j);
if (cl != UINT64_MAX &&
cl != j->written_compressed) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Download truncated.");
goto finish;
}
if (j->checksum_ctx) {
unsigned checksum_len;
uint8_t k[EVP_MAX_MD_SIZE];
r = EVP_DigestFinal_ex(j->checksum_ctx, k, &checksum_len);
if (r == 0) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
goto finish;
}
assert(checksum_len <= sizeof k);
j->checksum = hexmem(k, checksum_len);
if (!j->checksum) {
iovec_done(&j->checksum);
j->checksum.iov_base = malloc(EVP_MAX_MD_SIZE);
if (!j->checksum.iov_base) {
r = log_oom();
goto finish;
}
log_debug("SHA256 of %s is %s.", j->url, j->checksum);
r = EVP_DigestFinal_ex(j->checksum_ctx, j->checksum.iov_base, &checksum_len);
if (r == 0) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
goto finish;
}
assert(checksum_len <= EVP_MAX_MD_SIZE);
j->checksum.iov_len = checksum_len;
if (DEBUG_LOGGING) {
_cleanup_free_ char *h = hexmem(j->checksum.iov_base, j->checksum.iov_len);
if (!h) {
r = log_oom();
goto finish;
}
log_debug("%s of %s is %s.", EVP_MD_CTX_get0_name(j->checksum_ctx), j->url, h);
}
if (iovec_is_set(&j->expected_checksum) &&
iovec_memcmp(&j->checksum, &j->expected_checksum) != 0) {
r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Checksum of downloaded resource does not match expected checksum, yikes.");
goto finish;
}
}
/* Do a couple of finishing disk operations, but only if we are the sole owner of the file (i.e. no
@@ -343,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))
uint8_t *a = j->payload.iov_base;
if (!GREEDY_REALLOC(a, j->payload.iov_len + sz + 1))
return log_oom();
memcpy(j->payload + j->payload_size, p, sz);
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;
@@ -359,38 +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.");
if (j->content_length != UINT64_MAX &&
j->written_compressed + sz > j->content_length)
uint64_t cl = pull_job_content_length_effective(j);
if (cl != UINT64_MAX &&
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;
}
@@ -431,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)
@@ -451,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;
@@ -477,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;
@@ -493,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;
@@ -516,16 +545,6 @@ fail:
return 0;
}
static int http_status_ok(CURLcode status) {
/* Consider all HTTP status code in the 2xx range as OK */
return status >= 200 && status <= 299;
}
static int http_status_etag_exists(CURLcode status) {
/* This one is special, it's triggered by our etag mgmt logic */
return status == 304;
}
static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
_cleanup_free_ char *length = NULL, *last_modified = NULL, *etag = NULL;
size_t sz = size * nmemb;
@@ -589,6 +608,12 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb
goto fail;
}
if (j->expected_content_length != UINT64_MAX &&
j->expected_content_length != j->content_length) {
r = log_error_errno(SYNTHETIC_ERRNO(EPROTO), "Content does not have expected size.");
goto fail;
}
log_info("Downloading %s for %s.", FORMAT_BYTES(j->content_length), j->url);
}
@@ -691,6 +716,7 @@ int pull_job_new(
.url = TAKE_PTR(u),
.offset = UINT64_MAX,
.sync = true,
.expected_content_length = UINT64_MAX,
};
*ret = TAKE_PTR(j);

View File

@@ -58,8 +58,9 @@ typedef struct PullJob {
uint64_t uncompressed_max;
uint64_t compressed_max;
uint8_t *payload;
size_t payload_size;
uint64_t expected_content_length;
struct iovec payload;
int disk_fd;
bool close_disk_fd;
@@ -76,7 +77,9 @@ typedef struct PullJob {
bool calc_checksum;
EVP_MD_CTX *checksum_ctx;
char *checksum;
struct iovec checksum;
struct iovec expected_checksum;
bool sync;
bool force_memory;
} PullJob;

View File

@@ -67,8 +67,6 @@ typedef struct RawPull {
char *verity_path;
char *verity_temp_path;
char *checksum;
} RawPull;
RawPull* raw_pull_unref(RawPull *i) {
@@ -99,7 +97,6 @@ RawPull* raw_pull_unref(RawPull *i) {
free(i->verity_path);
free(i->image_root);
free(i->local);
free(i->checksum);
return mfree(i);
}
@@ -503,13 +500,10 @@ static int raw_pull_rename_auxiliary_file(
}
static void raw_pull_job_on_finished(PullJob *j) {
RawPull *i;
int r;
assert(j);
assert(j->userdata);
i = j->userdata;
RawPull *i = ASSERT_PTR(j->userdata);
if (j->error != 0) {
/* Only the main job and the checksum job are fatal if they fail. The other fails are just
@@ -585,7 +579,6 @@ static void raw_pull_job_on_finished(PullJob *j) {
raw_pull_report_progress(i, RAW_VERIFYING);
r = pull_verify(i->verify,
i->checksum,
i->raw_job,
i->checksum_job,
i->signature_job,
@@ -827,7 +820,7 @@ int raw_pull_start(
uint64_t size_max,
ImportFlags flags,
ImportVerify verify,
const char *checksum) {
const struct iovec *checksum) {
int r;
@@ -835,11 +828,11 @@ int raw_pull_start(
assert(url);
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
assert((verify < 0) || !iovec_is_set(checksum));
assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_RAW));
assert(offset == UINT64_MAX || FLAGS_SET(flags, IMPORT_DIRECT));
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !(flags & IMPORT_DIRECT));
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !checksum);
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !iovec_is_set(checksum));
if (!http_url_is_valid(url) && !file_url_is_valid(url))
return -EINVAL;
@@ -854,10 +847,6 @@ int raw_pull_start(
if (r < 0)
return r;
r = free_and_strdup(&i->checksum, checksum);
if (r < 0)
return r;
i->flags = flags;
i->verify = verify;
@@ -869,9 +858,12 @@ int raw_pull_start(
i->raw_job->on_finished = raw_pull_job_on_finished;
i->raw_job->on_open_disk = raw_pull_job_on_open_disk_raw;
if (checksum)
if (iovec_is_set(checksum)) {
if (!iovec_memdup(checksum, &i->raw_job->expected_checksum))
return -ENOMEM;
i->raw_job->calc_checksum = true;
else if (verify != IMPORT_VERIFY_NO) {
} else if (verify != IMPORT_VERIFY_NO) {
/* Calculate checksum of the main download unless the users asks for a SHA256SUM file or its
* signature, which we let gpg verify instead. */
@@ -880,8 +872,8 @@ int raw_pull_start(
return r;
i->raw_job->calc_checksum = r;
i->raw_job->force_memory = true; /* make sure this is both written to disk if that's
* requested and into memory, since we need to verify it */
i->raw_job->force_memory = !r; /* make sure this is both written to disk if that's
* requested and into memory, since we need to verify it */
}
if (size_max != UINT64_MAX)
@@ -899,7 +891,6 @@ int raw_pull_start(
&i->checksum_job,
&i->signature_job,
verify,
i->checksum,
url,
i->glue,
raw_pull_job_on_finished,

View File

@@ -14,4 +14,4 @@ RawPull* raw_pull_unref(RawPull *pull);
DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref);
int raw_pull_start(RawPull *pull, const char *url, const char *local, uint64_t offset, uint64_t size_max, ImportFlags flags, ImportVerify verify, const char *checksum);
int raw_pull_start(RawPull *pull, const char *url, const char *local, uint64_t offset, uint64_t size_max, ImportFlags flags, ImportVerify verify, const struct iovec *checksum);

View File

@@ -65,8 +65,6 @@ typedef struct TarPull {
char *settings_path;
char *settings_temp_path;
char *checksum;
int tree_fd;
int userns_fd;
@@ -98,7 +96,6 @@ TarPull* tar_pull_unref(TarPull *i) {
free(i->settings_path);
free(i->image_root);
free(i->local);
free(i->checksum);
safe_close(i->tree_fd);
safe_close(i->userns_fd);
@@ -402,13 +399,10 @@ static bool tar_pull_is_done(TarPull *i) {
}
static void tar_pull_job_on_finished(PullJob *j) {
TarPull *i;
int r;
assert(j);
assert(j->userdata);
i = j->userdata;
TarPull *i = ASSERT_PTR(j->userdata);
if (j->error != 0) {
clear_progress_bar(/* prefix= */ NULL);
@@ -478,7 +472,6 @@ static void tar_pull_job_on_finished(PullJob *j) {
clear_progress_bar(/* prefix= */ NULL);
r = pull_verify(i->verify,
i->checksum,
i->tar_job,
i->checksum_job,
i->signature_job,
@@ -586,13 +579,11 @@ finish:
static int tar_pull_job_on_open_disk_tar(PullJob *j) {
const char *where;
TarPull *i;
int r;
assert(j);
assert(j->userdata);
i = j->userdata;
TarPull *i = ASSERT_PTR(j->userdata);
assert(i->tar_job == j);
assert(!pidref_is_set(&i->tar_pid));
assert(i->tree_fd < 0);
@@ -698,17 +689,17 @@ int tar_pull_start(
const char *local,
ImportFlags flags,
ImportVerify verify,
const char *checksum) {
const struct iovec *checksum) {
int r;
assert(i);
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
assert((verify < 0) || !checksum);
assert((verify < 0) || !iovec_is_set(checksum));
assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_TAR));
assert(!(flags & IMPORT_PULL_SETTINGS) || !(flags & IMPORT_DIRECT));
assert(!(flags & IMPORT_PULL_SETTINGS) || !checksum);
assert(!(flags & IMPORT_PULL_SETTINGS) || !iovec_is_set(checksum));
if (!http_url_is_valid(url) && !file_url_is_valid(url))
return -EINVAL;
@@ -723,10 +714,6 @@ int tar_pull_start(
if (r < 0)
return r;
r = free_and_strdup(&i->checksum, checksum);
if (r < 0)
return r;
i->flags = flags;
i->verify = verify;
@@ -737,7 +724,14 @@ int tar_pull_start(
i->tar_job->on_finished = tar_pull_job_on_finished;
i->tar_job->on_open_disk = tar_pull_job_on_open_disk_tar;
i->tar_job->calc_checksum = checksum || IN_SET(verify, IMPORT_VERIFY_CHECKSUM, IMPORT_VERIFY_SIGNATURE);
if (iovec_is_set(checksum)) {
if (!iovec_memdup(checksum, &i->tar_job->expected_checksum))
return -ENOMEM;
i->tar_job->calc_checksum = true;
} else
i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
if (!FLAGS_SET(flags, IMPORT_DIRECT)) {
r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
@@ -750,7 +744,6 @@ int tar_pull_start(
&i->checksum_job,
&i->signature_job,
verify,
checksum,
url,
i->glue,
tar_pull_job_on_finished,

View File

@@ -14,4 +14,4 @@ TarPull* tar_pull_unref(TarPull *pull);
DEFINE_TRIVIAL_CLEANUP_FUNC(TarPull*, tar_pull_unref);
int tar_pull_start(TarPull *pull, const char *url, const char *local, ImportFlags flags, ImportVerify verify, const char *checksum);
int tar_pull_start(TarPull *pull, const char *url, const char *local, ImportFlags flags, ImportVerify verify, const struct iovec *checksum);

View File

@@ -15,6 +15,7 @@
#include "import-common.h"
#include "import-util.h"
#include "io-util.h"
#include "iovec-util.h"
#include "log.h"
#include "main-func.h"
#include "parse-argument.h"
@@ -32,11 +33,11 @@ static char *arg_image_root = NULL;
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHASH | IMPORT_PULL_ROOTHASH_SIGNATURE | IMPORT_PULL_VERITY | IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
static char *arg_checksum = NULL;
static struct iovec arg_checksum = {};
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
STATIC_DESTRUCTOR_REGISTER(arg_checksum, iovec_done);
STATIC_DESTRUCTOR_REGISTER(arg_image_root, freep);
static int normalize_local(const char *local, const char *url, char **ret) {
@@ -162,7 +163,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
normalized,
arg_import_flags & IMPORT_PULL_FLAGS_MASK_TAR,
arg_verify,
arg_checksum);
&arg_checksum);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@@ -231,7 +232,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
arg_size_max,
arg_import_flags & IMPORT_PULL_FLAGS_MASK_RAW,
arg_verify,
arg_checksum);
&arg_checksum);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@@ -371,7 +372,6 @@ static int parse_argv(int argc, char *argv[]) {
v = import_verify_from_string(optarg);
if (v < 0) {
_cleanup_free_ void *h = NULL;
char *hh;
size_t n;
/* If this is not a valid verification mode, maybe it's a literally specified
@@ -385,11 +385,10 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"64 hex character SHA256 hash required when specifying explicit checksum, %zu specified", n * 2);
hh = hexmem(h, n); /* bring into canonical (lowercase) form */
if (!hh)
return log_oom();
iovec_done(&arg_checksum);
arg_checksum.iov_base = TAKE_PTR(h);
arg_checksum.iov_len = n;
free_and_replace(arg_checksum, hh);
arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
arg_verify = _IMPORT_VERIFY_INVALID;
} else
@@ -542,7 +541,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset only supported in --direct mode.");
if (arg_checksum && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0)
if (iovec_is_set(&arg_checksum) && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Literal checksum verification only supported if no associated files are downloaded.");
if (!arg_image_root) {