From 3576d6315f3b6b686cdcf9f280d5e829e3d3daa0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jan 2015 03:01:13 +0100 Subject: [PATCH] import: add image verification using gpg This also adds an initial keyring for the verification, that contains Ubuntu's and Fedora's key. We should probably add more entries sooner or later. --- Makefile.am | 13 +- src/import/import-pubring.gpg | Bin 0 -> 9551 bytes src/import/import-raw.c | 261 ++++++++++++++++++++++++---------- src/shared/util.c | 10 ++ src/shared/util.h | 3 + 5 files changed, 210 insertions(+), 77 deletions(-) create mode 100644 src/import/import-pubring.gpg diff --git a/Makefile.am b/Makefile.am index b368e107e..4c5c57cdd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5275,7 +5275,9 @@ systemd_import_CFLAGS = \ $(LIBCURL_CFLAGS) \ $(XZ_CFLAGS) \ $(ZLIB_CFLAGS) \ - $(GCRYPT_CFLAGS) + $(GCRYPT_CFLAGS) \ + -D VENDOR_KEYRING_PATH=\"$(rootlibexecdir)/import-pubring.gpg\" \ + -D USER_KEYRING_PATH=\"$(pkgsysconfdir)/import-pubring.gpg\" systemd_import_LDADD = \ libsystemd-internal.la \ @@ -5303,6 +5305,9 @@ test_qcow2_LDADD = \ libsystemd-label.la \ libsystemd-shared.la \ $(ZLIB_LIBS) + +dist_rootlibexec_DATA = \ + src/import/import-pubring.gpg endif endif endif @@ -6668,3 +6673,9 @@ git-contrib: EXTRA_DIST += \ tools/gdb-sd_dump_hashmaps.py + +list-keys: + gpg --verbose --no-options --no-default-keyring --no-auto-key-locate --batch --trust-model=always --keyring=$(srcdir)/src/import/import-pubring.gpg --list-keys + +add-key: + gpg --verbose --no-options --no-default-keyring --no-auto-key-locate --batch --trust-model=always --keyring=$(srcdir)/src/import/import-pubring.gpg --import - diff --git a/src/import/import-pubring.gpg b/src/import/import-pubring.gpg new file mode 100644 index 0000000000000000000000000000000000000000..be27776896f30f580b03ad79d733483f81c8d117 GIT binary patch literal 9551 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 literal 0 HcmV?d00001 diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 6fb088278..67c805ed4 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -47,6 +48,7 @@ struct RawImport { ImportJob *raw_job; ImportJob *sha256sums_job; + ImportJob *signature_job; RawImportFinished on_finished; void *userdata; @@ -65,6 +67,8 @@ RawImport* raw_import_unref(RawImport *i) { return NULL; import_job_unref(i->raw_job); + import_job_unref(i->sha256sums_job); + import_job_unref(i->signature_job); curl_glue_unref(i->glue); sd_event_unref(i->event); @@ -248,17 +252,25 @@ static int raw_import_make_local_copy(RawImport *i) { } static int raw_import_verify_sha256sum(RawImport *i) { + _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 }; _cleanup_free_ char *fn = NULL; + _cleanup_close_ int sig_file = -1; const char *p, *line; + char sig_file_path[] = "/tmp/sigXXXXXX"; + _cleanup_sigkill_wait_ pid_t pid = 0; int r; assert(i); - assert(i->verify != IMPORT_VERIFY_NO); assert(i->raw_job); + + if (!i->sha256sums_job) + return 0; + + assert(i->raw_job->state == IMPORT_JOB_DONE); assert(i->raw_job->sha256); - assert(i->sha256sums_job); + assert(i->sha256sums_job->state == IMPORT_JOB_DONE); assert(i->sha256sums_job->payload); assert(i->sha256sums_job->payload_size > 0); @@ -285,56 +297,125 @@ static int raw_import_verify_sha256sum(RawImport *i) { log_info("SHA256 checksum of %s is valid.", i->raw_job->url); - return 0; -} + if (!i->signature_job) + return 0; -static int raw_import_finalize(RawImport *i) { - int r; + assert(i->signature_job->state == IMPORT_JOB_DONE); + assert(i->signature_job->payload); + assert(i->signature_job->payload_size > 0); - assert(i); + r = pipe2(gpg_pipe, O_CLOEXEC); + if (r < 0) + return log_error_errno(errno, "Failed to create pipe: %m"); - if (!IMPORT_JOB_STATE_IS_COMPLETE(i->raw_job) || - (i->verify != IMPORT_VERIFY_NO && !IMPORT_JOB_STATE_IS_COMPLETE(i->sha256sums_job))) - return 0; + sig_file = mkostemp(sig_file_path, O_RDWR); + if (sig_file < 0) + return log_error_errno(errno, "Failed to create temporary file: %m"); - if (i->verify != IMPORT_VERIFY_NO && - i->raw_job->etag_exists) { + r = loop_write(sig_file, i->signature_job->payload, i->signature_job->payload_size, false); + if (r < 0) { + log_error_errno(r, "Failed to write to temporary file: %m"); + goto finish; + } - assert(i->temp_path); - assert(i->final_path); - assert(i->raw_job->disk_fd >= 0); + pid = fork(); + if (pid < 0) + return log_error_errno(errno, "Failed to fork off gpg: %m"); + if (pid == 0) { + const char *cmd[] = { + "gpg", + "--no-options", + "--no-default-keyring", + "--no-auto-key-locate", + "--no-auto-check-trustdb", + "--batch", + "--trust-model=always", + "--keyring=" VENDOR_KEYRING_PATH, + NULL, /* maybe user keyring */ + NULL, /* --verify */ + NULL, /* signature file */ + NULL, /* dash */ + NULL /* trailing NULL */ + }; + unsigned k = ELEMENTSOF(cmd) - 5; + int null_fd; + + /* Child */ + + reset_all_signal_handlers(); + reset_signal_mask(); + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + + gpg_pipe[1] = safe_close(gpg_pipe[1]); + + if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) { + log_error_errno(errno, "Failed to dup2() fd: %m"); + _exit(EXIT_FAILURE); + } - r = raw_import_verify_sha256sum(i); - if (r < 0) - return r; + if (gpg_pipe[0] != STDIN_FILENO) + gpg_pipe[0] = safe_close(gpg_pipe[0]); - r = rename(i->temp_path, i->final_path); - if (r < 0) - return log_error_errno(errno, "Failed to move RAW file into place: %m"); + null_fd = open("/dev/null", O_WRONLY|O_NOCTTY); + if (null_fd < 0) { + log_error_errno(errno, "Failed to open /dev/null: %m"); + _exit(EXIT_FAILURE); + } - free(i->temp_path); - i->temp_path = NULL; + if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) { + log_error_errno(errno, "Failed to dup2() fd: %m"); + _exit(EXIT_FAILURE); + } + + if (null_fd != STDOUT_FILENO) + null_fd = safe_close(null_fd); + + /* We add the user keyring only to the command line + * arguments, if it's around since gpg fails + * otherwise. */ + if (access(USER_KEYRING_PATH, F_OK) >= 0) + cmd[k++] = "--keyring=" USER_KEYRING_PATH; + + cmd[k++] = "--verify"; + cmd[k++] = sig_file_path; + cmd[k++] = "-"; + cmd[k++] = NULL; + + execvp("gpg", (char * const *) cmd); + log_error_errno(errno, "Failed to execute gpg: %m"); + _exit(EXIT_FAILURE); } - r = raw_import_make_local_copy(i); - if (r < 0) - return r; + gpg_pipe[0] = safe_close(gpg_pipe[0]); - i->raw_job->disk_fd = safe_close(i->raw_job->disk_fd); + r = loop_write(gpg_pipe[1], i->sha256sums_job->payload, i->sha256sums_job->payload_size, false); + if (r < 0) { + log_error_errno(r, "Failed to write to pipe: %m"); + goto finish; + } - return 1; -} + gpg_pipe[1] = safe_close(gpg_pipe[1]); -static void raw_import_invoke_finished(RawImport *i, int r) { - assert(i); + r = wait_for_terminate_and_warn("gpg", pid, true); + pid = 0; + if (r < 0) + goto finish; + if (r > 0) { + log_error("Signature verification failed."); + r = -EBADMSG; + } else { + log_info("Signature verification succeeded."); + r = 0; + } - if (i->on_finished) - i->on_finished(i, r, i->userdata); - else - sd_event_exit(i->event, r); +finish: + if (sig_file >= 0) + unlink(sig_file_path); + + return r; } -static void raw_import_raw_job_on_finished(ImportJob *j) { +static void raw_import_job_on_finished(ImportJob *j) { RawImport *i; int r; @@ -343,6 +424,13 @@ static void raw_import_raw_job_on_finished(ImportJob *j) { i = j->userdata; if (j->error != 0) { + if (j == i->sha256sums_job) + log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)"); + else if (j == i->signature_job) + log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + else + log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)"); + r = j->error; goto finish; } @@ -350,60 +438,56 @@ static void raw_import_raw_job_on_finished(ImportJob *j) { /* This is invoked if either the download completed * successfully, or the download was skipped because we * already have the etag. In this case ->etag_exists is - * true. */ + * true. + * + * We only do something when we got all three files */ - if (!j->etag_exists) { - assert(j->disk_fd >= 0); + if (!IMPORT_JOB_STATE_IS_COMPLETE(i->raw_job)) + return; + if (i->sha256sums_job && !IMPORT_JOB_STATE_IS_COMPLETE(i->sha256sums_job)) + return; + if (i->signature_job && !IMPORT_JOB_STATE_IS_COMPLETE(i->signature_job)) + return; - r = raw_import_maybe_convert_qcow2(i); + if (!i->raw_job->etag_exists) { + assert(i->raw_job->disk_fd >= 0); + + r = raw_import_verify_sha256sum(i); if (r < 0) goto finish; - r = import_make_read_only_fd(j->disk_fd); + r = raw_import_maybe_convert_qcow2(i); if (r < 0) goto finish; - } - - r = raw_import_finalize(i); - if (r < 0) - goto finish; - if (r == 0) - return; - - r = 0; -finish: - raw_import_invoke_finished(i, r); -} - -static void raw_import_sha256sums_job_on_finished(ImportJob *j) { - RawImport *i; - int r; - - assert(j); - assert(j->userdata); + r = import_make_read_only_fd(i->raw_job->disk_fd); + if (r < 0) + goto finish; - i = j->userdata; - assert(i->verify != IMPORT_VERIFY_NO); + r = rename(i->temp_path, i->final_path); + if (r < 0) { + r = log_error_errno(errno, "Failed to move RAW file into place: %m"); + goto finish; + } - if (j->error != 0) { - log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify."); - r = j->error; - goto finish; + free(i->temp_path); + i->temp_path = NULL; } - r = raw_import_finalize(i); + r = raw_import_make_local_copy(i); if (r < 0) goto finish; - if (r == 0) - return; r = 0; + finish: - raw_import_invoke_finished(i, r); + if (i->on_finished) + i->on_finished(i, r, i->userdata); + else + sd_event_exit(i->event, r); } -static int raw_import_raw_job_on_open_disk(ImportJob *j) { +static int raw_import_job_on_open_disk(ImportJob *j) { RawImport *i; int r; @@ -434,7 +518,6 @@ static int raw_import_raw_job_on_open_disk(ImportJob *j) { } int raw_import_pull(RawImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) { - _cleanup_free_ char *sha256sums_url = NULL; int r; assert(i); @@ -461,8 +544,8 @@ int raw_import_pull(RawImport *i, const char *url, const char *local, bool force if (r < 0) return r; - i->raw_job->on_finished = raw_import_raw_job_on_finished; - i->raw_job->on_open_disk = raw_import_raw_job_on_open_disk; + i->raw_job->on_finished = raw_import_job_on_finished; + i->raw_job->on_open_disk = raw_import_job_on_open_disk; i->raw_job->calc_hash = true; r = import_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags); @@ -470,6 +553,8 @@ int raw_import_pull(RawImport *i, const char *url, const char *local, bool force return r; if (verify != IMPORT_VERIFY_NO) { + _cleanup_free_ char *sha256sums_url = NULL; + /* Queue job for the SHA256SUMS file for the image */ r = import_url_change_last_component(url, "SHA256SUMS", &sha256sums_url); if (r < 0) @@ -479,17 +564,41 @@ int raw_import_pull(RawImport *i, const char *url, const char *local, bool force if (r < 0) return r; - i->sha256sums_job->on_finished = raw_import_sha256sums_job_on_finished; + i->sha256sums_job->on_finished = raw_import_job_on_finished; i->sha256sums_job->uncompressed_max = i->sha256sums_job->compressed_max = 1ULL * 1024ULL * 1024ULL; + } - r = import_job_begin(i->sha256sums_job); + if (verify == IMPORT_VERIFY_SIGNATURE) { + _cleanup_free_ char *sha256sums_sig_url = NULL; + + /* Queue job for the SHA256SUMS.gpg file for the image. */ + r = import_url_change_last_component(url, "SHA256SUMS.gpg", &sha256sums_sig_url); if (r < 0) return r; + + r = import_job_new(&i->signature_job, sha256sums_sig_url, i->glue, i); + if (r < 0) + return r; + + i->signature_job->on_finished = raw_import_job_on_finished; + i->signature_job->uncompressed_max = i->signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL; } r = import_job_begin(i->raw_job); if (r < 0) return r; + if (i->sha256sums_job) { + r = import_job_begin(i->sha256sums_job); + if (r < 0) + return r; + } + + if (i->signature_job) { + r = import_job_begin(i->signature_job); + if (r < 0) + return r; + } + return 0; } diff --git a/src/shared/util.c b/src/shared/util.c index 5157b94a3..939247778 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -8011,3 +8011,13 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { return q - (const uint8_t*) p; } + +void sigkill_wait(pid_t *pid) { + if (!pid) + return; + if (*pid <= 1) + return; + + if (kill(*pid, SIGKILL) > 0) + (void) wait_for_terminate(*pid, NULL); +} diff --git a/src/shared/util.h b/src/shared/util.h index d40c0b037..f59a2bbb9 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -1065,3 +1065,6 @@ void release_lock_file(LockFile *f); #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); + +void sigkill_wait(pid_t *pid); +#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) -- 2.30.2