1
0
mirror of https://github.com/systemd/systemd synced 2025-11-10 20:34:45 +01:00

Compare commits

..

No commits in common. "aae054e1ab156d44f669c60140c213c0ec35b2d0" and "f8293452b65551c75534a35af8e6202a45837299" have entirely different histories.

10 changed files with 168 additions and 179 deletions

View File

@ -6,7 +6,6 @@
#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"
@ -248,6 +247,7 @@ 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 < 0 || /* verification already done (via literal checksum) */
verify == IMPORT_VERIFY_NO) { /* verification turned off */
if (verify == IMPORT_VERIFY_NO || checksum) {
*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(iovec_is_set(&job->checksum));
assert(job->checksum);
r = import_url_last_component(job->url, &fn);
if (r < 0)
@ -365,10 +365,6 @@ 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 */
@ -376,12 +372,12 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
" " /* non-standard separator used by linuxcontainers.org */) {
_cleanup_free_ char *line = NULL;
line = strjoin(cs, separator, fn, "\n");
line = strjoin(job->checksum, separator, fn, "\n");
if (!line)
return log_oom();
p = memmem_safe(checksum_job->payload.iov_base,
checksum_job->payload.iov_len,
p = memmem_safe(checksum_job->payload,
checksum_job->payload_size,
line,
strlen(line));
if (p)
@ -389,7 +385,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.iov_base && p[-1] != '\n'))
if (!p || (p != (char*) checksum_job->payload && 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 +394,8 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
}
static int verify_gpg(
const struct iovec *payload,
const struct iovec *signature) {
const void *payload, size_t payload_size,
const void *signature, size_t signature_size) {
_cleanup_close_pair_ int gpg_pipe[2] = EBADF_PAIR;
_cleanup_(rm_rf_physical_and_freep) char *gpg_home = NULL;
@ -407,21 +403,21 @@ static int verify_gpg(
_cleanup_(sigkill_waitp) pid_t pid = 0;
int r;
assert(iovec_is_valid(payload));
assert(iovec_is_valid(signature));
assert(payload || payload_size == 0);
assert(signature || signature_size == 0);
r = pipe2(gpg_pipe, O_CLOEXEC);
if (r < 0)
return log_error_errno(errno, "Failed to create pipe for gpg: %m");
if (iovec_is_set(signature)) {
if (signature_size > 0) {
_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->iov_base, signature->iov_len);
r = loop_write(sig_file, signature, signature_size);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
@ -487,13 +483,11 @@ static int verify_gpg(
gpg_pipe[0] = safe_close(gpg_pipe[0]);
if (iovec_is_set(payload)) {
r = loop_write(gpg_pipe[1], payload->iov_base, payload->iov_len);
r = loop_write(gpg_pipe[1], payload, payload_size);
if (r < 0) {
log_error_errno(r, "Failed to write to pipe: %m");
goto finish;
}
}
gpg_pipe[1] = safe_close(gpg_pipe[1]);
@ -509,13 +503,14 @@ static int verify_gpg(
}
finish:
if (iovec_is_set(signature))
if (signature_size > 0)
(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,
@ -531,13 +526,33 @@ 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 < 0 || /* verification already done (via literal checksum) */
verify == IMPORT_VERIFY_NO) /* verification turned off */
if (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);
@ -551,11 +566,11 @@ int pull_verify(ImportVerify verify,
verify_job = main_job;
} else {
assert(main_job->calc_checksum);
assert(iovec_is_set(&main_job->checksum));
assert(main_job->checksum);
assert(checksum_job);
assert(checksum_job->state == PULL_JOB_DONE);
if (!iovec_is_set(&checksum_job->payload))
if (!checksum_job->payload || checksum_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
@ -581,11 +596,11 @@ int pull_verify(ImportVerify verify,
assert(signature_job);
assert(signature_job->state == PULL_JOB_DONE);
if (!iovec_is_set(&signature_job->payload))
if (!signature_job->payload || signature_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
return verify_gpg(&verify_job->payload, &signature_job->payload);
return verify_gpg(verify_job->payload, verify_job->payload_size, signature_job->payload, signature_job->payload_size);
}
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 *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 *checksum, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
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);
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);
typedef enum VerificationStyle {
VERIFICATION_PER_FILE, /* SUSE-style ".sha256" files with detached gpg signature */

View File

@ -20,16 +20,6 @@
#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;
@ -57,9 +47,8 @@ PullJob* pull_job_unref(PullJob *j) {
free(j->url);
free(j->etag);
strv_free(j->old_etags);
iovec_done(&j->payload);
iovec_done(&j->checksum);
iovec_done(&j->expected_checksum);
free(j->payload);
free(j->checksum);
return mfree(j);
}
@ -95,16 +84,15 @@ static int pull_job_restart(PullJob *j, const char *new_url) {
j->state = PULL_JOB_INIT;
j->error = 0;
iovec_done(&j->payload);
j->payload = mfree(j->payload);
j->payload_size = 0;
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;
iovec_done(&j->checksum);
iovec_done(&j->expected_checksum);
j->expected_content_length = UINT64_MAX;
j->checksum = mfree(j->checksum);
curl_glue_remove_and_free(j->glue, j->curl);
j->curl = NULL;
@ -126,15 +114,6 @@ 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;
@ -187,7 +166,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
if (http_status_etag_exists(status)) {
if (status == 304) {
log_info("Image already downloaded. Skipping download.");
j->etag_exists = true;
r = 0;
@ -235,46 +214,30 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
uint64_t cl = pull_job_content_length_effective(j);
if (cl != UINT64_MAX &&
cl != j->written_compressed) {
if (j->content_length != UINT64_MAX &&
j->content_length != 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];
iovec_done(&j->checksum);
j->checksum.iov_base = malloc(EVP_MAX_MD_SIZE);
if (!j->checksum.iov_base) {
r = log_oom();
goto finish;
}
r = EVP_DigestFinal_ex(j->checksum_ctx, j->checksum.iov_base, &checksum_len);
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 <= EVP_MAX_MD_SIZE);
j->checksum.iov_len = checksum_len;
assert(checksum_len <= sizeof k);
if (DEBUG_LOGGING) {
_cleanup_free_ char *h = hexmem(j->checksum.iov_base, j->checksum.iov_len);
if (!h) {
j->checksum = hexmem(k, checksum_len);
if (!j->checksum) {
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;
}
log_debug("SHA256 of %s is %s.", j->url, j->checksum);
}
/* Do a couple of finishing disk operations, but only if we are the sole owner of the file (i.e. no
@ -380,14 +343,11 @@ static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata)
}
if (j->disk_fd < 0 || j->force_memory) {
uint8_t *a = j->payload.iov_base;
if (!GREEDY_REALLOC(a, j->payload.iov_len + sz + 1))
if (!GREEDY_REALLOC(j->payload, j->payload_size + sz))
return log_oom();
*((uint8_t*) mempcpy(a + j->payload.iov_len, p, sz)) = 0;
j->payload.iov_base = a;
j->payload.iov_len += sz;
memcpy(j->payload + j->payload_size, p, sz);
j->payload_size += sz;
}
j->written_uncompressed += sz;
@ -399,39 +359,38 @@ finish:
return 0;
}
static int pull_job_write_compressed(PullJob *j, const struct iovec *data) {
static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
int r;
assert(j);
assert(iovec_is_valid(data));
assert(p);
if (!iovec_is_set(data))
if (sz <= 0)
return 0;
if (j->written_compressed + data->iov_len < j->written_compressed)
if (j->written_compressed + sz < j->written_compressed)
return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "File too large, overflow");
if (j->written_compressed + data->iov_len > j->compressed_max)
if (j->written_compressed + sz > 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 + data->iov_len > cl)
if (j->content_length != UINT64_MAX &&
j->written_compressed + sz > j->content_length)
return log_error_errno(SYNTHETIC_ERRNO(EFBIG),
"Content length incorrect.");
if (j->checksum_ctx) {
r = EVP_DigestUpdate(j->checksum_ctx, data->iov_base, data->iov_len);
r = EVP_DigestUpdate(j->checksum_ctx, p, sz);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Could not hash chunk.");
}
r = import_uncompress(&j->compress, data->iov_base, data->iov_len, pull_job_write_uncompressed, j);
r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
if (r < 0)
return r;
j->written_compressed += data->iov_len;
j->written_compressed += sz;
return 0;
}
@ -472,11 +431,14 @@ 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.iov_base, j->payload.iov_len);
r = import_uncompress_detect(&j->compress, j->payload, j->payload_size);
if (r < 0)
return log_error_errno(r, "Failed to initialize compressor: %m");
if (r == 0)
@ -489,11 +451,15 @@ static int pull_job_detect_compression(PullJob *j) {
return r;
/* Now, take the payload we read so far, and decompress it */
_cleanup_(iovec_done) struct iovec stub = TAKE_STRUCT(j->payload);
stub = j->payload;
stub_size = j->payload_size;
j->payload = NULL;
j->payload_size = 0;
j->state = PULL_JOB_RUNNING;
r = pull_job_write_compressed(j, &stub);
r = pull_job_write_compressed(j, stub, stub_size);
if (r < 0)
return r;
@ -511,11 +477,15 @@ 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 (!iovec_append(&j->payload, &IOVEC_MAKE(contents, sz))) {
if (!GREEDY_REALLOC(j->payload, j->payload_size + 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;
@ -523,7 +493,8 @@ 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, &IOVEC_MAKE(contents, sz));
r = pull_job_write_compressed(j, contents, sz);
if (r < 0)
goto fail;
@ -545,6 +516,16 @@ 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;
@ -608,12 +589,6 @@ 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);
}
@ -716,7 +691,6 @@ 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,9 +58,8 @@ typedef struct PullJob {
uint64_t uncompressed_max;
uint64_t compressed_max;
uint64_t expected_content_length;
struct iovec payload;
uint8_t *payload;
size_t payload_size;
int disk_fd;
bool close_disk_fd;
@ -77,9 +76,7 @@ typedef struct PullJob {
bool calc_checksum;
EVP_MD_CTX *checksum_ctx;
struct iovec checksum;
struct iovec expected_checksum;
char *checksum;
bool sync;
bool force_memory;
} PullJob;

View File

@ -67,6 +67,8 @@ typedef struct RawPull {
char *verity_path;
char *verity_temp_path;
char *checksum;
} RawPull;
RawPull* raw_pull_unref(RawPull *i) {
@ -97,6 +99,7 @@ RawPull* raw_pull_unref(RawPull *i) {
free(i->verity_path);
free(i->image_root);
free(i->local);
free(i->checksum);
return mfree(i);
}
@ -500,10 +503,13 @@ static int raw_pull_rename_auxiliary_file(
}
static void raw_pull_job_on_finished(PullJob *j) {
RawPull *i;
int r;
assert(j);
RawPull *i = ASSERT_PTR(j->userdata);
assert(j->userdata);
i = j->userdata;
if (j->error != 0) {
/* Only the main job and the checksum job are fatal if they fail. The other fails are just
@ -579,6 +585,7 @@ 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,
@ -820,7 +827,7 @@ int raw_pull_start(
uint64_t size_max,
ImportFlags flags,
ImportVerify verify,
const struct iovec *checksum) {
const char *checksum) {
int r;
@ -828,11 +835,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) || !iovec_is_set(checksum));
assert((verify < 0) || !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)) || !iovec_is_set(checksum));
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !checksum);
if (!http_url_is_valid(url) && !file_url_is_valid(url))
return -EINVAL;
@ -847,6 +854,10 @@ 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;
@ -858,12 +869,9 @@ 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 (iovec_is_set(checksum)) {
if (!iovec_memdup(checksum, &i->raw_job->expected_checksum))
return -ENOMEM;
if (checksum)
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. */
@ -872,7 +880,7 @@ int raw_pull_start(
return r;
i->raw_job->calc_checksum = r;
i->raw_job->force_memory = !r; /* make sure this is both written to disk if that's
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 */
}
@ -891,6 +899,7 @@ 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 struct iovec *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 char *checksum);

View File

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

View File

@ -15,7 +15,6 @@
#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"
@ -33,11 +32,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 struct iovec arg_checksum = {};
static char *arg_checksum = NULL;
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_checksum, iovec_done);
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_root, freep);
static int normalize_local(const char *local, const char *url, char **ret) {
@ -163,7 +162,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");
@ -232,7 +231,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");
@ -372,6 +371,7 @@ 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,10 +385,11 @@ 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);
iovec_done(&arg_checksum);
arg_checksum.iov_base = TAKE_PTR(h);
arg_checksum.iov_len = n;
hh = hexmem(h, n); /* bring into canonical (lowercase) form */
if (!hh)
return log_oom();
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
@ -541,7 +542,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 (iovec_is_set(&arg_checksum) && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0)
if (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) {

View File

@ -15,44 +15,30 @@
#include "process-util.h"
#include "string-util.h"
/* Maximum namespace name length */
#define NAMESPACE_NAME_MAX 16U
/* So the namespace name should be 16 chars at max (because we want that it is usable in usernames, which
* have a limit of 31 chars effectively, and the nsresourced service wants to prefix/suffix some bits). But
* it also should be unique if we are called multiple times in a row. Hence we take the "comm" name (which is
* 15 chars), and suffix it with the PID and a counter, possibly overriding the end. */
assert_cc(TASK_COMM_LEN == NAMESPACE_NAME_MAX);
static int make_pid_name(char **ret) {
char comm[TASK_COMM_LEN];
static uint64_t counter = 0;
assert(ret);
if (prctl(PR_GET_NAME, comm) < 0)
return -errno;
/* So the namespace name should be 16 chars at max (because we want that it is usable in usernames,
* which have a limit of 31 chars effectively, and the nsresourced service wants to prefix/suffix
* some bits). But it also should be unique if we are called multiple times in a row. Hence we take
* the "comm" name (which is 15 chars), and suffix it with the PID, possibly overriding the end. */
assert_cc(TASK_COMM_LEN == 15 + 1);
char spid[DECIMAL_STR_MAX(pid_t)];
xsprintf(spid, PID_FMT, getpid_cached());
/* Include a counter in the name, so that we can allocate multiple namespaces per process, with
* unique names. For the first namespace we suppress the suffix */
char scounter[sizeof(counter) * 2 + 1];
if (counter == 0)
scounter[0] = 0;
else
xsprintf(scounter, "%" PRIx64, counter);
counter++;
assert(strlen(spid) <= 16);
strshorten(comm, 16 - strlen(spid));
strshorten(comm, LESS_BY(NAMESPACE_NAME_MAX, strlen(spid) + strlen(scounter)));
_cleanup_free_ char *s = strjoin(comm, spid, scounter);
_cleanup_free_ char *s = strjoin(comm, spid);
if (!s)
return -ENOMEM;
strshorten(s, NAMESPACE_NAME_MAX);
*ret = TAKE_PTR(s);
return 0;
}