chantra / rpms / rpm

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