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 b368e107e90..4c5c57cdd74 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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 QiH1`ldmwl=`fud@FHL^ng#Z8m literal 0 Hc-jL100001 diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 6fb088278a7..67c805ed47e 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 5157b94a346..9392477787b 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 d40c0b03788..f59a2bbb998 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.39.5