| |
@@ -0,0 +1,431 @@
|
| |
+ From ea1177fcef609519f0c2377ebee236001d2a8fae Mon Sep 17 00:00:00 2001
|
| |
+ From: chantra <chantr4@gmail.com>
|
| |
+ Date: Fri, 28 Jan 2022 08:31:39 -0800
|
| |
+ Subject: [PATCH 06/30] [rpm2extents] verify package signature during
|
| |
+ transcoding
|
| |
+
|
| |
+ ---
|
| |
+ lib/rpmchecksig.c | 30 ++++++
|
| |
+ lib/rpmcli.h | 9 ++
|
| |
+ rpm2extents.c | 233 +++++++++++++++++++++++++++++++++++++++++-----
|
| |
+ 3 files changed, 248 insertions(+), 24 deletions(-)
|
| |
+
|
| |
+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c
|
| |
+ index 40a3ab83f..1a6b95323 100644
|
| |
+ --- a/lib/rpmchecksig.c
|
| |
+ +++ b/lib/rpmchecksig.c
|
| |
+ @@ -304,3 +304,33 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
|
| |
+ rpmKeyringFree(keyring);
|
| |
+ return res;
|
| |
+ }
|
| |
+ +
|
| |
+ +int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi)
|
| |
+ +{
|
| |
+ + int res = 0;
|
| |
+ + rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
|
| |
+ + rpmVSFlags vsflags = rpmtsVfyFlags(ts);
|
| |
+ + int vfylevel = rpmtsVfyLevel(ts);
|
| |
+ +
|
| |
+ + vsflags |= rpmcliVSFlags;
|
| |
+ + if (rpmcliVfyLevelMask) {
|
| |
+ + vfylevel &= ~rpmcliVfyLevelMask;
|
| |
+ + rpmtsSetVfyLevel(ts, vfylevel);
|
| |
+ + }
|
| |
+ +
|
| |
+ + FD_t fd = fdDup(Fileno(fdi));
|
| |
+ + if (fd == NULL || Ferror(fd)) {
|
| |
+ + rpmlog(RPMLOG_ERR, _("fdDup failed: %s\n"), Fstrerror(fd));
|
| |
+ + res++;
|
| |
+ + } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, "stdin")) {
|
| |
+ + res++;
|
| |
+ + }
|
| |
+ +
|
| |
+ + lseek(Fileno(fd), SEEK_SET, 0);
|
| |
+ + Fclose(fd);
|
| |
+ + rpmsqPoll();
|
| |
+ +
|
| |
+ + rpmKeyringFree(keyring);
|
| |
+ + return res;
|
| |
+ +}
|
| |
+ +
|
| |
+ diff --git a/lib/rpmcli.h b/lib/rpmcli.h
|
| |
+ index 906fe9951..52443e459 100644
|
| |
+ --- a/lib/rpmcli.h
|
| |
+ +++ b/lib/rpmcli.h
|
| |
+ @@ -411,6 +411,15 @@ int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv);
|
| |
+ */
|
| |
+ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv);
|
| |
+
|
| |
+ +
|
| |
+ +/** \ingroup rpmcli
|
| |
+ + * Verify package signatures
|
| |
+ + * @param ts transaction set
|
| |
+ + * @param fd a file descriptor to verify
|
| |
+ + * @return 0 on success
|
| |
+ + */
|
| |
+ +int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd);
|
| |
+ +
|
| |
+ #ifdef __cplusplus
|
| |
+ }
|
| |
+ #endif
|
| |
+ diff --git a/rpm2extents.c b/rpm2extents.c
|
| |
+ index c111be0a2..d8e582676 100644
|
| |
+ --- a/rpm2extents.c
|
| |
+ +++ b/rpm2extents.c
|
| |
+ @@ -2,7 +2,9 @@
|
| |
+
|
| |
+ #include "system.h"
|
| |
+
|
| |
+ +#include <rpm/rpmcli.h>
|
| |
+ #include <rpm/rpmlib.h> /* rpmReadPackageFile .. */
|
| |
+ +#include <rpm/rpmlog.h>
|
| |
+ #include <rpm/rpmfi.h>
|
| |
+ #include <rpm/rpmtag.h>
|
| |
+ #include <rpm/rpmio.h>
|
| |
+ @@ -10,6 +12,7 @@
|
| |
+
|
| |
+ #include <rpm/rpmts.h>
|
| |
+ #include "lib/rpmlead.h"
|
| |
+ +#include "lib/rpmts.h"
|
| |
+ #include "lib/signature.h"
|
| |
+ #include "lib/header_internal.h"
|
| |
+ #include "rpmio/rpmio_internal.h"
|
| |
+ @@ -51,6 +54,16 @@ rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit)
|
| |
+ return (unit - (pos % unit)) % unit;
|
| |
+ }
|
| |
+
|
| |
+ +static struct poptOption optionsTable[] = {
|
| |
+ + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
|
| |
+ + N_("Common options for all rpm modes and executables:"), NULL },
|
| |
+ +
|
| |
+ + POPT_AUTOALIAS
|
| |
+ + POPT_AUTOHELP
|
| |
+ + POPT_TABLEEND
|
| |
+ +};
|
| |
+ +
|
| |
+ +
|
| |
+ static int digestor(
|
| |
+ FD_t fdi,
|
| |
+ FD_t fdo,
|
| |
+ @@ -120,7 +133,19 @@ exit:
|
| |
+ return rc;
|
| |
+ }
|
| |
+
|
| |
+ -static rpmRC process_package(FD_t fdi, FD_t validationi)
|
| |
+ +static rpmRC validator(FD_t fdi){
|
| |
+ + rpmts ts = rpmtsCreate();
|
| |
+ + rpmtsSetRootDir(ts, rpmcliRootDir);
|
| |
+ + /* rpmlog prints NOTICE to stdout */
|
| |
+ + // rpmlogSetFile(stderr);
|
| |
+ + if(rpmcliVerifySignaturesFD(ts, fdi)){
|
| |
+ + fprintf(stderr, _("Error validating package\n"));
|
| |
+ + return RPMRC_FAIL;
|
| |
+ + }
|
| |
+ + return RPMRC_OK;
|
| |
+ +}
|
| |
+ +
|
| |
+ +static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
|
| |
+ {
|
| |
+ uint32_t diglen;
|
| |
+ /* GNU C extension: can use diglen from outer context */
|
| |
+ @@ -148,7 +173,7 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
| |
+ rpm_mode_t mode;
|
| |
+ char *rpmio_flags = NULL, *zeros;
|
| |
+ const unsigned char *digest;
|
| |
+ - rpm_loff_t pos, size, pad, validation_pos;
|
| |
+ + rpm_loff_t pos, size, pad, digest_pos, validation_pos;
|
| |
+ uint32_t offset_ix = 0;
|
| |
+ size_t len;
|
| |
+ int next = 0;
|
| |
+ @@ -278,17 +303,26 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
| |
+ goto exit;
|
| |
+ }
|
| |
+ }
|
| |
+ - validation_pos = (
|
| |
+ + digest_pos = (
|
| |
+ pos + sizeof(offset_ix) + sizeof(diglen) +
|
| |
+ offset_ix * (diglen + sizeof(rpm_loff_t))
|
| |
+ );
|
| |
+
|
| |
+ + ssize_t digest_len = ufdCopy(digestori, fdo);
|
| |
+ + if (digest_len == -1) {
|
| |
+ + fprintf(stderr, _("digest table ufdCopy failed\n"));
|
| |
+ + rc = RPMRC_FAIL;
|
| |
+ + goto exit;
|
| |
+ + }
|
| |
+ +
|
| |
+ + validation_pos = digest_pos + digest_len;
|
| |
+ ssize_t validation_len = ufdCopy(validationi, fdo);
|
| |
+ if (validation_len == -1) {
|
| |
+ - fprintf(stderr, _("digest table ufdCopy failed\n"));
|
| |
+ + fprintf(stderr, _("validation output ufdCopy failed\n"));
|
| |
+ rc = RPMRC_FAIL;
|
| |
+ goto exit;
|
| |
+ }
|
| |
+ +
|
| |
+ /* add more padding so the last file can be cloned. It doesn't matter that
|
| |
+ * the table and validation etc are in this space. In fact, it's pretty
|
| |
+ * efficient if it is.
|
| |
+ @@ -307,11 +341,16 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
| |
+ rc = RPMRC_FAIL;
|
| |
+ goto exit;
|
| |
+ }
|
| |
+ - if (Fwrite(&validation_pos, len, 1, fdo) != len) {
|
| |
+ + if (Fwrite(&digest_pos, len, 1, fdo) != len) {
|
| |
+ fprintf(stderr, _("Unable to write offset of validation table\n"));
|
| |
+ rc = RPMRC_FAIL;
|
| |
+ goto exit;
|
| |
+ }
|
| |
+ + if (Fwrite(&validation_pos, len, 1, fdo) != len) {
|
| |
+ + fprintf(stderr, _("Unable to write offset of validation output\n"));
|
| |
+ + rc = RPMRC_FAIL;
|
| |
+ + goto exit;
|
| |
+ + }
|
| |
+ uint64_t magic = MAGIC;
|
| |
+ len = sizeof(magic);
|
| |
+ if (Fwrite(&magic, len, 1, fdo) != len) {
|
| |
+ @@ -327,10 +366,156 @@ exit:
|
| |
+ return rc;
|
| |
+ }
|
| |
+
|
| |
+ +static off_t ufdTee(FD_t sfd, FD_t *fds, int len)
|
| |
+ +{
|
| |
+ + char buf[BUFSIZ];
|
| |
+ + ssize_t rdbytes, wrbytes;
|
| |
+ + off_t total = 0;
|
| |
+ +
|
| |
+ + while (1) {
|
| |
+ + rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
|
| |
+ +
|
| |
+ + if (rdbytes > 0) {
|
| |
+ + for(int i=0; i < len; i++) {
|
| |
+ + wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, fds[i]);
|
| |
+ + if (wrbytes != rdbytes) {
|
| |
+ + fprintf(stderr, "Error wriing to FD %d: %s\n", i, Fstrerror(fds[i]));
|
| |
+ + total = -1;
|
| |
+ + break;
|
| |
+ + }
|
| |
+ + }
|
| |
+ + if(total == -1){
|
| |
+ + break;
|
| |
+ + }
|
| |
+ + total += wrbytes;
|
| |
+ + } else {
|
| |
+ + if (rdbytes < 0)
|
| |
+ + total = -1;
|
| |
+ + break;
|
| |
+ + }
|
| |
+ + }
|
| |
+ +
|
| |
+ + return total;
|
| |
+ +}
|
| |
+ +
|
| |
+ +static int teeRpm(FD_t fdi, FD_t digestori) {
|
| |
+ + rpmRC rc;
|
| |
+ + off_t offt = -1;
|
| |
+ + int processorpipefd[2];
|
| |
+ + int validatorpipefd[2];
|
| |
+ + int rpmsignpipefd[2];
|
| |
+ + pid_t cpids[2], w;
|
| |
+ + int wstatus;
|
| |
+ + FD_t fds[2];
|
| |
+ +
|
| |
+ + if (pipe(processorpipefd) == -1) {
|
| |
+ + fprintf(stderr, _("Processor pipe failure\n"));
|
| |
+ + return RPMRC_FAIL;
|
| |
+ + }
|
| |
+ +
|
| |
+ + if (pipe(validatorpipefd) == -1) {
|
| |
+ + fprintf(stderr, _("Validator pipe failure\n"));
|
| |
+ + return RPMRC_FAIL;
|
| |
+ + }
|
| |
+ +
|
| |
+ + if (pipe(rpmsignpipefd) == -1) {
|
| |
+ + fprintf(stderr, _("Validator pipe failure\n"));
|
| |
+ + return RPMRC_FAIL;
|
| |
+ + }
|
| |
+ +
|
| |
+ + cpids[0] = fork();
|
| |
+ + if (cpids[0] == 0) {
|
| |
+ + /* child: validator */
|
| |
+ + close(processorpipefd[0]);
|
| |
+ + close(processorpipefd[1]);
|
| |
+ + close(validatorpipefd[1]);
|
| |
+ + close(rpmsignpipefd[0]);
|
| |
+ + FD_t fdi = fdDup(validatorpipefd[0]);
|
| |
+ + // redirect STDOUT to the pipe
|
| |
+ + close(STDOUT_FILENO);
|
| |
+ + FD_t fdo = fdDup(rpmsignpipefd[1]);
|
| |
+ + close(rpmsignpipefd[1]);
|
| |
+ + rc = validator(fdi);
|
| |
+ + if(rc != RPMRC_OK) {
|
| |
+ + fprintf(stderr, _("Validator failed\n"));
|
| |
+ + }
|
| |
+ + Fclose(fdi);
|
| |
+ + Fclose(fdo);
|
| |
+ + if (rc != RPMRC_OK) {
|
| |
+ + exit(EXIT_FAILURE);
|
| |
+ + }
|
| |
+ + exit(EXIT_SUCCESS);
|
| |
+ + } else {
|
| |
+ + /* parent: main program */
|
| |
+ + cpids[1] = fork();
|
| |
+ + if (cpids[1] == 0) {
|
| |
+ + /* child: process_package */
|
| |
+ + close(validatorpipefd[0]);
|
| |
+ + close(validatorpipefd[1]);
|
| |
+ + close(processorpipefd[1]);
|
| |
+ + close(rpmsignpipefd[1]);
|
| |
+ + FD_t fdi = fdDup(processorpipefd[0]);
|
| |
+ + close(processorpipefd[0]);
|
| |
+ + FD_t validatori = fdDup(rpmsignpipefd[0]);
|
| |
+ + close(rpmsignpipefd[0]);
|
| |
+ +
|
| |
+ + rc = process_package(fdi, digestori, validatori);
|
| |
+ + if(rc != RPMRC_OK) {
|
| |
+ + fprintf(stderr, _("Validator failed\n"));
|
| |
+ + }
|
| |
+ + Fclose(digestori);
|
| |
+ + Fclose(validatori);
|
| |
+ + /* fdi is normally closed through the stacked file gzdi in the
|
| |
+ + * function
|
| |
+ + */
|
| |
+ +
|
| |
+ + if (rc != RPMRC_OK) {
|
| |
+ + exit(EXIT_FAILURE);
|
| |
+ + }
|
| |
+ + exit(EXIT_SUCCESS);
|
| |
+ +
|
| |
+ +
|
| |
+ + } else {
|
| |
+ + /* Actual parent. Read from fdi and write to both processes */
|
| |
+ + close(processorpipefd[0]);
|
| |
+ + close(validatorpipefd[0]);
|
| |
+ + fds[0] = fdDup(processorpipefd[1]);
|
| |
+ + fds[1] = fdDup(validatorpipefd[1]);
|
| |
+ + close(validatorpipefd[1]);
|
| |
+ + close(processorpipefd[1]);
|
| |
+ + close(rpmsignpipefd[0]);
|
| |
+ + close(rpmsignpipefd[1]);
|
| |
+ +
|
| |
+ + offt = ufdTee(fdi, fds, 2);
|
| |
+ + if(offt == -1){
|
| |
+ + fprintf(stderr, _("Failed to tee RPM\n"));
|
| |
+ + rc = RPMRC_FAIL;
|
| |
+ + }
|
| |
+ + Fclose(fds[0]);
|
| |
+ + Fclose(fds[1]);
|
| |
+ + w = waitpid(cpids[0], &wstatus, 0);
|
| |
+ + if (w == -1) {
|
| |
+ + fprintf(stderr, _("waitpid cpids[0] failed\n"));
|
| |
+ + rc = RPMRC_FAIL;
|
| |
+ + }
|
| |
+ + w = waitpid(cpids[1], &wstatus, 0);
|
| |
+ + if (w == -1) {
|
| |
+ + fprintf(stderr, _("waitpid cpids[1] failed\n"));
|
| |
+ + rc = RPMRC_FAIL;
|
| |
+ + }
|
| |
+ + }
|
| |
+ + }
|
| |
+ +
|
| |
+ + return rc;
|
| |
+ +}
|
| |
+ +
|
| |
+ int main(int argc, char *argv[]) {
|
| |
+ rpmRC rc;
|
| |
+ int cprc = 0;
|
| |
+ - uint8_t algos[argc - 1];
|
| |
+ + poptContext optCon = NULL;
|
| |
+ + const char **args = NULL;
|
| |
+ + int nb_algos = 0;
|
| |
+ +
|
| |
+ int mainpipefd[2];
|
| |
+ int metapipefd[2];
|
| |
+ pid_t cpid, w;
|
| |
+ @@ -338,29 +523,30 @@ int main(int argc, char *argv[]) {
|
| |
+
|
| |
+ xsetprogname(argv[0]); /* Portability call -- see system.h */
|
| |
+ rpmReadConfigFiles(NULL, NULL);
|
| |
+ + optCon = rpmcliInit(argc, argv, optionsTable);
|
| |
+ + poptSetOtherOptionHelp(optCon, "[OPTIONS]* <DIGESTALGO>");
|
| |
+
|
| |
+ - if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) {
|
| |
+ - fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
|
| |
+ - exit(EXIT_FAILURE);
|
| |
+ - }
|
| |
+ -
|
| |
+ - if (argc == 1) {
|
| |
+ + if (poptPeekArg(optCon) == NULL) {
|
| |
+ fprintf(stderr,
|
| |
+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));
|
| |
+ + poptPrintUsage(optCon, stderr, 0);
|
| |
+ exit(EXIT_FAILURE);
|
| |
+ }
|
| |
+
|
| |
+ - for (int x = 0; x < (argc - 1); x++) {
|
| |
+ - if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
|
| |
+ + args = poptGetArgs(optCon);
|
| |
+ +
|
| |
+ + for (nb_algos=0; args[nb_algos]; nb_algos++);
|
| |
+ + uint8_t algos[nb_algos];
|
| |
+ + for (int x = 0; x < nb_algos; x++) {
|
| |
+ + if (pgpStringVal(PGPVAL_HASHALGO, args[x], &algos[x]) != 0)
|
| |
+ {
|
| |
+ fprintf(stderr,
|
| |
+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
|
| |
+ - argv[x + 1]);
|
| |
+ + args[x]);
|
| |
+ exit(EXIT_FAILURE);
|
| |
+ }
|
| |
+ }
|
| |
+
|
| |
+ -
|
| |
+ if (pipe(mainpipefd) == -1) {
|
| |
+ fprintf(stderr, _("Main pipe failure\n"));
|
| |
+ exit(EXIT_FAILURE);
|
| |
+ @@ -369,6 +555,7 @@ int main(int argc, char *argv[]) {
|
| |
+ fprintf(stderr, _("Meta pipe failure\n"));
|
| |
+ exit(EXIT_FAILURE);
|
| |
+ }
|
| |
+ +
|
| |
+ cpid = fork();
|
| |
+ if (cpid == 0) {
|
| |
+ /* child: digestor */
|
| |
+ @@ -377,7 +564,7 @@ int main(int argc, char *argv[]) {
|
| |
+ FD_t fdi = fdDup(STDIN_FILENO);
|
| |
+ FD_t fdo = fdDup(mainpipefd[1]);
|
| |
+ FD_t validationo = fdDup(metapipefd[1]);
|
| |
+ - rc = digestor(fdi, fdo, validationo, algos, argc - 1);
|
| |
+ + rc = digestor(fdi, fdo, validationo, algos, nb_algos);
|
| |
+ Fclose(validationo);
|
| |
+ Fclose(fdo);
|
| |
+ Fclose(fdi);
|
| |
+ @@ -386,12 +573,10 @@ int main(int argc, char *argv[]) {
|
| |
+ close(mainpipefd[1]);
|
| |
+ close(metapipefd[1]);
|
| |
+ FD_t fdi = fdDup(mainpipefd[0]);
|
| |
+ - FD_t validationi = fdDup(metapipefd[0]);
|
| |
+ - rc = process_package(fdi, validationi);
|
| |
+ - Fclose(validationi);
|
| |
+ - /* fdi is normally closed through the stacked file gzdi in the
|
| |
+ - * function.
|
| |
+ - * Wait for child process (digestor for stdin) to complete.
|
| |
+ + FD_t digestori = fdDup(metapipefd[0]);
|
| |
+ + rc = teeRpm(fdi, digestori);
|
| |
+ + Fclose(digestori);
|
| |
+ + /* Wait for child process (digestor for stdin) to complete.
|
| |
+ */
|
| |
+ if (rc != RPMRC_OK) {
|
| |
+ if (kill(cpid, SIGTERM) != 0) {
|
| |
+ @@ -402,7 +587,7 @@ int main(int argc, char *argv[]) {
|
| |
+ }
|
| |
+ w = waitpid(cpid, &wstatus, 0);
|
| |
+ if (w == -1) {
|
| |
+ - fprintf(stderr, _("waitpid failed\n"));
|
| |
+ + fprintf(stderr, _("waitpid %d failed %s\n"), cpid, strerror(errno));
|
| |
+ cprc = EXIT_FAILURE;
|
| |
+ } else if (WIFEXITED(wstatus)) {
|
| |
+ cprc = WEXITSTATUS(wstatus);
|
| |
+ --
|
| |
+ 2.35.1
|
| |
+
|
| |