#3 merge upstream changes from rel 11 to rel 17
Merged 2 years ago by chantra. Opened 2 years ago by chantra.

@@ -0,0 +1,40 @@ 

+ From 48546ffc0a3f3eb15bfd439a19fc9722eaea592f Mon Sep 17 00:00:00 2001

+ From: Florian Festi <ffesti@redhat.com>

+ Date: Tue, 28 Jun 2022 12:50:54 +0200

+ Subject: [PATCH] Give warning on not supported hash for RSA keys

+ 

+ This can happen when old keys are used on systems that have disabled SHA1

+ e.g. for FIPS requirements.

+ 

+ This is less than ideal but there is currently no way to pass a meaningful

+ error code up to rpmtsImportPubkey. rpmPubkeyNew just returns a valid key

+ or NULL.

+ 

+ See rhbz#2069877

+ ---

+  rpmio/digest_openssl.c | 2 ++

+  1 file changed, 2 insertions(+)

+ 

+ diff --git a/rpmio/digest_openssl.c b/rpmio/digest_openssl.c

+ index a28a13acc..2ec5140f1 100644

+ --- a/rpmio/digest_openssl.c

+ +++ b/rpmio/digest_openssl.c

+ @@ -4,6 +4,7 @@

+  #include <openssl/rsa.h>

+  #include <openssl/dsa.h>

+  #include <rpm/rpmpgp.h>

+ +#include <rpm/rpmlog.h>

+  

+  #include "rpmio/digest.h"

+  

+ @@ -483,6 +484,7 @@ static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,

+  

+      ret = EVP_PKEY_CTX_set_signature_md(pkey_ctx, getEVPMD(hash_algo));

+      if (ret < 0) {

+ +	rpmlog(RPMLOG_WARNING, "Signature not supported. Hash algorithm %s not available.\n", pgpValString(PGPVAL_HASHALGO, hash_algo));

+          rc = 1;

+          goto done;

+      }

+ -- 

+ 2.36.1

+ 

The added file is too large to be shown here, see it at: 0001-RPM-with-Copy-on-Write.patch
@@ -0,0 +1,53 @@ 

+ From 845b5c3882b1eecb31d712b61a4e91fe0eb70712 Mon Sep 17 00:00:00 2001

+ From: Matthew Almond <malmond@fb.com>

+ Date: Sun, 31 Jan 2021 12:30:33 -0800

+ Subject: [PATCH 02/30] Remove use of bool type for consistency

+ 

+ ---

+  lib/fsm.c | 9 ++++-----

+  1 file changed, 4 insertions(+), 5 deletions(-)

+ 

+ diff --git a/lib/fsm.c b/lib/fsm.c

+ index 90193c749..feda3750c 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -8,7 +8,6 @@

+  

+  #include <utime.h>

+  #include <errno.h>

+ -#include <stdbool.h>

+  #if WITH_CAP

+  #include <sys/capability.h>

+  #endif

+ @@ -896,10 +895,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+  

+      Header h = rpmteHeader(te);

+      const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);

+ -    bool cpio = true;

+ +    int cpio = 1;

+  

+      if (payloadfmt && rstreq(payloadfmt, "clon")) {

+ -	cpio = false;

+ +	cpio = 0;

+      }

+  

+      /* transaction id used for temporary path suffix while installing */

+ @@ -927,13 +926,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+  	/* Run fsm file pre hook for all plugins */

+  	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,

+  				      fp->sb.st_mode, fp->action);

+ -	fp->plugin_contents = false;

+ +	fp->plugin_contents = 0;

+  	switch (rc) {

+  	case RPMRC_OK:

+  	    setFileState(fs, fx);

+  	    break;

+  	case RPMRC_PLUGIN_CONTENTS:

+ -	    fp->plugin_contents = true;

+ +	    fp->plugin_contents = 1;

+  	    // reduce reads on cpio to this value. Could be zero if

+  	    // this is from a hard link.

+  	    rc = RPMRC_OK;

+ -- 

+ 2.35.1

+ 

The added file is too large to be shown here, see it at: 0003-Match-formatting-style-of-existing-code.patch
@@ -0,0 +1,27 @@ 

+ From 15127592f8cc3221129f61b79319d88c7727bec3 Mon Sep 17 00:00:00 2001

+ From: Matthew Almond <malmond@fb.com>

+ Date: Sun, 31 Jan 2021 15:24:25 -0800

+ Subject: [PATCH 04/30] Fix printf formatting in reflink.c

+ 

+ There were some mismatches on field "sizes". This should eliminate the

+ error messages.

+ ---

+  plugins/reflink.c | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index 9eaa87094..513887604 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -316,7 +316,7 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,

+  		return RPMRC_FAIL;

+  	    }

+  	    rpmlog(RPMLOG_DEBUG,

+ -	           _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"),

+ +	           _("reflink: Reflinking %llu bytes at %llu to %s orig size=%ld, file=%lld\n"),

+  		   fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);

+  	    rc = ioctl(dst, FICLONERANGE, &fcr);

+  	    if (rc) {

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,73 @@ 

+ From fd4060dcfbe4127fb0d19f1878d0d8b9f34c7b9a Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Fri, 28 Jan 2022 08:33:16 -0800

+ Subject: [PATCH 05/30] [tests][rpm2extents] Add basic tests for rpm2extents

+ 

+ ---

+  tests/Makefile.am    |  1 +

+  tests/rpm2extents.at | 31 +++++++++++++++++++++++++++++++

+  tests/rpmtests.at    |  1 +

+  3 files changed, 33 insertions(+)

+  create mode 100644 tests/rpm2extents.at

+ 

+ diff --git a/tests/Makefile.am b/tests/Makefile.am

+ index f78e17c3e..fc8a24a5e 100644

+ --- a/tests/Makefile.am

+ +++ b/tests/Makefile.am

+ @@ -36,6 +36,7 @@ TESTSUITE_AT += rpmio.at

+  TESTSUITE_AT += rpmio.at

+  TESTSUITE_AT += rpmorder.at

+  TESTSUITE_AT += rpmvfylevel.at

+ +TESTSUITE_AT += rpm2extents.at

+  EXTRA_DIST += $(TESTSUITE_AT)

+  

+  ## testsuite data

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ new file mode 100644

+ index 000000000..f943b9af4

+ --- /dev/null

+ +++ b/tests/rpm2extents.at

+ @@ -0,0 +1,31 @@

+ +#    rpm2extents.at: Some very basic checks

+ +#

+ +#    Copyright (C) 2022  Manu Bretelle <chantr4@gmail.com>

+ +#

+ +#    This program is free software; you can redistribute it and/or modify

+ +#    it under the terms of the GNU General Public License as published by

+ +#    the Free Software Foundation; either version 2 of the License, or

+ +#    (at your option) any later version.

+ +#

+ +#    This program is distributed in the hope that it will be useful,

+ +#    but WITHOUT ANY WARRANTY; without even the implied warranty of

+ +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ +#    GNU General Public License for more details.

+ +#

+ +#    You should have received a copy of the GNU General Public License

+ +#    along with this program; if not, write to the Free Software

+ +#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

+ +

+ +AT_BANNER([rpm2extents tests])

+ +

+ +# ------------------------------

+ +

+ +# check that transcoder write magic at the end

+ +AT_SETUP([rpm2extents magic])

+ +AT_KEYWORDS([rpm2extents])

+ +AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | tail -c8],

+ +[0],

+ +[KWTSH100],

+ +[ignore])

+ +AT_CLEANUP

+ +

+ diff --git a/tests/rpmtests.at b/tests/rpmtests.at

+ index a1adab8e0..205fed6a3 100644

+ --- a/tests/rpmtests.at

+ +++ b/tests/rpmtests.at

+ @@ -21,3 +21,4 @@ m4_include([rpmreplace.at])

+  m4_include([rpmconfig.at])

+  m4_include([rpmconfig2.at])

+  m4_include([rpmconfig3.at])

+ +m4_include([rpm2extents.at])

+ -- 

+ 2.35.1

+ 

@@ -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

+ 

@@ -0,0 +1,282 @@ 

+ From a4755a5ed793ca439bb23b804ba7a8ab080ff110 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Fri, 28 Jan 2022 19:19:45 -0800

+ Subject: [PATCH 07/30] [rpm2extents] write RC and output to transcodedfile

+  metadata

+ 

+ create a new rpmcliVerifySignaturesFD function which takes a custom callback

+ that allows collecting a textual output of the validation, similar to what

+ rpmsign command would give.

+ ---

+  lib/rpmchecksig.c | 67 +++++++++++++++++++++++++++++++++++--------

+  lib/rpmcli.h      |  5 ++--

+  rpm2extents.c     | 73 +++++++++++++++++++++++++++++++----------------

+  3 files changed, 106 insertions(+), 39 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index 1a6b95323..fcdbb424f 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -260,6 +260,29 @@ exit:

+      return rc;

+  }

+  

+ +static int rpmpkgVerifySigsFD(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+ +			   FD_t fd, rpmsinfoCb cb, void *cbdata)

+ +{

+ +    char *msg = NULL;

+ +    int rc;

+ +    struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+ +

+ +    rc = rpmpkgRead(vs, fd, NULL, NULL, &msg);

+ +

+ +    if (rc)

+ +	goto exit;

+ +

+ +    rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata);

+ +

+ +exit:

+ +    if (rc && msg)

+ +	rpmlog(RPMLOG_ERR, "%s\n", msg);

+ +    rpmvsFree(vs);

+ +    free(msg);

+ +    return rc;

+ +}

+ +

+ +

+  /* Wrapper around rpmkVerifySigs to preserve API */

+  int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)

+  {

+ @@ -305,12 +328,38 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)

+      return res;

+  }

+  

+ -int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi)

+ +struct vfydatafd_s {

+ +    size_t len;

+ +    char msg[BUFSIZ];

+ +};

+ +

+ +

+ +static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata)

+  {

+ -    int res = 0;

+ +    struct vfydatafd_s *vd = cbdata;

+ +    char *vmsg, *msg;

+ +    size_t n;

+ +    size_t remainder = BUFSIZ - vd->len;

+ +

+ +    vmsg = rpmsinfoMsg(sinfo);

+ +    rasprintf(&msg, "    %s\n", vmsg);

+ +    n = rstrlcpy(vd->msg + vd->len, msg, remainder);

+ +    free(vmsg);

+ +    free(msg);

+ +    if(n <= remainder){

+ +	vd->len += n;

+ +    }

+ +    return 1;

+ +}

+ +

+ +

+ +int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg)

+ +{

+ +    rpmRC rc = RPMRC_FAIL;

+      rpmKeyring keyring = rpmtsGetKeyring(ts, 1);

+      rpmVSFlags vsflags = rpmtsVfyFlags(ts);

+      int vfylevel = rpmtsVfyLevel(ts);

+ +    struct vfydatafd_s vd = {.len = 0};

+  

+      vsflags |= rpmcliVSFlags;

+      if (rpmcliVfyLevelMask) {

+ @@ -318,19 +367,13 @@ int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi)

+  	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++;

+ +    if (!rpmpkgVerifySigsFD(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) {

+ +	rc = RPMRC_OK;

+      }

+ -

+ -    lseek(Fileno(fd), SEEK_SET, 0);

+ -    Fclose(fd);

+ +    *msg = strdup(vd.msg);

+      rpmsqPoll();

+  

+      rpmKeyringFree(keyring);

+ -    return res;

+ +    return rc;

+  }

+  

+ diff --git a/lib/rpmcli.h b/lib/rpmcli.h

+ index 52443e459..7ff48b37a 100644

+ --- a/lib/rpmcli.h

+ +++ b/lib/rpmcli.h

+ @@ -413,12 +413,13 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv);

+  

+  

+  /** \ingroup rpmcli

+ - * Verify package signatures

+ + * Verify package signatures.

+   * @param ts		transaction set

+   * @param fd		a file descriptor to verify

+ + * @param msg		a string containing textual information about the verification, similar to rpmcliVerifySignatures output.

+   * @return		0 on success

+   */

+ -int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd);

+ +int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd, char **msg);

+  

+  #ifdef __cplusplus

+  }

+ diff --git a/rpm2extents.c b/rpm2extents.c

+ index d8e582676..065a00306 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -133,16 +133,38 @@ exit:

+      return rc;

+  }

+  

+ -static rpmRC validator(FD_t fdi){

+ +static rpmRC validator(FD_t fdi, FD_t fdo){

+ +    int rc;

+ +    char *msg = NULL;

+      rpmts ts = rpmtsCreate();

+ +    size_t len;

+ +

+      rpmtsSetRootDir(ts, rpmcliRootDir);

+ -    /* rpmlog prints NOTICE to stdout */

+ -    // rpmlogSetFile(stderr);

+ -    if(rpmcliVerifySignaturesFD(ts, fdi)){

+ +    rc = rpmcliVerifySignaturesFD(ts, fdi, &msg);

+ +    if(rc){

+  	fprintf(stderr, _("Error validating package\n"));

+ -	return RPMRC_FAIL;

+      }

+ -    return RPMRC_OK;

+ +    len = sizeof(rc);

+ +    if (Fwrite(&rc, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write validator RC code %d\n"), rc);

+ +	goto exit;

+ +    }

+ +    size_t validator_len = msg ? strlen(msg) : 0;

+ +    len = sizeof(validator_len);

+ +    if (Fwrite(&validator_len, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write validator output length code %zd\n"), validator_len);

+ +	goto exit;

+ +    }

+ +    if (Fwrite(msg, validator_len, 1, fdo) != validator_len) {

+ +	fprintf(stderr, _("Unable to write validator output %s\n"), msg);

+ +	goto exit;

+ +    }

+ +

+ +exit:

+ +    if(msg) {

+ +	free(msg);

+ +    }

+ +    return rc ? RPMRC_FAIL : RPMRC_OK;

+  }

+  

+  static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+ @@ -173,7 +195,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      rpm_mode_t mode;

+      char *rpmio_flags = NULL, *zeros;

+      const unsigned char *digest;

+ -    rpm_loff_t pos, size, pad, digest_pos, validation_pos;

+ +    rpm_loff_t pos, size, pad, digest_pos, validation_pos, digest_table_pos;

+      uint32_t offset_ix = 0;

+      size_t len;

+      int next = 0;

+ @@ -278,6 +300,16 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset),

+  	  digestoffsetCmp);

+  

+ +    validation_pos = pos;

+ +    ssize_t validation_len = ufdCopy(validationi, fdo);

+ +    if (validation_len == -1) {

+ +	fprintf(stderr, _("validation output ufdCopy failed\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto exit;

+ +    }

+ +

+ +    digest_table_pos = validation_pos + validation_len;

+ +

+      len = sizeof(offset_ix);

+      if (Fwrite(&offset_ix, len, 1, fdo) != len) {

+  	fprintf(stderr, _("Unable to write length of table\n"));

+ @@ -304,7 +336,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	}

+      }

+      digest_pos = (

+ -	pos + sizeof(offset_ix) + sizeof(diglen) +

+ +	digest_table_pos + sizeof(offset_ix) + sizeof(diglen) +

+  	offset_ix * (diglen + sizeof(rpm_loff_t))

+      );

+  

+ @@ -315,14 +347,6 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	goto exit;

+      }

+  

+ -    validation_pos = digest_pos + digest_len;

+ -    ssize_t validation_len = ufdCopy(validationi, fdo);

+ -    if (validation_len == -1) {

+ -	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.

+ @@ -336,18 +360,18 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	goto exit;

+      }

+      zeros = _free(zeros);

+ -    if (Fwrite(&pos, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write offset of digest table\n"));

+ +    if (Fwrite(&validation_pos, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write offset of validation output\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ -    if (Fwrite(&digest_pos, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write offset of validation table\n"));

+ +    if (Fwrite(&digest_table_pos, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write offset of digest 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"));

+ +    if (Fwrite(&digest_pos, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write offset of validation table\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ @@ -431,11 +455,9 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	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);

+ +	rc = validator(fdi, fdo);

+  	if(rc != RPMRC_OK) {

+  	    fprintf(stderr, _("Validator failed\n"));

+  	}

+ @@ -486,6 +508,7 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	    close(rpmsignpipefd[0]);

+  	    close(rpmsignpipefd[1]);

+  

+ +	    rc = RPMRC_OK;

+  	    offt = ufdTee(fdi, fds, 2);

+  	    if(offt == -1){

+  		fprintf(stderr, _("Failed to tee RPM\n"));

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,116 @@ 

+ From c705a6287f8c7fb5e37dad0ac87257731a41fa69 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Sat, 29 Jan 2022 07:00:27 +0000

+ Subject: [PATCH 08/30] [rpm2extents] Add script to troubleshoot transcoded

+  file content This script is essentially dumping the metadata written at the

+  end of the transcoded files, it will also be used as part of the end-to-end

+  tests.

+ 

+ ---

+  scripts/rpm2extents_dump | 94 ++++++++++++++++++++++++++++++++++++++++

+  1 file changed, 94 insertions(+)

+  create mode 100755 scripts/rpm2extents_dump

+ 

+ diff --git a/scripts/rpm2extents_dump b/scripts/rpm2extents_dump

+ new file mode 100755

+ index 000000000..596a59a49

+ --- /dev/null

+ +++ b/scripts/rpm2extents_dump

+ @@ -0,0 +1,94 @@

+ +#!/usr/bin/env python3

+ +

+ +import argparse

+ +import binascii

+ +import os

+ +import struct

+ +import sys

+ +

+ +MAGIC_SIZE = 8

+ +MAGIC_STR = b'KWTSH100'

+ +

+ +POS_SIZE = 8

+ +

+ +def keep_position(func):

+ +    def wrapper(*args, **kwargs):

+ +        curr = args[0].tell()

+ +        res = func(*args, **kwargs)

+ +        f.seek(curr, os.SEEK_SET)

+ +        return res

+ +    return wrapper

+ +

+ +def read_validation_digest(f, validation_offset):

+ +	digests = []

+ +    # validation

+ +	f.seek(validation_offset, os.SEEK_SET)

+ +	val_content_len, val_digests_num = struct.unpack('=QI', f.read(8+4))

+ +	for i in range(val_digests_num):

+ +		algo_name_len, digest_len = struct.unpack('=II', f.read(8))

+ +		algo_name, digest = struct.unpack(f'{algo_name_len}s{digest_len}s', f.read(algo_name_len+digest_len))

+ +		digests.append((algo_name, binascii.hexlify(digest)))

+ +	return digests

+ +

+ +

+ +def read_digests_table(f, digest_offset):

+ +	digests = []

+ +    # validation

+ +	f.seek(digest_offset, os.SEEK_SET)

+ +	table_len, digest_len = struct.unpack('=II', f.read(8))

+ +

+ +	for i in range(table_len):

+ +		digest, pos = struct.unpack(f'{digest_len}sQ', f.read(digest_len + 8))

+ +		digests.append((pos, binascii.hexlify(digest)))

+ +	return digests

+ +

+ +def read_signature_output(f, signature_offset):

+ +    f.seek(signature_offset, os.SEEK_SET)

+ +    signature_rc, signature_output_len = struct.unpack('=IQ', f.read(12))

+ +    return signature_rc, f.read(signature_output_len)

+ +

+ +@keep_position

+ +def parse_file(f):

+ +	digests = []

+ +	pos_table_offset = f.seek(-8 - 3*POS_SIZE, os.SEEK_END)

+ +	signature_offset, digest_offset, validation_offset = struct.unpack('=QQQ', f.read(3*POS_SIZE))

+ +

+ +	validation_digests = read_validation_digest(f, validation_offset)

+ +	digests_table = read_digests_table(f, digest_offset)

+ +	signature_ouput = read_signature_output(f, signature_offset)

+ +

+ +	return validation_digests, digests_table, signature_ouput

+ +

+ +@keep_position

+ +def is_transcoded(f):

+ +    f.seek(-MAGIC_SIZE, os.SEEK_END)

+ +    magic = f.read(MAGIC_SIZE)

+ +    return magic == MAGIC_STR

+ +

+ +def arg_parse():

+ +    parser = argparse.ArgumentParser()

+ +    parser.add_argument('--dump-signature', action='store_true')

+ +    parser.add_argument('--dump-file-digest-table', action='store_true')

+ +    parser.add_argument('--dump-digests', action='store_true')

+ +    parser.add_argument('file')

+ +

+ +    return parser.parse_args()

+ +

+ +if __name__ == '__main__':

+ +    args = arg_parse()

+ +    f = open(args.file, 'rb')

+ +    if not is_transcoded(f):

+ +        sys.exit(1)

+ +

+ +    validation_digests, digests_table, signature_output = parse_file(f)

+ +    if(args.dump_file_digest_table):

+ +        for digest in digests_table:

+ +            print(f"FileDigest {hex(digest[0])}: {digest[1]}")

+ +

+ +    if(args.dump_digests):

+ +        for validation_digest in validation_digests:

+ +            print(f"HeaderDigest {validation_digest[0]} {validation_digest[1]}")

+ +

+ +    if(args.dump_signature):

+ +        print(f"RPMSignOutput RC {signature_output[0]}\nRPMSignOutput Content {signature_output[1].decode()}")

+ +

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,70 @@ 

+ From 44b86112136e4804eb606636cbcb4ae847cad773 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Sat, 29 Jan 2022 07:05:18 +0000

+ Subject: [PATCH 09/30] [rpm2extents] Add test verifying RC code and signature

+  validation text

+ 

+ When transcoding an RPM, the RPM signatures are being validated on the fly and the result from the signature validation is being written at the tail of the transcoded file.

+ This test check that we get the expected results and is based on the rpmsigdig.at test.

+ ---

+  Makefile.am          |  2 +-

+  tests/rpm2extents.at | 33 +++++++++++++++++++++++++++++++++

+  2 files changed, 34 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Makefile.am b/Makefile.am

+ index 288668819..96542c8c8 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -185,7 +185,7 @@ bin_PROGRAMS +=		rpmgraph

+  rpmgraph_SOURCES =	tools/rpmgraph.c

+  rpmgraph_LDADD =	lib/librpm.la rpmio/librpmio.la @WITH_POPT_LIB@

+  

+ -dist_bin_SCRIPTS =	scripts/gendiff

+ +dist_bin_SCRIPTS =	scripts/gendiff scripts/rpm2extents_dump

+  

+  rpmconfig_DATA = rpmrc

+  rpmrc: $(top_srcdir)/rpmrc.in

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index f943b9af4..baea987e4 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -29,3 +29,36 @@ AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rp

+  [ignore])

+  AT_CLEANUP

+  

+ +# Check that tailer writes checksig return code and content.

+ +#

+ +AT_SETUP([rpm2extents signature])

+ +AT_KEYWORDS([rpm2extents digest signature])

+ +AT_CHECK([

+ +RPMDB_INIT

+ +

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null

+ +rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm

+ +runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm

+ +rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm

+ +],

+ +[0],

+ +[RPMSignOutput RC 2

+ +RPMSignOutput Content     Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY

+ +    Header SHA256 digest: OK

+ +    Header SHA1 digest: OK

+ +    Payload SHA256 digest: OK

+ +    V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY

+ +    MD5 digest: OK

+ +

+ +RPMSignOutput RC 0

+ +RPMSignOutput Content     Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+ +    Header SHA256 digest: OK

+ +    Header SHA1 digest: OK

+ +    Payload SHA256 digest: OK

+ +    V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+ +    MD5 digest: OK

+ +

+ +],

+ +[])

+ +AT_CLEANUP

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,204 @@ 

+ From 7da1e826ccb08fdd404524146736b3f12a473e31 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Mon, 31 Jan 2022 14:42:25 -0800

+ Subject: [PATCH 10/30] [rpm2extents] Make rpmkeys support reading metadata

+  from transcoded footer

+ 

+ If the file is seekable and is a transcoded file, read signature validation from transcoded file tail metadata

+ ---

+  lib/rpmchecksig.c    | 112 ++++++++++++++++++++++++++++++++++++++++++-

+  tests/rpm2extents.at |  34 ++++++++++++-

+  2 files changed, 144 insertions(+), 2 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index fcdbb424f..6164d012c 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -24,6 +24,11 @@

+  

+  #include "debug.h"

+  

+ +/* magic value at end of file (64 bits) that indicates this is a transcoded

+ + * rpm.

+ + */

+ +#define MAGIC 3472329499408095051

+ +

+  static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)

+  {

+      char const * const pgpmark = "-----BEGIN PGP ";

+ @@ -220,6 +225,107 @@ exit:

+      return rc;

+  }

+  

+ +static rpmRC isTranscodedRpm(FD_t fd) {

+ +    rpmRC rc = RPMRC_NOTFOUND;

+ +    rpm_loff_t current;

+ +    uint64_t magic;

+ +    size_t len;

+ +

+ +    // If the file is not seekable, we cannot detect whether or not it is transcoded.

+ +    if(Fseek(fd, 0, SEEK_CUR) < 0) {

+ +        return RPMRC_FAIL;

+ +    }

+ +    current = Ftell(fd);

+ +

+ +    if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto exit;

+ +    }

+ +    len = sizeof(magic);

+ +    if (Fread(&magic, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto exit;

+ +    }

+ +    if (magic != MAGIC) {

+ +	rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n"));

+ +	rc = RPMRC_NOTFOUND;

+ +	goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+ +exit:

+ +    if (Fseek(fd, current, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n"));

+ +    }

+ +    return rc;

+ +}

+ +

+ +static int rpmpkgVerifySigsTranscoded(FD_t fd){

+ +    rpm_loff_t current;

+ +    uint64_t magic;

+ +    rpm_loff_t offset;

+ +    int32_t rc;

+ +    size_t len;

+ +    uint64_t content_len;

+ +    char *content = NULL;

+ +

+ +    current = Ftell(fd);

+ +

+ +    if(Fseek(fd, -(sizeof(magic) + 3 * sizeof(offset) ), SEEK_END) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: failed to seek for offset\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +

+ +    len = sizeof(offset);

+ +    if (Fread(&offset, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification offset\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +

+ +    if(Fseek(fd,  offset, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +    len = sizeof(rc);

+ +    if (Fread(&rc, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification RC\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +

+ +    len = sizeof(content_len);

+ +    if (Fread(&content_len, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content length\n"));

+ +	goto exit;

+ +    }

+ +

+ +    content = malloc(content_len + 1);

+ +    if(content == NULL) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to allocate memory to read signature content\n"));

+ +	goto exit;

+ +    }

+ +    content[content_len] = 0;

+ +    if (Fread(content, content_len, 1, fd) != content_len) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content\n"));

+ +	goto exit;

+ +    }

+ +

+ +    rpmlog(RPMLOG_NOTICE, "%s", content);

+ +exit:

+ +    if(content){

+ +	free(content);

+ +    }

+ +    if (Fseek(fd, current, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: unable to seek back to original location\n"));

+ +    }

+ +    return rc;

+ +

+ +}

+ +

+  static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+  			   FD_t fd, const char *fn)

+  {

+ @@ -229,10 +335,14 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+  			    .verbose = rpmIsVerbose(),

+      };

+      int rc;

+ -    struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+  

+      rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : "");

+  

+ +    if(isTranscodedRpm(fd) == RPMRC_OK){

+ +	return rpmpkgVerifySigsTranscoded(fd);

+ +    }

+ +    struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+ +

+      rc = rpmpkgRead(vs, fd, NULL, NULL, &msg);

+  

+      if (rc)

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index baea987e4..18accfc75 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -29,7 +29,7 @@ AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rp

+  [ignore])

+  AT_CLEANUP

+  

+ -# Check that tailer writes checksig return code and content.

+ +# Check that transcoder writes checksig return code and content.

+  #

+  AT_SETUP([rpm2extents signature])

+  AT_KEYWORDS([rpm2extents digest signature])

+ @@ -62,3 +62,35 @@ RPMSignOutput Content     Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+  ],

+  [])

+  AT_CLEANUP

+ +

+ +AT_SETUP([rpm2extents signature verification])

+ +AT_KEYWORDS([rpm2extents digest signature])

+ +AT_CHECK([

+ +RPMDB_INIT

+ +

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null

+ +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?

+ +runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm

+ +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?

+ +],

+ +[0],

+ +[/tmp/hello-2.0-1.x86_64-signed.rpm:

+ +    Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY

+ +    Header SHA256 digest: OK

+ +    Header SHA1 digest: OK

+ +    Payload SHA256 digest: OK

+ +    V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY

+ +    MD5 digest: OK

+ +1

+ +/tmp/hello-2.0-1.x86_64-signed.rpm:

+ +    Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+ +    Header SHA256 digest: OK

+ +    Header SHA1 digest: OK

+ +    Payload SHA256 digest: OK

+ +    V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+ +    MD5 digest: OK

+ +0

+ +],

+ +[])

+ +AT_CLEANUP

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,389 @@ 

+ From 86776bf17f1644c76fdf8b87042645cf77bd3873 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Wed, 2 Feb 2022 13:34:28 -0800

+ Subject: [PATCH 11/30] [rpm2extents] Perform digest computation within the

+  validator

+ 

+ The validator calls `rpmcliVerifySignaturesFD` which under the hood

+ performs `Fread`. Digests are computed/updated for each `Fread`.

+ 

+ This diffs takes advantage of that by initializing the digest before

+ calling `rpmcliVerifySignaturesFD`. Once `rpmcliVerifySignaturesFD` as

+ returned and the file has been read, the digests are available.

+ 

+ This saves us from spawning a `digestor` process, as well as performing

+ an extra file read within it.

+ ---

+  rpm2extents.c | 234 +++++++++++++++++++++++---------------------------

+  1 file changed, 106 insertions(+), 128 deletions(-)

+ 

+ diff --git a/rpm2extents.c b/rpm2extents.c

+ index 065a00306..e316a2834 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -64,38 +64,37 @@ static struct poptOption optionsTable[] = {

+  };

+  

+  

+ -static int digestor(

+ +static void FDDigestInit(FD_t fdi, uint8_t algos[], uint32_t algos_len){

+ +    int algo;

+ +

+ +    for (algo = 0; algo < algos_len; algo++) {

+ +	fdInitDigest(fdi, algos[algo], 0);

+ +    }

+ +}

+ +

+ +static int FDWriteDigests(

+      FD_t fdi,

+      FD_t fdo,

+ -    FD_t validationo,

+      uint8_t algos[],

+ -    uint32_t algos_len

+ -)

+ +    uint32_t algos_len)

+  {

+ -    ssize_t fdilength;

+      const char *filedigest, *algo_name;

+      size_t filedigest_len, len;

+      uint32_t algo_name_len, algo_digest_len;

+      int algo;

+      rpmRC rc = RPMRC_FAIL;

+  

+ -    for (algo = 0; algo < algos_len; algo++) {

+ -	fdInitDigest(fdi, algos[algo], 0);

+ -    }

+ -    fdilength = ufdCopy(fdi, fdo);

+ -    if (fdilength == -1) {

+ -	fprintf(stderr, _("digest cat failed\n"));

+ -	goto exit;

+ -    }

+ +    ssize_t fdilength = fdOp(fdi, FDSTAT_READ)->bytes;

+  

+      len = sizeof(fdilength);

+ -    if (Fwrite(&fdilength, len, 1, validationo) != len) {

+ +    if (Fwrite(&fdilength, len, 1, fdo) != len) {

+  	fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);

+  	goto exit;

+      }

+      len = sizeof(algos_len);

+ -    if (Fwrite(&algos_len, len, 1, validationo) != len) {

+ -	fprintf(stderr, _("Unable to write number of validation digests\n"));

+ +    if (Fwrite(&algos_len, len, 1, fdo) != len) {

+ +	algo_digest_len = (uint32_t)filedigest_len;

+ +	fprintf(stderr, _("Unable to write number of digests\n"));

+  	goto exit;

+      }

+      for (algo = 0; algo < algos_len; algo++) {

+ @@ -106,24 +105,24 @@ static int digestor(

+  	algo_digest_len = (uint32_t)filedigest_len;

+  

+  	len = sizeof(algo_name_len);

+ -	if (Fwrite(&algo_name_len, len, 1, validationo) != len) {

+ +	if (Fwrite(&algo_name_len, len, 1, fdo) != len) {

+  	    fprintf(stderr,

+ -		    _("Unable to write validation algo name length\n"));

+ +		    _("Unable to write digest algo name length\n"));

+  	    goto exit;

+  	}

+  	len = sizeof(algo_digest_len);

+ -	if (Fwrite(&algo_digest_len, len, 1, validationo) != len) {

+ +	if (Fwrite(&algo_digest_len, len, 1, fdo) != len) {

+  	    fprintf(stderr,

+ -		    _("Unable to write number of bytes for validation digest\n"));

+ +		    _("Unable to write number of bytes for digest\n"));

+  	     goto exit;

+  	}

+ -	if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) {

+ -	    fprintf(stderr, _("Unable to write validation algo name\n"));

+ +	if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) {

+ +	    fprintf(stderr, _("Unable to write digest algo name\n"));

+  	    goto exit;

+  	}

+ -	if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) {

+ +	if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) {

+  	    fprintf(stderr,

+ -		    _("Unable to write validation digest value %u, %zu\n"),

+ +		    _("Unable to write digest value %u, %zu\n"),

+  		    algo_digest_len, filedigest_len);

+  	    goto exit;

+  	}

+ @@ -133,38 +132,66 @@ exit:

+      return rc;

+  }

+  

+ -static rpmRC validator(FD_t fdi, FD_t fdo){

+ -    int rc;

+ -    char *msg = NULL;

+ -    rpmts ts = rpmtsCreate();

+ +static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) {

+      size_t len;

+ +    rpmRC rc = RPMRC_FAIL;

+  

+ -    rpmtsSetRootDir(ts, rpmcliRootDir);

+ -    rc = rpmcliVerifySignaturesFD(ts, fdi, &msg);

+ -    if(rc){

+ -	fprintf(stderr, _("Error validating package\n"));

+ +    if(rpmvsrc){

+ +	fprintf(stderr, _("Error verifying package signatures\n"));

+      }

+ -    len = sizeof(rc);

+ -    if (Fwrite(&rc, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write validator RC code %d\n"), rc);

+ +

+ +    len = sizeof(rpmvsrc);

+ +    if (Fwrite(&rpmvsrc, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write signature verification RC code %d\n"), rpmvsrc);

+ +	goto exit;

+ +    }

+ +    size_t content_len = msg ? strlen(msg) : 0;

+ +    len = sizeof(content_len);

+ +    if (Fwrite(&content_len, len, 1, fdo) != len) {

+ +	fprintf(stderr, _("Unable to write signature verification output length %zd\n"), content_len);

+  	goto exit;

+      }

+ -    size_t validator_len = msg ? strlen(msg) : 0;

+ -    len = sizeof(validator_len);

+ -    if (Fwrite(&validator_len, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write validator output length code %zd\n"), validator_len);

+ +    if (Fwrite(msg, content_len, 1, fdo) != content_len) {

+ +	fprintf(stderr, _("Unable to write signature verification output %s\n"), msg);

+  	goto exit;

+      }

+ -    if (Fwrite(msg, validator_len, 1, fdo) != validator_len) {

+ -	fprintf(stderr, _("Unable to write validator output %s\n"), msg);

+ +

+ +    rc = RPMRC_OK;

+ +exit:

+ +

+ +    return rc;

+ +}

+ +

+ +static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo,

+ +	uint8_t algos[],

+ +	uint32_t algos_len){

+ +    int rpmvsrc;

+ +    rpmRC rc = RPMRC_FAIL;

+ +    char *msg = NULL;

+ +    rpmts ts = rpmtsCreate();

+ +

+ +    rpmtsSetRootDir(ts, rpmcliRootDir);

+ +

+ +    FDDigestInit(fdi, algos, algos_len);

+ +

+ +    rpmvsrc = rpmcliVerifySignaturesFD(ts, fdi, &msg);

+ +

+ +    // Write result of digest computation

+ +    if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) {

+ +	fprintf(stderr, _("Failed to write digests"));

+  	goto exit;

+      }

+  

+ +    // Write result of signature validation.

+ +    if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) {

+ +	goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+  exit:

+      if(msg) {

+  	free(msg);

+      }

+ -    return rc ? RPMRC_FAIL : RPMRC_OK;

+ +    return rc;

+  }

+  

+  static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+ @@ -422,12 +449,16 @@ static off_t ufdTee(FD_t sfd, FD_t *fds, int len)

+      return total;

+  }

+  

+ -static int teeRpm(FD_t fdi, FD_t digestori) {

+ -    rpmRC rc;

+ +static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {

+ +    rpmRC rc = RPMRC_FAIL;

+      off_t offt = -1;

+ +    // tee-ed stdin

+      int processorpipefd[2];

+      int validatorpipefd[2];

+ -    int rpmsignpipefd[2];

+ +    // metadata

+ +    int meta_digestpipefd[2];

+ +    int meta_rpmsignpipefd[2];

+ +

+      pid_t cpids[2], w;

+      int wstatus;

+      FD_t fds[2];

+ @@ -442,8 +473,13 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	return RPMRC_FAIL;

+      }

+  

+ -    if (pipe(rpmsignpipefd) == -1) {

+ -	fprintf(stderr, _("Validator pipe failure\n"));

+ +    if (pipe(meta_digestpipefd) == -1) {

+ +	fprintf(stderr, _("Meta digest pipe failure\n"));

+ +	return RPMRC_FAIL;

+ +    }

+ +

+ +    if (pipe(meta_rpmsignpipefd) == -1) {

+ +	fprintf(stderr, _("Meta rpm signature pipe failure\n"));

+  	return RPMRC_FAIL;

+      }

+  

+ @@ -453,16 +489,20 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	close(processorpipefd[0]);

+  	close(processorpipefd[1]);

+  	close(validatorpipefd[1]);

+ -	close(rpmsignpipefd[0]);

+ +	close(meta_digestpipefd[0]);

+ +	close(meta_rpmsignpipefd[0]);

+  	FD_t fdi = fdDup(validatorpipefd[0]);

+ -	FD_t fdo = fdDup(rpmsignpipefd[1]);

+ -	close(rpmsignpipefd[1]);

+ -	rc = validator(fdi, fdo);

+ +	FD_t digesto = fdDup(meta_digestpipefd[1]);

+ +	FD_t sigo = fdDup(meta_rpmsignpipefd[1]);

+ +	close(meta_digestpipefd[1]);

+ +	close(meta_rpmsignpipefd[1]);

+ +	rc = validator(fdi, digesto, sigo, algos, algos_len);

+  	if(rc != RPMRC_OK) {

+  	    fprintf(stderr, _("Validator failed\n"));

+  	}

+  	Fclose(fdi);

+ -	Fclose(fdo);

+ +	Fclose(digesto);

+ +	Fclose(sigo);

+  	if (rc != RPMRC_OK) {

+  	    exit(EXIT_FAILURE);

+  	}

+ @@ -475,18 +515,21 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	    close(validatorpipefd[0]);

+  	    close(validatorpipefd[1]);

+  	    close(processorpipefd[1]);

+ -	    close(rpmsignpipefd[1]);

+ +	    close(meta_digestpipefd[1]);

+ +	    close(meta_rpmsignpipefd[1]);

+  	    FD_t fdi = fdDup(processorpipefd[0]);

+  	    close(processorpipefd[0]);

+ -	    FD_t validatori = fdDup(rpmsignpipefd[0]);

+ -	    close(rpmsignpipefd[0]);

+ +	    FD_t sigi = fdDup(meta_rpmsignpipefd[0]);

+ +	    close(meta_rpmsignpipefd[0]);

+ +	    FD_t digestori = fdDup(meta_digestpipefd[0]);

+ +	    close(meta_digestpipefd[0]);

+  

+ -	    rc = process_package(fdi, digestori, validatori);

+ +	    rc = process_package(fdi, digestori, sigi);

+  	    if(rc != RPMRC_OK) {

+  		fprintf(stderr, _("Validator failed\n"));

+  	    }

+  	    Fclose(digestori);

+ -	    Fclose(validatori);

+ +	    Fclose(sigi);

+  	    /* fdi is normally closed through the stacked file gzdi in the

+  	     * function

+  	     */

+ @@ -505,8 +548,10 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  	    fds[1] = fdDup(validatorpipefd[1]);

+  	    close(validatorpipefd[1]);

+  	    close(processorpipefd[1]);

+ -	    close(rpmsignpipefd[0]);

+ -	    close(rpmsignpipefd[1]);

+ +	    close(meta_digestpipefd[0]);

+ +	    close(meta_digestpipefd[1]);

+ +	    close(meta_rpmsignpipefd[0]);

+ +	    close(meta_rpmsignpipefd[1]);

+  

+  	    rc = RPMRC_OK;

+  	    offt = ufdTee(fdi, fds, 2);

+ @@ -534,16 +579,10 @@ static int teeRpm(FD_t fdi, FD_t digestori) {

+  

+  int main(int argc, char *argv[]) {

+      rpmRC rc;

+ -    int cprc = 0;

+      poptContext optCon = NULL;

+      const char **args = NULL;

+      int nb_algos = 0;

+  

+ -    int mainpipefd[2];

+ -    int metapipefd[2];

+ -    pid_t cpid, w;

+ -    int wstatus;

+ -

+      xsetprogname(argv[0]);	/* Portability call -- see system.h */

+      rpmReadConfigFiles(NULL, NULL);

+      optCon = rpmcliInit(argc, argv, optionsTable);

+ @@ -570,69 +609,8 @@ int main(int argc, char *argv[]) {

+  	}

+      }

+  

+ -    if (pipe(mainpipefd) == -1) {

+ -	fprintf(stderr, _("Main pipe failure\n"));

+ -	exit(EXIT_FAILURE);

+ -    }

+ -    if (pipe(metapipefd) == -1) {

+ -	fprintf(stderr, _("Meta pipe failure\n"));

+ -	exit(EXIT_FAILURE);

+ -    }

+ -

+ -    cpid = fork();

+ -    if (cpid == 0) {

+ -	/* child: digestor */

+ -	close(mainpipefd[0]);

+ -	close(metapipefd[0]);

+ -	FD_t fdi = fdDup(STDIN_FILENO);

+ -	FD_t fdo = fdDup(mainpipefd[1]);

+ -	FD_t validationo = fdDup(metapipefd[1]);

+ -	rc = digestor(fdi, fdo, validationo, algos, nb_algos);

+ -	Fclose(validationo);

+ -	Fclose(fdo);

+ -	Fclose(fdi);

+ -    } else {

+ -	/* parent: main program */

+ -	close(mainpipefd[1]);

+ -	close(metapipefd[1]);

+ -	FD_t fdi = fdDup(mainpipefd[0]);

+ -	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) {

+ -		fprintf(stderr,

+ -		        _("Failed to kill digest process when main process failed: %s\n"),

+ -			strerror(errno));

+ -	    }

+ -	}

+ -	w = waitpid(cpid, &wstatus, 0);

+ -	if (w == -1) {

+ -	    fprintf(stderr, _("waitpid %d failed %s\n"), cpid, strerror(errno));

+ -	    cprc = EXIT_FAILURE;

+ -	} else if (WIFEXITED(wstatus)) {

+ -	    cprc = WEXITSTATUS(wstatus);

+ -	    if (cprc != 0) {

+ -		fprintf(stderr,

+ -			_("Digest process non-zero exit code %d\n"),

+ -			cprc);

+ -	    }

+ -	} else if (WIFSIGNALED(wstatus)) {

+ -	    fprintf(stderr,

+ -		    _("Digest process was terminated with a signal: %d\n"),

+ -		    WTERMSIG(wstatus));

+ -	    cprc = EXIT_FAILURE;

+ -	} else {

+ -	    /* Don't think this can happen, but covering all bases */

+ -	    fprintf(stderr, _("Unhandled circumstance in waitpid\n"));

+ -	    cprc = EXIT_FAILURE;

+ -	}

+ -	if (cprc != EXIT_SUCCESS) {

+ -	    rc = RPMRC_FAIL;

+ -	}

+ -    }

+ +    FD_t fdi = fdDup(STDIN_FILENO);

+ +    rc = teeRpm(fdi, algos, nb_algos);

+      if (rc != RPMRC_OK) {

+  	/* translate rpmRC into generic failure return code. */

+  	return EXIT_FAILURE;

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,299 @@ 

+ From ecab80b80e3917d3acf0f909c9cc84691a207fc0 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Thu, 3 Feb 2022 21:09:05 -0800

+ Subject: [PATCH 12/30] [rpmextents] Create an internal library to make

+  rpmextents file manipulation easier and less duplicated

+ 

+ ---

+  lib/Makefile.am           |  3 ++-

+  lib/rpmchecksig.c         | 42 +---------------------------------

+  lib/rpmextents.c          | 46 +++++++++++++++++++++++++++++++++++++

+  lib/rpmextents_internal.h | 22 ++++++++++++++++++

+  plugins/reflink.c         | 48 +++++++++++++--------------------------

+  rpm2extents.c             |  8 ++-----

+  6 files changed, 89 insertions(+), 80 deletions(-)

+  create mode 100644 lib/rpmextents.c

+  create mode 100644 lib/rpmextents_internal.h

+ 

+ diff --git a/lib/Makefile.am b/lib/Makefile.am

+ index 5a1b6ca9b..2f1b3597f 100644

+ --- a/lib/Makefile.am

+ +++ b/lib/Makefile.am

+ @@ -40,7 +40,8 @@ librpm_la_SOURCES = \

+  	rpmscript.h rpmscript.c \

+  	rpmchroot.c rpmchroot.h \

+  	rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \

+ -	rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h

+ +	rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h \

+ +	rpmextents.c rpmextents_internal.h

+  

+  librpm_la_LDFLAGS = -version-info $(rpm_version_info)

+  

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index 6164d012c..dc1726a18 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -20,15 +20,11 @@

+  #include "rpmio/rpmio_internal.h" 	/* fdSetBundle() */

+  #include "lib/rpmlead.h"

+  #include "lib/header_internal.h"

+ +#include "lib/rpmextents_internal.h"

+  #include "lib/rpmvs.h"

+  

+  #include "debug.h"

+  

+ -/* magic value at end of file (64 bits) that indicates this is a transcoded

+ - * rpm.

+ - */

+ -#define MAGIC 3472329499408095051

+ -

+  static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen)

+  {

+      char const * const pgpmark = "-----BEGIN PGP ";

+ @@ -225,42 +221,6 @@ exit:

+      return rc;

+  }

+  

+ -static rpmRC isTranscodedRpm(FD_t fd) {

+ -    rpmRC rc = RPMRC_NOTFOUND;

+ -    rpm_loff_t current;

+ -    uint64_t magic;

+ -    size_t len;

+ -

+ -    // If the file is not seekable, we cannot detect whether or not it is transcoded.

+ -    if(Fseek(fd, 0, SEEK_CUR) < 0) {

+ -        return RPMRC_FAIL;

+ -    }

+ -    current = Ftell(fd);

+ -

+ -    if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    len = sizeof(magic);

+ -    if (Fread(&magic, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    if (magic != MAGIC) {

+ -	rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n"));

+ -	rc = RPMRC_NOTFOUND;

+ -	goto exit;

+ -    }

+ -    rc = RPMRC_OK;

+ -exit:

+ -    if (Fseek(fd, current, SEEK_SET) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n"));

+ -    }

+ -    return rc;

+ -}

+ -

+  static int rpmpkgVerifySigsTranscoded(FD_t fd){

+      rpm_loff_t current;

+      uint64_t magic;

+ diff --git a/lib/rpmextents.c b/lib/rpmextents.c

+ new file mode 100644

+ index 000000000..015277751

+ --- /dev/null

+ +++ b/lib/rpmextents.c

+ @@ -0,0 +1,46 @@

+ +

+ +#include "system.h"

+ +

+ +#include <rpm/rpmlog.h>

+ +#include <rpm/rpmio.h>

+ +

+ +#include "lib/rpmextents_internal.h"

+ +

+ +rpmRC isTranscodedRpm(FD_t fd) {

+ +    rpmRC rc = RPMRC_NOTFOUND;

+ +    rpm_loff_t current;

+ +    extents_magic_t magic;

+ +    size_t len;

+ +

+ +    // If the file is not seekable, we cannot detect whether or not it is transcoded.

+ +    if(Fseek(fd, 0, SEEK_CUR) < 0) {

+ +        return RPMRC_FAIL;

+ +    }

+ +    current = Ftell(fd);

+ +

+ +    if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto exit;

+ +    }

+ +    len = sizeof(magic);

+ +    if (Fread(&magic, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto exit;

+ +    }

+ +    if (magic != EXTENTS_MAGIC) {

+ +	rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n"));

+ +	rc = RPMRC_NOTFOUND;

+ +	goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+ +exit:

+ +    if (Fseek(fd, current, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n"));

+ +	rc = RPMRC_FAIL;

+ +    }

+ +    return rc;

+ +}

+ +

+ +

+ diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h

+ new file mode 100644

+ index 000000000..57cecfc31

+ --- /dev/null

+ +++ b/lib/rpmextents_internal.h

+ @@ -0,0 +1,22 @@

+ +#ifndef _RPMEXTENTS_INTERNAL_H

+ +#define _RPMEXTENTS_INTERNAL_H

+ +

+ +#ifdef __cplusplus

+ +extern "C" {

+ +#endif

+ +

+ +#include <stdint.h>

+ +

+ +/* magic value at end of file (64 bits) that indicates this is a transcoded

+ + * rpm.

+ + */

+ +#define EXTENTS_MAGIC 3472329499408095051

+ +

+ +typedef uint64_t extents_magic_t;

+ +

+ +rpmRC isTranscodedRpm(FD_t fd);

+ +

+ +#ifdef __cplusplus

+ +}

+ +#endif

+ +#endif

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index 513887604..ec575f55e 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -13,6 +13,7 @@

+  #include <rpm/rpmlog.h>

+  #include "lib/rpmlib.h"

+  #include "lib/rpmplugin.h"

+ +#include "lib/rpmextents_internal.h"

+  #include "lib/rpmte_internal.h"

+  #include <rpm/rpmfileutil.h>

+  #include "rpmio/rpmio_internal.h"

+ @@ -40,11 +41,6 @@

+  

+  #define BUFFER_SIZE (1024 * 128)

+  

+ -/* magic value at end of file (64 bits) that indicates this is a transcoded

+ - * rpm.

+ - */

+ -#define MAGIC 3472329499408095051

+ -

+  struct reflink_state_s {

+      /* Stuff that's used across rpms */

+      long fundamental_block_size;

+ @@ -96,40 +92,28 @@ static void reflink_cleanup(rpmPlugin plugin) {

+  }

+  

+  static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {

+ +    rpmRC rc;

+ +    size_t len;

+ +

+      reflink_state state = rpmPluginGetData(plugin);

+      state->fd = rpmteFd(te);

+      if (state->fd == 0) {

+  	rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));

+  	return RPMRC_OK;

+      }

+ +

+      rpm_loff_t current = Ftell(state->fd);

+ -    uint64_t magic;

+ -    if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));

+ -	if (Fseek(state->fd, current, SEEK_SET) < 0) {

+ -	    /* yes this gets a bit repetitive */

+ -	    rpmlog(RPMLOG_ERR,

+ -		 _("reflink: unable to seek back to original location\n"));

+ -	}

+ -	return RPMRC_FAIL;

+ -    }

+ -    size_t len = sizeof(magic);

+ -    if (Fread(&magic, len, 1, state->fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));

+ -	if (Fseek(state->fd, current, SEEK_SET) < 0) {

+ -	    rpmlog(RPMLOG_ERR,

+ -		   _("reflink: unable to seek back to original location\n"));

+ -	}

+ -	return RPMRC_FAIL;

+ -    }

+ -    if (magic != MAGIC) {

+ -	rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));

+ -	if (Fseek(state->fd, current, SEEK_SET) < 0) {

+ -	    rpmlog(RPMLOG_ERR,

+ -		   _("reflink: unable to seek back to original location\n"));

+ +    rc = isTranscodedRpm(state->fd);

+ +

+ +    switch(rc){

+ +	// Fail to parse the file, fail the plugin.

+ +	case RPMRC_FAIL:

+  	    return RPMRC_FAIL;

+ -	}

+ -	return RPMRC_OK;

+ +	// This is not a transcoded file, do nothing.

+ +	case RPMRC_NOTFOUND:

+ +	    return RPMRC_OK;

+ +	default:

+ +	    break;

+      }

+      rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));

+      Header h = rpmteHeader(te);

+ @@ -140,7 +124,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {

+      headerFree(h);

+      state->files = rpmteFiles(te);

+      /* tail of file contains offset_table, offset_checksums then magic */

+ -    if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) {

+ +    if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) {

+  	rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"),

+  	       state->fd);

+  	return RPMRC_FAIL;

+ diff --git a/rpm2extents.c b/rpm2extents.c

+ index e316a2834..a326e3857 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -15,6 +15,7 @@

+  #include "lib/rpmts.h"

+  #include "lib/signature.h"

+  #include "lib/header_internal.h"

+ +#include "lib/rpmextents_internal.h"

+  #include "rpmio/rpmio_internal.h"

+  

+  #include <unistd.h>

+ @@ -37,11 +38,6 @@

+  #include "lib/rpmhash.H"

+  #include "lib/rpmhash.C"

+  

+ -/* magic value at end of file (64 bits) that indicates this is a transcoded

+ - * rpm.

+ - */

+ -#define MAGIC 3472329499408095051

+ -

+  struct digestoffset {

+      const unsigned char * digest;

+      rpm_loff_t pos;

+ @@ -402,7 +398,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ -    uint64_t magic = MAGIC;

+ +    extents_magic_t magic = EXTENTS_MAGIC;

+      len = sizeof(magic);

+      if (Fwrite(&magic, len, 1, fdo) != len) {

+  	fprintf(stderr, _("Unable to write magic\n"));

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,109 @@ 

+ From 5c97d7f83f56015d6a37934cee4e55ed8d747890 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 16:57:25 -0800

+ Subject: [PATCH 13/30] [plugin] add `plugin_fsm_file_install_func` plugin hook

+ 

+ This hook is to be called when installing individual files from the RPM.

+ ---

+  lib/rpmplugin.h  |  5 +++++

+  lib/rpmplugins.c | 37 +++++++++++++++++++++++++++++++++++++

+  lib/rpmplugins.h | 15 +++++++++++++++

+  3 files changed, 57 insertions(+)

+ 

+ diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h

+ index fd81aec8d..877db81f3 100644

+ --- a/lib/rpmplugin.h

+ +++ b/lib/rpmplugin.h

+ @@ -60,6 +60,10 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,

+  					      const char* path,

+  					      const char *dest,

+  					      mode_t file_mode, rpmFsmOp op);

+ +typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi,

+ +					      const char* path,

+ +					      mode_t file_mode, rpmFsmOp op);

+ +

+  

+  typedef struct rpmPluginHooks_s * rpmPluginHooks;

+  struct rpmPluginHooks_s {

+ @@ -80,6 +84,7 @@ struct rpmPluginHooks_s {

+      plugin_fsm_file_pre_func		fsm_file_pre;

+      plugin_fsm_file_post_func		fsm_file_post;

+      plugin_fsm_file_prepare_func	fsm_file_prepare;

+ +    plugin_fsm_file_install_func	fsm_file_install;

+  };

+  

+  #ifdef __cplusplus

+ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c

+ index 3da3097af..850a025a0 100644

+ --- a/lib/rpmplugins.c

+ +++ b/lib/rpmplugins.c

+ @@ -421,3 +421,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

+  

+      return rc;

+  }

+ +

+ +rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,

+ +				   const char *path, mode_t file_mode,

+ +				   rpmFsmOp op)

+ +{

+ +    plugin_fsm_file_install_func hookFunc;

+ +    int i;

+ +    rpmRC rc = RPMRC_OK;

+ +    rpmRC hook_rc;

+ +

+ +    for (i = 0; i < plugins->count; i++) {

+ +	rpmPlugin plugin = plugins->plugins[i];

+ +	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_install);

+ +	if (hookFunc) {

+ +	    hook_rc = hookFunc(plugin, fi, path, file_mode, op);

+ +	    if (hook_rc == RPMRC_FAIL) {

+ +		rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_install failed\n", plugin->name);

+ +		rc = RPMRC_FAIL;

+ +	    } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {

+ +		if (rc == RPMRC_PLUGIN_CONTENTS) {

+ +		    /* Another plugin already said it'd handle contents. It's

+ +		     * undefined how these would combine, so treat this as a

+ +		     * failure condition.

+ +		    */

+ +		    rc = RPMRC_FAIL;

+ +		} else {

+ +		    /* Plugin will handle content */

+ +		    rc = RPMRC_PLUGIN_CONTENTS;

+ +		}

+ +	    }

+ +	}

+ +    }

+ +

+ +    return rc;

+ +}

+ +

+ +

+ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h

+ index 39762c376..5365cf698 100644

+ --- a/lib/rpmplugins.h

+ +++ b/lib/rpmplugins.h

+ @@ -167,6 +167,21 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

+                                     const char *path, const char *dest,

+                                     mode_t mode, rpmFsmOp op);

+  

+ +/** \ingroup rpmplugins

+ + * Call the fsm file install plugin hook

+ + * @param plugins	plugins structure

+ + * @param fi		file info iterator (or NULL)

+ + * @param path		file object path

+ + * @param file_mode	file object mode

+ + * @param op		file operation + associated flags

+ + * @return		RPMRC_OK on success, RPMRC_FAIL otherwise

+ + */

+ +RPM_GNUC_INTERNAL

+ +rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,

+ +				   const char* path, mode_t file_mode,

+ +				   rpmFsmOp op);

+ +

+ +

+  #ifdef __cplusplus

+  }

+  #endif

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,79 @@ 

+ From ad46eb4132cbd2c4ee23686a1c52f2fc57afffc5 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 17:06:55 -0800

+ Subject: [PATCH 14/30] [fsm] Call new `rpmpluginsCallFsmFileInstall` in

+  `rpmPackageFilesInstall`

+ 

+ Call `rpmpluginsCallFsmFileInstall` for every files to be installed by

+ `rpmPackageFilesInstall`, this allows for plugin such as reflink to

+ write (reflink) a file and make sure the parent directories have already

+ been created.

+ If this was done in `rpmpluginsCallFsmFilePre`, the directories may be

+ missing, which makes file installation fail.

+ ---

+  lib/fsm.c | 29 +++++++++--------------------

+  1 file changed, 9 insertions(+), 20 deletions(-)

+ 

+ diff --git a/lib/fsm.c b/lib/fsm.c

+ index feda3750c..711f553d3 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -53,7 +53,6 @@ struct filedata_s {

+      int stage;

+      int setmeta;

+      int skip;

+ -    int plugin_contents;

+      rpmFileAction action;

+      const char *suffix;

+      char *fpath;

+ @@ -921,23 +920,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+  	/* Remap file perms, owner, and group. */

+  	rc = rpmfiStat(fi, 1, &fp->sb);

+  

+ +	setFileState(fs, fx);

+  	fsmDebug(fp->fpath, fp->action, &fp->sb);

+  

+  	/* Run fsm file pre hook for all plugins */

+  	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,

+  				      fp->sb.st_mode, fp->action);

+ -	fp->plugin_contents = 0;

+ -	switch (rc) {

+ -	case RPMRC_OK:

+ -	    setFileState(fs, fx);

+ -	    break;

+ -	case RPMRC_PLUGIN_CONTENTS:

+ -	    fp->plugin_contents = 1;

+ -	    // reduce reads on cpio to this value. Could be zero if

+ -	    // this is from a hard link.

+ -	    rc = RPMRC_OK;

+ -	    break;

+ -	}

+  	fp->stage = FILE_PRE;

+      }

+      fi = rpmfiFree(fi);

+ @@ -992,14 +980,15 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+  	    if (fp->action == FA_TOUCH)

+  		continue;

+  

+ -            if (S_ISREG(fp->sb.st_mode)) {

+ +	    rpmRC plugin_rc = rpmpluginsCallFsmFileInstall(plugins, fi, fp->fpath, fp->sb.st_mode, fp->action);

+ +	    if(!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){

+ +		rc = plugin_rc;

+ +	    } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){

+ +		rc = RPMRC_OK;

+ +	    } else if (S_ISREG(fp->sb.st_mode)) {

+  		if (rc == RPMERR_ENOENT) {

+ -		    if(fp->plugin_contents) {

+ -			rc = RPMRC_OK;

+ -		    }else {

+ -			rc = fsmMkfile(fi, fp, files, psm, nodigest,

+ -			    &firstlink, &firstlinkfile);

+ -		    }

+ +		    rc = fsmMkfile(fi, fp, files, psm, nodigest,

+ +			&firstlink, &firstlinkfile);

+  		}

+              } else if (S_ISDIR(fp->sb.st_mode)) {

+                  if (rc == RPMERR_ENOENT) {

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,33 @@ 

+ From b2fc576828af873a1993bdaa2fcb7c860b94df3e Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 17:10:23 -0800

+ Subject: [PATCH 15/30] [reflink] use reflink_fsm_file_install hook instead of

+  reflink_fsm_file_pre

+ 

+ ---

+  plugins/reflink.c | 4 ++--

+  1 file changed, 2 insertions(+), 2 deletions(-)

+ 

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index ec575f55e..7dda06d8e 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -223,7 +223,7 @@ rpm_loff_t find(const unsigned char *digest, reflink_state state) {

+      return offset;

+  }

+  

+ -static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,

+ +static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* path,

+                                    mode_t file_mode, rpmFsmOp op)

+  {

+      struct file_clone_range fcr;

+ @@ -355,5 +355,5 @@ struct rpmPluginHooks_s reflink_hooks = {

+      .cleanup = reflink_cleanup,

+      .psm_pre = reflink_psm_pre,

+      .psm_post = reflink_psm_post,

+ -    .fsm_file_pre = reflink_fsm_file_pre,

+ +    .fsm_file_install = reflink_fsm_file_install,

+  };

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,28 @@ 

+ From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 20 Apr 2020 11:22:15 -0400

+ Subject: [PATCH 15/33] rpmsign: RPMSIGN_FLAG_IMA is already set

+ 

+ There is no need to set RPMSIGN_FLAG_IMA since it was already set to

+ get here.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  rpmsign.c | 1 -

+  1 file changed, 1 deletion(-)

+ 

+ diff --git a/rpmsign.c b/rpmsign.c

+ index a74948ba8..e1d207da5 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -130,7 +130,6 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  	    free(fileSigningKeyPassword);

+  	}

+  

+ -	sargs->signflags |= RPMSIGN_FLAG_IMA;

+  	free(key);

+      }

+  #endif

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,136 @@ 

+ From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Fri, 27 Mar 2020 18:31:36 -0400

+ Subject: [PATCH 16/33] Add basic autoconf and framework for fsverity support

+ 

+ Use the same signing key argument as is used for IMA file signing.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  configure.ac     | 19 +++++++++++++++++++

+  rpmsign.c        | 20 ++++++++++++++------

+  sign/Makefile.am |  5 +++++

+  sign/rpmsign.h   |  1 +

+  4 files changed, 39 insertions(+), 6 deletions(-)

+ 

+ diff --git a/configure.ac b/configure.ac

+ index 3c102d5eb..cc7144440 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -919,6 +919,25 @@ fi

+  AM_CONDITIONAL(WITH_IMAEVM,[test "$with_imaevm" = yes])

+  AC_SUBST(WITH_IMAEVM_LIB)

+  

+ +# fsverity

+ +AC_ARG_WITH([fsverity], [AS_HELP_STRING([--with-fsverity],[build with fsverity support])],[],[with_fsverity=no])

+ +if test "$with_fsverity" = yes ; then

+ +  AC_MSG_CHECKING([libfsverity])

+ +  AC_COMPILE_IFELSE(

+ +    [AC_LANG_PROGRAM(

+ +      [[#include <libfsverity.h>]],

+ +      [[return libfsverity_sign_digest(NULL, NULL, NULL, NULL);]]

+ +    )],

+ +    [AC_MSG_RESULT(yes)

+ +      AC_DEFINE(WITH_FSVERITY, 1, [Build with fsverity support?])

+ +      WITH_FSVERITY_LIB="-lfsverity"

+ +    ],

+ +    [AC_MSG_ERROR([--with-fsverity given, libfsverity or libfsverity.h missing])]

+ +  )

+ +fi

+ +AM_CONDITIONAL(WITH_FSVERITY,[test "$with_fsverity" = yes])

+ +AC_SUBST(WITH_FSVERITY_LIB)

+ +

+  # libcap

+  WITH_CAP_LIB=

+  AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],

+ diff --git a/rpmsign.c b/rpmsign.c

+ index e1d207da5..8861c2c59 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -18,7 +18,7 @@ enum modes {

+  

+  static int mode = MODE_NONE;

+  

+ -#ifdef WITH_IMAEVM

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+  static int fskpass = 0;

+  static char * fileSigningKey = NULL;

+  #endif

+ @@ -39,6 +39,13 @@ static struct poptOption signOptsTable[] = {

+      { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),

+  	&sargs.signflags, RPMSIGN_FLAG_IMA,

+  	N_("sign package(s) files"), NULL},

+ +#endif

+ +#ifdef WITH_FSVERITY

+ +    { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),

+ +	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,

+ +	N_("generate fsverity signatures for package(s) files"), NULL},

+ +#endif

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+      { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,

+  	N_("use file signing key <key>"),

+  	N_("<key>") },

+ @@ -59,7 +66,7 @@ static struct poptOption optionsTable[] = {

+      POPT_TABLEEND

+  };

+  

+ -#ifdef WITH_IMAEVM

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+  static char *get_fskpass(void)

+  {

+      struct termios flags, tmp_flags;

+ @@ -106,12 +113,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  	goto exit;

+      }

+  

+ -#ifdef WITH_IMAEVM

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+      if (fileSigningKey) {

+  	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);

+      }

+  

+ -    if (sargs->signflags & RPMSIGN_FLAG_IMA) {

+ +    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {

+  	char *fileSigningKeyPassword = NULL;

+  	char *key = rpmExpand("%{?_file_signing_key}", NULL);

+  	if (rstreq(key, "")) {

+ @@ -165,8 +172,9 @@ int main(int argc, char *argv[])

+  	argerror(_("no arguments given"));

+      }

+  

+ -#ifdef WITH_IMAEVM

+ -    if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) {

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+ +    if (fileSigningKey &&

+ +	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {

+  	argerror(_("--fskpath may only be specified when signing files"));

+      }

+  #endif

+ diff --git a/sign/Makefile.am b/sign/Makefile.am

+ index db774de0e..8d372915a 100644

+ --- a/sign/Makefile.am

+ +++ b/sign/Makefile.am

+ @@ -24,3 +24,8 @@ if WITH_IMAEVM

+  librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h

+  librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@

+  endif

+ +

+ +if WITH_FSVERITY

+ +librpmsign_la_SOURCES += rpmsignverity.c rpmsignverity.h

+ +librpmsign_la_LIBADD += @WITH_FSVERITY_LIB@

+ +endif

+ diff --git a/sign/rpmsign.h b/sign/rpmsign.h

+ index 7a770d879..2b8a10a1a 100644

+ --- a/sign/rpmsign.h

+ +++ b/sign/rpmsign.h

+ @@ -17,6 +17,7 @@ enum rpmSignFlags_e {

+      RPMSIGN_FLAG_NONE		= 0,

+      RPMSIGN_FLAG_IMA		= (1 << 0),

+      RPMSIGN_FLAG_RPMV3		= (1 << 1),

+ +    RPMSIGN_FLAG_FSVERITY	= (1 << 2),

+  };

+  typedef rpmFlags rpmSignFlags;

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,33 @@ 

+ From e04b5d20a6d8c64dba7416edba8e435145a5d7d3 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 17:12:09 -0800

+ Subject: [PATCH 16/30] [test] new runroot_plugins function to run command in

+  fakeroot without having the plugins disabled

+ 

+ ---

+  tests/atlocal.in | 9 +++++++++

+  1 file changed, 9 insertions(+)

+ 

+ diff --git a/tests/atlocal.in b/tests/atlocal.in

+ index c3189d327..c18637362 100644

+ --- a/tests/atlocal.in

+ +++ b/tests/atlocal.in

+ @@ -82,6 +82,15 @@ function runroot()

+      )

+  }

+  

+ +function runroot_plugins()

+ +{

+ +    setup_env

+ +    (unset RPM_CONFIGDIR RPM_POPTEXEC_PATH; cd ${RPMTEST} && \

+ +     MAGIC="/magic/magic" FAKECHROOT_BASE="${RPMTEST}" fakechroot "$@" --define "_buildhost testhost" --define "_topdir /build" --nouserns

+ +    )

+ +}

+ +

+ +

+  function runroot_other()

+  {

+      setup_env

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,51 @@ 

+ From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Wed, 27 May 2020 16:49:03 -0400

+ Subject: [PATCH 17/33] rpmsign: Add helper to indicate file signing enabled

+ 

+ Helper function returning true if either IMA or VERITY signatures are

+ to be applied. This simplifies the code and makes it easier to read.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  rpmsign.c | 10 +++++++---

+  1 file changed, 7 insertions(+), 3 deletions(-)

+ 

+ diff --git a/rpmsign.c b/rpmsign.c

+ index 8861c2c59..94cbf1d1a 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -67,6 +67,11 @@ static struct poptOption optionsTable[] = {

+  };

+  

+  #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+ +static int flags_sign_files(int flags)

+ +{

+ +	return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0);

+ +}

+ +

+  static char *get_fskpass(void)

+  {

+      struct termios flags, tmp_flags;

+ @@ -118,7 +123,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);

+      }

+  

+ -    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {

+ +    if (flags_sign_files(sargs->signflags)) {

+  	char *fileSigningKeyPassword = NULL;

+  	char *key = rpmExpand("%{?_file_signing_key}", NULL);

+  	if (rstreq(key, "")) {

+ @@ -173,8 +178,7 @@ int main(int argc, char *argv[])

+      }

+  

+  #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+ -    if (fileSigningKey &&

+ -	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {

+ +    if (fileSigningKey && !(flags_sign_files(sargs.signflags))) {

+  	argerror(_("--fskpath may only be specified when signing files"));

+      }

+  #endif

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,63 @@ 

+ From e86207d3395e0963f19363b047551100569900df Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 17:12:55 -0800

+ Subject: [PATCH 17/30] [test] Add test installing an RPM with reflink plugin

+ 

+ The test only runs for reflinkable FS, like XFS and BTRFS.

+ dbus_announce is being disabled as it generates warning to stderr when

+ running within the fakeroot.

+ ---

+  tests/atlocal.in     | 13 +++++++++++++

+  tests/rpm2extents.at | 15 +++++++++++++++

+  2 files changed, 28 insertions(+)

+ 

+ diff --git a/tests/atlocal.in b/tests/atlocal.in

+ index c18637362..a110564e2 100644

+ --- a/tests/atlocal.in

+ +++ b/tests/atlocal.in

+ @@ -50,6 +50,19 @@ else

+      CAP_DISABLED=true;

+  fi

+  

+ +FSTYPE=$(stat -f -c %T /)

+ +REFLINKABLE_FS=("xfs" "brtfs")

+ +

+ +REFLINK_DISABLED=true;

+ +for item in "${REFLINKABLE_FS[@]}"

+ +do

+ +    if test "${FSTYPE}" = "${item}"

+ +    then

+ +	REFLINK_DISABLED=false;

+ +	break

+ +    fi

+ +done

+ +

+  function setup_env()

+  {

+      if [ -d testing ]; then

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index 18accfc75..44e46a68e 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -94,3 +94,18 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?

+  ],

+  [])

+  AT_CLEANUP

+ +

+ +AT_SETUP([rpm2extents install package])

+ +AT_KEYWORDS([rpm2extents install package])

+ +AT_SKIP_IF([$REFLINK_DISABLED])

+ +AT_CHECK([

+ +RPMDB_INIT

+ +

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null

+ +runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm

+ +test -f ${RPMTEST}/usr/bin/hello

+ +],

+ +[0],

+ +[],

+ +[])

+ +AT_CLEANUP

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,97 @@ 

+ From 048db395b6de8544dc88231f0afebee8570daee6 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 18:21:33 -0800

+ Subject: [PATCH 18/30] [plugin] add `rpmpluginsCallFsmFileArchiveReader`

+ 

+ This allows plugins to provide a custom `rpmfi` to

+ `rpmPackageFilesInstall` function in fsm.c. It enables supporting

+ transcoded files such as with reflink plugin.

+ ---

+  lib/rpmplugin.h  |  4 ++++

+  lib/rpmplugins.c | 34 ++++++++++++++++++++++++++++++++++

+  lib/rpmplugins.h |  4 +++-

+  3 files changed, 41 insertions(+), 1 deletion(-)

+ 

+ diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h

+ index 877db81f3..6dbbcff35 100644

+ --- a/lib/rpmplugin.h

+ +++ b/lib/rpmplugin.h

+ @@ -63,6 +63,9 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,

+  typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi,

+  					      const char* path,

+  					      mode_t file_mode, rpmFsmOp op);

+ +typedef rpmRC (*plugin_fsm_file_archive_reader_func)(rpmPlugin plugin,

+ +						     FD_t payload,

+ +						     rpmfiles files, rpmfi *fi);

+  

+  

+  typedef struct rpmPluginHooks_s * rpmPluginHooks;

+ @@ -85,6 +88,7 @@ struct rpmPluginHooks_s {

+      plugin_fsm_file_post_func		fsm_file_post;

+      plugin_fsm_file_prepare_func	fsm_file_prepare;

+      plugin_fsm_file_install_func	fsm_file_install;

+ +    plugin_fsm_file_archive_reader_func	fsm_file_archive_reader;

+  };

+  

+  #ifdef __cplusplus

+ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c

+ index 850a025a0..901af1ac5 100644

+ --- a/lib/rpmplugins.c

+ +++ b/lib/rpmplugins.c

+ @@ -457,4 +457,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,

+      return rc;

+  }

+  

+ +rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload,

+ +				   rpmfiles files, rpmfi *fi)

+ +{

+ +    plugin_fsm_file_archive_reader_func hookFunc;

+ +    int i;

+ +    rpmRC rc = RPMRC_OK;

+ +    rpmRC hook_rc;

+ +

+ +    for (i = 0; i < plugins->count; i++) {

+ +	rpmPlugin plugin = plugins->plugins[i];

+ +	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_archive_reader);

+ +	if (hookFunc) {

+ +	    hook_rc = hookFunc(plugin, payload, files, fi);

+ +	    if (hook_rc == RPMRC_FAIL) {

+ +		rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_archive_reader failed\n", plugin->name);

+ +		rc = RPMRC_FAIL;

+ +	    } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {

+ +		if (rc == RPMRC_PLUGIN_CONTENTS) {

+ +		    /* Another plugin already said it'd handle contents. It's

+ +		     * undefined how these would combine, so treat this as a

+ +		     * failure condition.

+ +		    */

+ +		    rc = RPMRC_FAIL;

+ +		} else {

+ +		    /* Plugin will handle content */

+ +		    rc = RPMRC_PLUGIN_CONTENTS;

+ +		}

+ +	    }

+ +	}

+ +    }

+ +

+ +    return rc;

+ +}

+ +

+  

+ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h

+ index 5365cf698..88807c53c 100644

+ --- a/lib/rpmplugins.h

+ +++ b/lib/rpmplugins.h

+ @@ -181,7 +181,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,

+  				   const char* path, mode_t file_mode,

+  				   rpmFsmOp op);

+  

+ -

+ +RPM_GNUC_INTERNAL

+ +rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload,

+ +					 rpmfiles files, rpmfi *fi);

+  #ifdef __cplusplus

+  }

+  #endif

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,52 @@ 

+ From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Fri, 3 Apr 2020 16:26:06 -0400

+ Subject: [PATCH 18/33] rpmsign: Handle --certpath for signing certificate

+ 

+ fsverirty needs a certificate for signing, in addition to the signing key.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  rpmsign.c | 12 ++++++++++++

+  1 file changed, 12 insertions(+)

+ 

+ diff --git a/rpmsign.c b/rpmsign.c

+ index 94cbf1d1a..074dd8b13 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -22,6 +22,9 @@ static int mode = MODE_NONE;

+  static int fskpass = 0;

+  static char * fileSigningKey = NULL;

+  #endif

+ +#ifdef WITH_FSVERITY

+ +static char * fileSigningCert = NULL;

+ +#endif

+  

+  static struct rpmSignArgs sargs = {NULL, 0, 0};

+  

+ @@ -44,6 +47,9 @@ static struct poptOption signOptsTable[] = {

+      { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),

+  	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,

+  	N_("generate fsverity signatures for package(s) files"), NULL},

+ +    { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,

+ +	N_("use file signing cert <cert>"),

+ +	N_("<cert>") },

+  #endif

+  #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+      { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,

+ @@ -123,6 +129,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);

+      }

+  

+ +#ifdef WITH_FSVERITY

+ +    if (fileSigningCert) {

+ +	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);

+ +    }

+ +#endif

+ +

+      if (flags_sign_files(sargs->signflags)) {

+  	char *fileSigningKeyPassword = NULL;

+  	char *key = rpmExpand("%{?_file_signing_key}", NULL);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,243 @@ 

+ From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Fri, 3 Apr 2020 16:38:08 -0400

+ Subject: [PATCH 19/33] Implement rpmSignVerity()

+ 

+ This generates the root Merkle tree hash and signs it using the

+ specified key and certificate.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  sign/rpmgensig.c     |  36 +++++++++++++

+  sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++

+  sign/rpmsignverity.h |  29 +++++++++++

+  3 files changed, 186 insertions(+)

+  create mode 100644 sign/rpmsignverity.c

+  create mode 100644 sign/rpmsignverity.h

+ 

+ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c

+ index a6e37e71b..8d5c5858f 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -22,6 +22,7 @@

+  #include "lib/signature.h"

+  #include "lib/rpmvs.h"

+  #include "sign/rpmsignfiles.h"

+ +#include "sign/rpmsignverity.h"

+  

+  #include "debug.h"

+  

+ @@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)

+  #endif

+  }

+  

+ +static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)

+ +{

+ +#ifdef WITH_FSVERITY

+ +    rpmRC rc;

+ +    char *key = rpmExpand("%{?_file_signing_key}", NULL);

+ +    char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);

+ +    char *cert = rpmExpand("%{?_file_signing_cert}", NULL);

+ +

+ +    if (rstreq(keypass, "")) {

+ +	free(keypass);

+ +	keypass = NULL;

+ +    }

+ +

+ +    if (key && cert) {

+ +	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);

+ +    } else {

+ +	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));

+ +	rc = RPMRC_FAIL;

+ +    }

+ +

+ +    free(keypass);

+ +    free(key);

+ +    free(cert);

+ +    return rc;

+ +#else

+ +    rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n"));

+ +    return RPMRC_FAIL;

+ +#endif

+ +}

+ +

+  static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)

+  {

+      char **msg = cbdata;

+ @@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	    goto exit;

+      }

+  

+ +    if (flags & RPMSIGN_FLAG_FSVERITY) {

+ +	if (includeVeritySignatures(fd, &sigh, &h))

+ +	    goto exit;

+ +    }

+ +

+      if (deleting) {	/* Nuke all the signature tags. */

+  	deleteSigs(sigh);

+      } else {

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ new file mode 100644

+ index 000000000..5346c3bc8

+ --- /dev/null

+ +++ b/sign/rpmsignverity.c

+ @@ -0,0 +1,121 @@

+ +/**

+ + * Copyright (C) 2020 Facebook

+ + *

+ + * Author: Jes Sorensen <jsorensen@fb.com>

+ + */

+ +

+ +#include "system.h"

+ +

+ +#include <rpm/rpmlib.h>		/* RPMSIGTAG & related */

+ +#include <rpm/rpmlog.h>		/* rpmlog */

+ +#include <rpm/rpmfi.h>

+ +#include <rpm/rpmpgp.h>		/* rpmDigestLength */

+ +#include "lib/header.h"		/* HEADERGET_MINMEM */

+ +#include "lib/header_internal.h"

+ +#include "lib/rpmtypes.h"	/* rpmRC */

+ +#include <libfsverity.h>

+ +#include "rpmio/rpmio_internal.h"

+ +#include "lib/rpmvs.h"

+ +

+ +#include "sign/rpmsignverity.h"

+ +

+ +#define MAX_SIGNATURE_LENGTH 1024

+ +

+ +static int rpmVerityRead(void *opaque, void *buf, size_t size)

+ +{

+ +	int retval;

+ +	rpmfi fi = (rpmfi)opaque;

+ +

+ +	retval = rpmfiArchiveRead(fi, buf, size);

+ +

+ +	if (retval > 0)

+ +		retval = 0;

+ +	return retval;

+ +}

+ +

+ +rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ +		    char *keypass, char *cert)

+ +{

+ +    int rc, status;

+ +    FD_t gzdi;

+ +    rpmfiles files = NULL;

+ +    rpmfi fi = NULL;

+ +    rpmts ts = rpmtsCreate();

+ +    struct libfsverity_digest *digest = NULL;

+ +    struct libfsverity_merkle_tree_params params;

+ +    struct libfsverity_signature_params sig_params;

+ +    rpm_loff_t file_size;

+ +    off_t offset = Ftell(fd);

+ +    const char *compr;

+ +    char *rpmio_flags = NULL;

+ +    char *digest_hex;

+ +    uint8_t *sig;

+ +    size_t sig_size;

+ +

+ +    Fseek(fd, 0, SEEK_SET);

+ +    rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |

+ +		    RPMVSF_NOHDRCHK);

+ +    rc = rpmReadPackageFile(ts, fd, "fsverity", &h);

+ +    if (rc != RPMRC_OK) {

+ +	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),

+ +	       __func__, rc);

+ +	goto out;

+ +    }

+ +

+ +    rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);

+ +    rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);

+ +

+ +    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);

+ +    rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);

+ +

+ +    gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);

+ +    free(rpmio_flags);

+ +

+ +    files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);

+ +    fi = rpmfiNewArchiveReader(gzdi, files,

+ +			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);

+ +

+ +    while (rpmfiNext(fi) >= 0) {

+ +	if (!S_ISREG(rpmfiFMode(fi)))

+ +	    continue;

+ +	file_size = rpmfiFSize(fi);

+ +	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),

+ +	       rpmfiFN(fi), file_size);

+ +

+ +	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));

+ +	params.version = 1;

+ +	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ +	params.block_size = sysconf(_SC_PAGESIZE);

+ +	params.salt_size = 0 /* salt_size */;

+ +	params.salt = NULL /* salt */;

+ +	params.file_size = file_size;

+ +	status = libfsverity_compute_digest(fi, rpmVerityRead,

+ +					    &params, &digest);

+ +	if (!status) {

+ +	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);

+ +	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),

+ +		   digest->digest_size, digest_hex);

+ +	    free(digest_hex);

+ +	}

+ +	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));

+ +	sig_params.keyfile = key;

+ +	sig_params.certfile = cert;

+ +	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {

+ +	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));

+ +	    rc = RPMRC_FAIL;

+ +	    goto out;

+ +	}

+ +	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));

+ +

+ +	free(digest);

+ +	free(sig);

+ +    }

+ +

+ +out:

+ +    Fseek(fd, offset, SEEK_SET);

+ +

+ +    rpmfilesFree(files);

+ +    rpmfiFree(fi);

+ +    rpmtsFree(ts);

+ +    return rc;

+ +}

+ diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h

+ new file mode 100644

+ index 000000000..f3ad3bb18

+ --- /dev/null

+ +++ b/sign/rpmsignverity.h

+ @@ -0,0 +1,29 @@

+ +#ifndef H_RPMSIGNVERITY

+ +#define H_RPMSIGNVERITY

+ +

+ +#include <rpm/rpmtypes.h>

+ +#include <rpm/rpmutil.h>

+ +

+ +#ifdef __cplusplus

+ +extern "C" {

+ +#endif

+ +

+ +/**

+ + * Sign file digests in header into signature header

+ + * @param fd		file descriptor of RPM

+ + * @param sigh		package signature header

+ + * @param h		package header

+ + * @param key		signing key

+ + * @param keypass	signing key password

+ + * @param cert		signing cert

+ + * @return		RPMRC_OK on success

+ + */

+ +RPM_GNUC_INTERNAL

+ +rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ +		    char *keypass, char *cert);

+ +

+ +#ifdef _cplusplus

+ +}

+ +#endif

+ +

+ +#endif /* H_RPMSIGNVERITY */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,156 @@ 

+ From 5f762af17c6e72e86e4710975dcdfd71fc5d1b07 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 8 Feb 2022 18:24:12 -0800

+ Subject: [PATCH 19/30] [reflink] use `rpmpluginsCallFsmFileArchiveReader` to

+  provide custom rpmfi

+ 

+ As the plugin can now be responsible to provide an Archive Reader to

+ `rpmPackageFilesInstall`, we also don't need to mutate the

+ `RPMTAG_PAYLOADFORMAT` header in memory, removing some special-casing.

+ ---

+  lib/depends.c     |  2 --

+  lib/fsm.c         | 38 +++++++++++++++++++-------------------

+  plugins/reflink.c | 18 +++++++++++++-----

+  3 files changed, 32 insertions(+), 26 deletions(-)

+ 

+ diff --git a/lib/depends.c b/lib/depends.c

+ index 8998afcd3..30234df3d 100644

+ --- a/lib/depends.c

+ +++ b/lib/depends.c

+ @@ -81,8 +81,6 @@ static rpmRC headerCheckPayloadFormat(Header h) {

+       */

+      if (!payloadfmt) return rc;

+  

+ -    if (rstreq(payloadfmt, "clon")) return rc;

+ -

+      if (!rstreq(payloadfmt, "cpio")) {

+          char *nevra = headerGetAsString(h, RPMTAG_NEVRA);

+          if (payloadfmt && rstreq(payloadfmt, "drpm")) {

+ diff --git a/lib/fsm.c b/lib/fsm.c

+ index 711f553d3..6972602e0 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -19,7 +19,6 @@

+  

+  #include "rpmio/rpmio_internal.h"	/* fdInit/FiniDigest */

+  #include "lib/fsm.h"

+ -#include "lib/rpmlib.h"

+  #include "lib/rpmte_internal.h"	/* XXX rpmfs */

+  #include "lib/rpmplugins.h"	/* rpm plugins hooks */

+  #include "lib/rpmug.h"

+ @@ -892,14 +891,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+      struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));

+      struct filedata_s *firstlink = NULL;

+  

+ -    Header h = rpmteHeader(te);

+ -    const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);

+ -    int cpio = 1;

+ -

+ -    if (payloadfmt && rstreq(payloadfmt, "clon")) {

+ -	cpio = 0;

+ -    }

+ -

+      /* transaction id used for temporary path suffix while installing */

+      rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));

+  

+ @@ -933,14 +924,24 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+      if (rc)

+  	goto exit;

+  

+ -    if (cpio) {

+ -	fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);

+ -	if (fi == NULL) {

+ -	    rc = RPMERR_BAD_MAGIC;

+ -	    goto exit;

+ -	}

+ -    } else {

+ -	fi = rpmfilesIter(files, RPMFI_ITER_FWD);

+ +    rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, &fi);

+ +    switch(plugin_rc) {

+ +	case RPMRC_PLUGIN_CONTENTS:

+ +	    if(fi == NULL) {

+ +		rc = RPMERR_BAD_MAGIC;

+ +		goto exit;

+ +	    }

+ +	    rc = RPMRC_OK;

+ +	    break;

+ +	case RPMRC_OK:

+ +	    fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);

+ +	    if (fi == NULL) {

+ +		rc = RPMERR_BAD_MAGIC;

+ +		goto exit;

+ +	    }

+ +	    break;

+ +	default:

+ +	    rc = RPMRC_FAIL;

+      }

+  

+      /* Detect and create directories not explicitly in package. */

+ @@ -988,7 +989,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+  	    } else if (S_ISREG(fp->sb.st_mode)) {

+  		if (rc == RPMERR_ENOENT) {

+  		    rc = fsmMkfile(fi, fp, files, psm, nodigest,

+ -			&firstlink, &firstlinkfile);

+ +				   &firstlink, &firstlinkfile);

+  		}

+              } else if (S_ISDIR(fp->sb.st_mode)) {

+                  if (rc == RPMERR_ENOENT) {

+ @@ -1096,7 +1097,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,

+      rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));

+  

+  exit:

+ -    h = headerFree(h);

+      fi = rpmfiFree(fi);

+      Fclose(payload);

+      free(tid);

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index 7dda06d8e..d5e6db27a 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -54,6 +54,7 @@ struct reflink_state_s {

+      FD_t fd;

+      rpmfiles files;

+      inodeIndexHash inodeIndexes;

+ +    int transcoded;

+  };

+  

+  typedef struct reflink_state_s * reflink_state;

+ @@ -116,12 +117,8 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {

+  	    break;

+      }

+      rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));

+ -    Header h = rpmteHeader(te);

+ +    state->transcoded = 1;

+  

+ -    /* replace/add header that main fsm.c can read */

+ -    headerDel(h, RPMTAG_PAYLOADFORMAT);

+ -    headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon");

+ -    headerFree(h);

+      state->files = rpmteFiles(te);

+      /* tail of file contains offset_table, offset_checksums then magic */

+      if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) {

+ @@ -350,10 +347,21 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa

+      return RPMRC_OK;

+  }

+  

+ +static rpmRC reflink_fsm_file_archive_reader(rpmPlugin plugin, FD_t payload,

+ +					     rpmfiles files, rpmfi *fi) {

+ +    reflink_state state = rpmPluginGetData(plugin);

+ +    if(state->transcoded) {

+ +	*fi = rpmfilesIter(files, RPMFI_ITER_FWD);

+ +	return RPMRC_PLUGIN_CONTENTS;

+ +    }

+ +    return RPMRC_OK;

+ +}

+ +

+  struct rpmPluginHooks_s reflink_hooks = {

+      .init = reflink_init,

+      .cleanup = reflink_cleanup,

+      .psm_pre = reflink_psm_pre,

+      .psm_post = reflink_psm_post,

+      .fsm_file_install = reflink_fsm_file_install,

+ +    .fsm_file_archive_reader = reflink_fsm_file_archive_reader,

+  };

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,95 @@ 

+ From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Thu, 28 May 2020 17:48:23 -0400

+ Subject: [PATCH 20/33] Introduce base2bin() - a helper to convert tag array of

+  base64 strings

+ 

+ This will convert a tag of base64 strings to a binary array, similar

+ to how hex2bin() works. It supports variable sized strings, and will

+ determine the maximum string length and build the output array based

+ on that.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/rpmfi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++

+  1 file changed, 58 insertions(+)

+ 

+ diff --git a/lib/rpmfi.c b/lib/rpmfi.c

+ index 689ead2c5..8c69d3e40 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -19,6 +19,7 @@

+  #include "lib/fsm.h"	/* rpmpsm stuff for now */

+  #include "lib/rpmug.h"

+  #include "rpmio/rpmio_internal.h"       /* fdInit/FiniDigest */

+ +#include "rpmio/rpmbase64.h"

+  

+  #include "debug.h"

+  

+ @@ -1520,6 +1521,63 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)

+      return bin;

+  }

+  

+ +/*

+ + * Convert a tag of base64 strings to binary presentation.

+ + * This handles variable length strings by finding the longest string

+ + * before building the output array. Dummy strings in the tag should be

+ + * added as '\0'

+ + */

+ +static uint8_t *base2bin(Header h, rpmTagVal tag, rpm_count_t num, int *len)

+ +{

+ +    struct rpmtd_s td;

+ +    uint8_t *bin = NULL, *t = NULL;

+ +    size_t maxlen = 0;

+ +    int status, i= 0;

+ +    void **arr = xmalloc(num * sizeof(void *));

+ +    size_t *lengths = xcalloc(num, sizeof(size_t));

+ +    const char *s;

+ +

+ +    if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) != num)

+ +	goto out;

+ +

+ +    while ((s = rpmtdNextString(&td))) {

+ +	/* Insert a dummy entry for empty strings */

+ +	if (*s == '\0') {

+ +	    arr[i++] = NULL;

+ +	    continue;

+ +	}

+ +	status = rpmBase64Decode(s, &arr[i], &lengths[i]);

+ +	if (lengths[i] > maxlen)

+ +	    maxlen = lengths[i];

+ +	if (status) {

+ +	    rpmlog(RPMLOG_DEBUG, _("%s: base64 decode failed, len %li\n"),

+ +		   __func__, lengths[i]);

+ +	    goto out;

+ +	}

+ +	i++;

+ +    }

+ +

+ +    if (maxlen) {

+ +	rpmlog(RPMLOG_DEBUG, _("%s: base64 decode success, len %li\n"),

+ +	       __func__, maxlen);

+ +

+ +	t = bin = xcalloc(num, maxlen);

+ +

+ +	for (i = 0; i < num; i++) {

+ +	    memcpy(t, arr[i], lengths[i]);

+ +	    free(arr[i]);

+ +	    t += maxlen;

+ +	}

+ +	*len = maxlen;

+ +    }

+ + out:

+ +    free(arr);

+ +    free(lengths);

+ +    rpmtdFreeData(&td);

+ +

+ +    return bin;

+ +}

+ +

+  static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)

+  {

+      headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ? 

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,35 @@ 

+ From 13aea986ada3ed7d26182d81d8878bcc807a6ab5 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Thu, 10 Feb 2022 08:49:17 -0800

+ Subject: [PATCH 20/30] [reflink][tests] Can install standard RPM with reflink

+ 

+ Add a test to validate that if a file is a non-transcoded RPM, the reflink plugin correctly ignores the file and let core RPM do the job.

+ ---

+  tests/rpm2extents.at | 14 ++++++++++++++

+  1 file changed, 14 insertions(+)

+ 

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index 44e46a68e..648304287 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -109,3 +109,17 @@ test -f ${RPMTEST}/usr/bin/hello

+  [],

+  [])

+  AT_CLEANUP

+ +

+ +AT_SETUP([reflink ignores non-transcoded package])

+ +AT_KEYWORDS([reflink])

+ +AT_CHECK([

+ +RPMDB_INIT

+ +

+ +runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $?

+ +# Check that the file is properly installed in chroot

+ +test -f ${RPMTEST}/usr/bin/hello

+ +],

+ +[0],

+ +[],

+ +[])

+ +AT_CLEANUP

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,206 @@ 

+ From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Thu, 9 Apr 2020 12:58:17 -0400

+ Subject: [PATCH 21/33] rpmsignverity: Add verity signature headers to the

+  package

+ 

+ This adds the array of verity signatures, and a signature length

+ header. We use 4K block for the Merkle tree, and rely on the kernel

+ doing the right thing.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/rpmtag.h         |   6 ++-

+  sign/rpmsignverity.c | 112 +++++++++++++++++++++++++++++--------------

+  sign/rpmsignverity.h |   7 +++

+  3 files changed, 87 insertions(+), 38 deletions(-)

+ 

+ diff --git a/lib/rpmtag.h b/lib/rpmtag.h

+ index 40ff5fa5d..478457ecb 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -67,6 +67,7 @@ typedef enum rpmTag_e {

+      RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */

+      /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */

+      /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */

+ +    RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */

+  

+      RPMTAG_NAME  		= 1000,	/* s */

+  #define	RPMTAG_N	RPMTAG_NAME	/* s */

+ @@ -427,6 +428,7 @@ typedef enum rpmSigTag_e {

+      RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,

+      RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,

+      RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,

+ +    RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,

+  } rpmSigTag;

+  

+  

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 5346c3bc8..a9818bd08 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -33,23 +33,66 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)

+  	return retval;

+  }

+  

+ +static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+ +			       char *keypass, char *cert)

+ +{

+ +    struct libfsverity_merkle_tree_params params;

+ +    struct libfsverity_signature_params sig_params;

+ +    struct libfsverity_digest *digest = NULL;

+ +    rpm_loff_t file_size;

+ +    char *digest_hex, *sig_hex = NULL;

+ +    uint8_t *sig;

+ +    int status;

+ +

+ +    file_size = rpmfiFSize(fi);

+ +

+ +    memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));

+ +    params.version = 1;

+ +    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ +    params.block_size = RPM_FSVERITY_BLKSZ;

+ +    params.salt_size = 0 /* salt_size */;

+ +    params.salt = NULL /* salt */;

+ +    params.file_size = file_size;

+ +    status = libfsverity_compute_digest(fi, rpmVerityRead, &params, &digest);

+ +    if (status) {

+ +	rpmlog(RPMLOG_DEBUG, _("failed to compute digest\n"));

+ +	goto out;

+ +    }

+ +

+ +    digest_hex = pgpHexStr(digest->digest, digest->digest_size);

+ +    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),

+ +	   digest->digest_size, digest_hex);

+ +    free(digest_hex);

+ +

+ +    memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));

+ +    sig_params.keyfile = key;

+ +    sig_params.certfile = cert;

+ +    if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) {

+ +	rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));

+ +	goto out;

+ +    }

+ +

+ +    sig_hex = pgpHexStr(sig, *sig_size + 1);

+ + out:

+ +    free(digest);

+ +    free(sig);

+ +    return sig_hex;

+ +}

+ +

+  rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+  		    char *keypass, char *cert)

+  {

+ -    int rc, status;

+ +    int rc;

+      FD_t gzdi;

+      rpmfiles files = NULL;

+      rpmfi fi = NULL;

+      rpmts ts = rpmtsCreate();

+ -    struct libfsverity_digest *digest = NULL;

+ -    struct libfsverity_merkle_tree_params params;

+ -    struct libfsverity_signature_params sig_params;

+ +    struct rpmtd_s td;

+      rpm_loff_t file_size;

+      off_t offset = Ftell(fd);

+      const char *compr;

+      char *rpmio_flags = NULL;

+ -    char *digest_hex;

+ -    uint8_t *sig;

+ +    char *sig_hex;

+      size_t sig_size;

+  

+      Fseek(fd, 0, SEEK_SET);

+ @@ -75,43 +118,40 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      fi = rpmfiNewArchiveReader(gzdi, files,

+  			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);

+  

+ +    /*

+ +     * Should this be sigh from the cloned fd or the sigh we received?

+ +     */

+ +    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);

+ +

+ +    rpmtdReset(&td);

+ +    td.tag = RPMSIGTAG_VERITYSIGNATURES;

+ +    td.type = RPM_STRING_ARRAY_TYPE;

+ +    td.count = 1;

+ +

+      while (rpmfiNext(fi) >= 0) {

+ -	if (!S_ISREG(rpmfiFMode(fi)))

+ -	    continue;

+  	file_size = rpmfiFSize(fi);

+ -	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),

+ -	       rpmfiFN(fi), file_size);

+ -

+ -	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));

+ -	params.version = 1;

+ -	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ -	params.block_size = sysconf(_SC_PAGESIZE);

+ -	params.salt_size = 0 /* salt_size */;

+ -	params.salt = NULL /* salt */;

+ -	params.file_size = file_size;

+ -	status = libfsverity_compute_digest(fi, rpmVerityRead,

+ -					    &params, &digest);

+ -	if (!status) {

+ -	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);

+ -	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),

+ -		   digest->digest_size, digest_hex);

+ -	    free(digest_hex);

+ -	}

+ -	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));

+ -	sig_params.keyfile = key;

+ -	sig_params.certfile = cert;

+ -	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {

+ -	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));

+ +

+ +	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),

+ +	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));

+ +

+ +	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);

+ +	td.data = &sig_hex;

+ +	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);

+ +#if 0

+ +	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);

+ +#endif

+ +	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {

+ +	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto out;

+  	}

+ -	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));

+ -

+ -	free(digest);

+ -	free(sig);

+ +	free(sig_hex);

+      }

+  

+ -out:

+ +    rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));

+ +

+ +    rc = RPMRC_OK;

+ + out:

+      Fseek(fd, offset, SEEK_SET);

+  

+      rpmfilesFree(files);

+ diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h

+ index f3ad3bb18..69bbaf7f7 100644

+ --- a/sign/rpmsignverity.h

+ +++ b/sign/rpmsignverity.h

+ @@ -8,6 +8,13 @@

+  extern "C" {

+  #endif

+  

+ +/*

+ + * Block size used to generate the Merkle tree for fsverity. For now

+ + * we only support 4K blocks, if we ever decide to support different

+ + * block sizes, we will need a tag to indicate this.

+ + */

+ +#define RPM_FSVERITY_BLKSZ	4096

+ +

+  /**

+   * Sign file digests in header into signature header

+   * @param fd		file descriptor of RPM

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,43 @@ 

+ From 3e363f853a4379e0199db81f777f4b610e158eae Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Thu, 10 Feb 2022 08:49:58 -0800

+ Subject: [PATCH 21/30] [tests] Fix tests AT_KEYWORDS usage

+ 

+ ---

+  tests/rpm2extents.at | 6 +++---

+  1 file changed, 3 insertions(+), 3 deletions(-)

+ 

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index 648304287..fa124ac03 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -32,7 +32,7 @@ AT_CLEANUP

+  # Check that transcoder writes checksig return code and content.

+  #

+  AT_SETUP([rpm2extents signature])

+ -AT_KEYWORDS([rpm2extents digest signature])

+ +AT_KEYWORDS([rpm2extents])

+  AT_CHECK([

+  RPMDB_INIT

+  

+ @@ -64,7 +64,7 @@ RPMSignOutput Content     Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK

+  AT_CLEANUP

+  

+  AT_SETUP([rpm2extents signature verification])

+ -AT_KEYWORDS([rpm2extents digest signature])

+ +AT_KEYWORDS([rpm2extents])

+  AT_CHECK([

+  RPMDB_INIT

+  

+ @@ -96,7 +96,7 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?

+  AT_CLEANUP

+  

+  AT_SETUP([rpm2extents install package])

+ -AT_KEYWORDS([rpm2extents install package])

+ +AT_KEYWORDS([rpm2extents reflink])

+  AT_SKIP_IF([$REFLINK_DISABLED])

+  AT_CHECK([

+  RPMDB_INIT

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,132 @@ 

+ From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Fri, 11 Feb 2022 18:09:47 -0800

+ Subject: [PATCH 22/30] [reflink] fix support for hardlinks

+ 

+ a `suffix` made of ";${tid}" is now used until the changes are commited. As such, when

+ linking the file, we should link to the suffixed file.

+ 

+ The `suffix` is currently internal only to rpmPackageFilesInstall and there is

+ no obvious way to use data from struct `filedata_s` without exposing it to

+ a bunch of other places such as rpmplugin*.

+ We already keep track of the first file index. We used to use this to fetch the

+ file name, but due to suffix, the file is not named correctly, e.g it

+ has the name we will want at the end, once the transaction is commited,

+ not the temporary name.

+ Instead of re-implementing a local suffix that may change over time as

+ the implementation evolves, we can store the name of the file we should link to

+ in the hash instead of the index, which we were then using to fetch the

+ file name.

+ When hardlinking, we can then retrieve the name of the target file

+ instead of the index, like we previously did, and hardlink to that

+ without any issues.

+ Add a test to validate that reflink can handle hardlinking.

+ 

+ Originally, the test added would fail with:

+ 

+ ```

+ error: reflink: Unable to hard link /foo/hello -> /foo/hello-bar;6207219c due to No such file or directory

+ error: Plugin reflink: hook fsm_file_install failed

+ error: unpacking of archive failed on file /foo/hello-bar;6207219c:

+ cpio: (error 0x2)

+ error: hlinktest-1.0-1.noarch: install failed

+ ./rpm2extents.at:114: exit code was 1, expected 0

+ 499. rpm2extents.at:112: 499. reflink hardlink package

+ (rpm2extents.at:112): FAILED (rpm2extents.at:114)

+ ```

+ 

+ After this change, the test passes.

+ ---

+  plugins/reflink.c    | 19 ++++++++-----------

+  tests/rpm2extents.at | 15 +++++++++++++++

+  2 files changed, 23 insertions(+), 11 deletions(-)

+ 

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index d5e6db27a..4fc1d74d1 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -29,7 +29,7 @@

+  #undef HTDATATYPE

+  #define HASHTYPE inodeIndexHash

+  #define HTKEYTYPE rpm_ino_t

+ -#define HTDATATYPE int

+ +#define HTDATATYPE const char *

+  #include "lib/rpmhash.H"

+  #include "lib/rpmhash.C"

+  

+ @@ -163,7 +163,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {

+  	    return RPMRC_FAIL;

+  	}

+  	state->inodeIndexes = inodeIndexHashCreate(

+ -	    state->keys, inodeId, inodeCmp, NULL, NULL

+ +	    state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)rfree

+  	);

+      }

+  

+ @@ -226,7 +226,7 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa

+      struct file_clone_range fcr;

+      rpm_loff_t size;

+      int dst, rc;

+ -    int *hlix;

+ +    const char **hl_target = NULL;

+  

+      reflink_state state = rpmPluginGetData(plugin);

+      if (state->table == NULL) {

+ @@ -243,18 +243,15 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa

+  	/* check for hard link entry in table. GetEntry overwrites hlix with

+  	 * the address of the first match.

+  	 */

+ -	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL,

+ -	                           NULL)) {

+ +	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target,

+ +				   NULL, NULL)) {

+  	    /* entry is in table, use hard link */

+ -	    char *fn = rpmfilesFN(state->files, hlix[0]);

+ -	    if (link(fn, path) != 0) {

+ +	    if (link(hl_target[0], path) != 0) {

+  		rpmlog(RPMLOG_ERR,

+  		       _("reflink: Unable to hard link %s -> %s due to %s\n"),

+ -		       fn, path, strerror(errno));

+ -		free(fn);

+ +		       hl_target[0], path, strerror(errno));

+  		return RPMRC_FAIL;

+  	    }

+ -	    free(fn);

+  	    return RPMRC_PLUGIN_CONTENTS;

+  	}

+  	/* if we didn't hard link, then we'll track this inode as being

+ @@ -262,7 +259,7 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa

+  	 */

+  	if (rpmfiFNlink(fi) > 1) {

+  	    /* minor optimization: only store files with more than one link */

+ -	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));

+ +	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path));

+  	}

+  	/* derived from wfd_open in fsm.c */

+  	mode_t old_umask = umask(0577);

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index fa124ac03..5c66de7f6 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -123,3 +123,18 @@ test -f ${RPMTEST}/usr/bin/hello

+  [],

+  [])

+  AT_CLEANUP

+ +

+ +AT_SETUP([reflink hardlink package])

+ +AT_KEYWORDS([reflink hardlink])

+ +AT_SKIP_IF([$REFLINK_DISABLED])

+ +AT_CHECK([

+ +RPMDB_INIT

+ +

+ +PKG=hlinktest-1.0-1.noarch.rpm

+ +runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null

+ +runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG}

+ +],

+ +[0],

+ +[],

+ +[])

+ +AT_CLEANUP

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,162 @@ 

+ From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 13 Apr 2020 18:14:15 -0400

+ Subject: [PATCH 22/33] rpmSignVerity: Generate signatures for files not

+  present in archive

+ 

+ This generates signatures for all files in the archive, then picks up

+ ghost files from the header metadata and generates signatures for them

+ as well. It finally submits them to RPMTAG_VERITYSIGNATURES in header

+ file order as we cannot rely on archive order and header order being

+ the same.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/package.c        |  1 +

+  sign/rpmsignverity.c | 55 ++++++++++++++++++++++++++++++++++----------

+  2 files changed, 44 insertions(+), 12 deletions(-)

+ 

+ diff --git a/lib/package.c b/lib/package.c

+ index b7d996a12..c6108f686 100644

+ --- a/lib/package.c

+ +++ b/lib/package.c

+ @@ -45,6 +45,7 @@ struct taglate_s {

+      { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },

+      { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },

+      { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },

+ +    { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },

+      { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },

+      { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },

+      { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index a9818bd08..3bb23a18d 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -41,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      struct libfsverity_digest *digest = NULL;

+      rpm_loff_t file_size;

+      char *digest_hex, *sig_hex = NULL;

+ -    uint8_t *sig;

+ +    uint8_t *sig = NULL;

+      int status;

+  

+      file_size = rpmfiFSize(fi);

+ @@ -72,7 +72,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+  	goto out;

+      }

+  

+ -    sig_hex = pgpHexStr(sig, *sig_size + 1);

+ +    sig_hex = pgpHexStr(sig, *sig_size);

+   out:

+      free(digest);

+      free(sig);

+ @@ -86,6 +86,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      FD_t gzdi;

+      rpmfiles files = NULL;

+      rpmfi fi = NULL;

+ +    rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);

+      rpmts ts = rpmtsCreate();

+      struct rpmtd_s td;

+      rpm_loff_t file_size;

+ @@ -93,11 +94,14 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      const char *compr;

+      char *rpmio_flags = NULL;

+      char *sig_hex;

+ +    char **signatures = NULL;

+      size_t sig_size;

+ +    int nr_files, idx;

+  

+      Fseek(fd, 0, SEEK_SET);

+      rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |

+  		    RPMVSF_NOHDRCHK);

+ +

+      rc = rpmReadPackageFile(ts, fd, "fsverity", &h);

+      if (rc != RPMRC_OK) {

+  	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),

+ @@ -113,6 +117,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+  

+      gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);

+      free(rpmio_flags);

+ +    if (!gzdi)

+ +	rpmlog(RPMLOG_DEBUG, _("Fdopen() failed\n"));

+  

+      files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);

+      fi = rpmfiNewArchiveReader(gzdi, files,

+ @@ -123,39 +129,64 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+       */

+      headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);

+  

+ -    rpmtdReset(&td);

+ -    td.tag = RPMSIGTAG_VERITYSIGNATURES;

+ -    td.type = RPM_STRING_ARRAY_TYPE;

+ -    td.count = 1;

+ +    /*

+ +     * The payload doesn't include special files, like ghost files, and

+ +     * we cannot rely on the file order in the payload to match that of

+ +     * the header. Instead we allocate an array of pointers and populate

+ +     * it as we go along. Then walk the header fi and account for the

+ +     * special files. Last we walk the array and populate the header.

+ +     */

+ +    nr_files = rpmfiFC(hfi);

+ +    signatures = xcalloc(nr_files, sizeof(char *));

+ +

+ +    rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),

+ +	   nr_files, rpmfiFC(fi));

+  

+      while (rpmfiNext(fi) >= 0) {

+  	file_size = rpmfiFSize(fi);

+ +	idx = rpmfiFX(fi);

+  

+  	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),

+  	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));

+  

+ -	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);

+ +	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);

+ +    }

+ +

+ +    while (rpmfiNext(hfi) >= 0) {

+ +	idx = rpmfiFX(hfi);

+ +	if (signatures[idx])

+ +	    continue;

+ +	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);

+ +    }

+ +

+ +    rpmtdReset(&td);

+ +    td.tag = RPMSIGTAG_VERITYSIGNATURES;

+ +    td.type = RPM_STRING_ARRAY_TYPE;

+ +    td.count = 1;

+ +    for (idx = 0; idx < nr_files; idx++) {

+ +	sig_hex = signatures[idx];

+  	td.data = &sig_hex;

+ -	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);

+ -#if 0

+ -	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);

+ -#endif

+  	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {

+  	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto out;

+  	}

+ -	free(sig_hex);

+ +	rpmlog(RPMLOG_DEBUG, _("signature: %s\n"), signatures[idx]);

+ +	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);

+ +	free(signatures[idx]);

+ +	signatures[idx] = NULL;

+      }

+  

+      rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));

+  

+      rc = RPMRC_OK;

+   out:

+ +    signatures = _free(signatures);

+      Fseek(fd, offset, SEEK_SET);

+  

+      rpmfilesFree(files);

+      rpmfiFree(fi);

+ +    rpmfiFree(hfi);

+      rpmtsFree(ts);

+      return rc;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,189 @@ 

+ From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 13 Apr 2020 18:21:36 -0400

+ Subject: [PATCH 23/33] Process verity tag on package read

+ 

+ This processes verity signature tags on package read, and provides

+ accessor functions to access them.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/rpmfi.c          | 27 +++++++++++++++++++++++++++

+  lib/rpmfi.h          |  8 ++++++++

+  lib/rpmfiles.h       | 10 ++++++++++

+  sign/rpmsignverity.c | 20 ++++++++++++++++----

+  4 files changed, 61 insertions(+), 4 deletions(-)

+ 

+ diff --git a/lib/rpmfi.c b/lib/rpmfi.c

+ index 8c69d3e40..5fdbe02a2 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -116,8 +116,10 @@ struct rpmfiles_s {

+  

+      int digestalgo;		/*!< File digest algorithm */

+      uint32_t *signatureoffs;	/*!< File signature offsets */

+ +    int veritysiglength;	/*!< Verity signature length */

+      unsigned char * digests;	/*!< File digests in binary. */

+      unsigned char * signatures; /*!< File signatures in binary. */

+ +    unsigned char * veritysigs; /*!< Verity signatures in binary. */

+  

+      struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */

+      rpm_off_t * replacedSizes;	/*!< (TR_ADDED) */

+ @@ -582,6 +584,19 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)

+      return signature;

+  }

+  

+ +const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)

+ +{

+ +    const unsigned char *vsignature = NULL;

+ +

+ +    if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {

+ +	if (fi->veritysigs != NULL)

+ +	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);

+ +	if (len)

+ +	    *len = fi->veritysiglength;

+ +    }

+ +    return vsignature;

+ +}

+ +

+  const char * rpmfilesFLink(rpmfiles fi, int ix)

+  {

+      const char * flink = NULL;

+ @@ -1268,6 +1283,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)

+  	fi->digests = _free(fi->digests);

+  	fi->signatures = _free(fi->signatures);

+  	fi->signatureoffs = _free(fi->signatureoffs);

+ +	fi->veritysigs = _free(fi->veritysigs);

+  	fi->fcaps = _free(fi->fcaps);

+  

+  	fi->cdict = _free(fi->cdict);

+ @@ -1649,6 +1665,12 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)

+  				 totalfc, &fi->signatureoffs);

+      }

+  

+ +    fi->veritysigs = NULL;

+ +    if (!(flags & RPMFI_NOVERITYSIGNATURES)) {

+ +	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,

+ +				  totalfc, &fi->veritysiglength);

+ +    }

+ +

+      /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */

+      if (!(flags & RPMFI_NOFILEMTIMES))

+  	_hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);

+ @@ -1939,6 +1961,11 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)

+      return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);

+  }

+  

+ +const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)

+ +{

+ +    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);

+ +}

+ +

+  uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)

+  {

+      return rpmfilesFDepends(fi->files,  fi ? fi->i : -1, fddictp);

+ diff --git a/lib/rpmfi.h b/lib/rpmfi.h

+ index 6ef70cd28..fcb9d3acd 100644

+ --- a/lib/rpmfi.h

+ +++ b/lib/rpmfi.h

+ @@ -190,6 +190,14 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo);

+   */

+  const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);

+  

+ +/** \ingroup rpmfi

+ + * Return current verity (binary) signature of file info set iterator.

+ + * @param fi		file info set iterator

+ + * @retval siglen	signature length (pass NULL to ignore)

+ + * @return		current verity signature, NULL on invalid

+ + */

+ +const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);

+ +

+  /** \ingroup rpmfi

+   * Return current file linkto (i.e. symlink(2) target) from file info set iterator.

+   * @param fi		file info set iterator

+ diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h

+ index daf572cf4..81b3d01a1 100644

+ --- a/lib/rpmfiles.h

+ +++ b/lib/rpmfiles.h

+ @@ -119,6 +119,7 @@ enum rpmfiFlags_e {

+      RPMFI_NOFILEVERIFYFLAGS	= (1 << 16),

+      RPMFI_NOFILEFLAGS		= (1 << 17),

+      RPMFI_NOFILESIGNATURES	= (1 << 18),

+ +    RPMFI_NOVERITYSIGNATURES	= (1 << 19),

+  };

+  

+  typedef rpmFlags rpmfiFlags;

+ @@ -442,6 +443,15 @@ const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *le

+   */

+  const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);

+  

+ +/** \ingroup rpmfiles

+ + * Return file verity signature (binary)

+ + * @param fi            file info set

+ + * @param ix            file index

+ + * @retval len       signature length (pass NULL to ignore)

+ + * @return              verity signature, NULL on invalid

+ + */

+ +const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);

+ +

+  /** \ingroup rpmfiles

+   * Return file rdev from file info set.

+   * @param fi		file info set

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 3bb23a18d..177561957 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -15,6 +15,7 @@

+  #include "lib/rpmtypes.h"	/* rpmRC */

+  #include <libfsverity.h>

+  #include "rpmio/rpmio_internal.h"

+ +#include "rpmio/rpmbase64.h"

+  #include "lib/rpmvs.h"

+  

+  #include "sign/rpmsignverity.h"

+ @@ -40,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      struct libfsverity_signature_params sig_params;

+      struct libfsverity_digest *digest = NULL;

+      rpm_loff_t file_size;

+ -    char *digest_hex, *sig_hex = NULL;

+ +    char *digest_hex, *digest_base64, *sig_base64 = NULL, *sig_hex = NULL;

+      uint8_t *sig = NULL;

+      int status;

+  

+ @@ -60,8 +61,14 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      }

+  

+      digest_hex = pgpHexStr(digest->digest, digest->digest_size);

+ -    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),

+ -	   digest->digest_size, digest_hex);

+ +    digest_base64 = rpmBase64Encode(digest->digest, digest->digest_size, -1);

+ +    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest(%i): %s, idx %i\n"),

+ +	   file_size, rpmfiFN(fi), digest->digest_size, digest_hex,

+ +	   rpmfiFX(fi));

+ +    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest sz (%i): base64 sz (%li), %s, idx %i\n"),

+ +	   file_size, rpmfiFN(fi), digest->digest_size, strlen(digest_base64),

+ +	   digest_base64, rpmfiFX(fi));

+ +

+      free(digest_hex);

+  

+      memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));

+ @@ -73,10 +80,15 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      }

+  

+      sig_hex = pgpHexStr(sig, *sig_size);

+ +    sig_base64 = rpmBase64Encode(sig, *sig_size, -1);

+ +    rpmlog(RPMLOG_DEBUG, _("%s: sig_size(%li), base64_size(%li), idx %i: signature:\n%s\n"),

+ +	   rpmfiFN(fi), *sig_size, strlen(sig_base64), rpmfiFX(fi), sig_hex);

+   out:

+ +    free(sig_hex);

+ +

+      free(digest);

+      free(sig);

+ -    return sig_hex;

+ +    return sig_base64;

+  }

+  

+  rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,393 @@ 

+ From a2c959085250d186c54130b78af076095c3d3cd3 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Tue, 15 Feb 2022 09:11:33 -0800

+ Subject: [PATCH 23/30] [rpm2extents] Improve logging

+ 

+ ```

+ $ ls -l tests/data/RPMS/hello-2.0-1.x86_64.rpm

+ -rw-r--r--. 1 chantra chantra 9915 Jan 19 09:10 tests/data/RPMS/hello-2.0-1.x86_64.rpm

+ $ cp tests/data/RPMS/hello-2.0-1.x86_64.rpm ~/trunc-hello-2.0-1.x86_64.rpm

+ $ truncate -s 9000 ~/trunc-hello-2.0-1.x86_64.rpm

+ $ ls -l ~/trunc-hello-2.0-1.x86_64.rpm

+ -rw-r--r--. 1 chantra chantra 9000 Feb 15 09:13 /home/chantra/trunc-hello-2.0-1.x86_64.rpm

+ $ cat ~/trunc-hello-2.0-1.x86_64.rpm| ./rpm2extents SHA256 > /dev/null

+ error: rpmfiArchiveReadToFile failed while extracting "/usr/bin/hello" with RC -32784: cpio: read failed - Illegal seek

+ error: Package processor failed: -32784

+ error: Unable to write input length 9000: 32, Broken pipe

+ error: Failed to write digests: 32, Broken pipe

+ error: Validator failed with RC 2

+ ```

+ Before:

+ ```

+ $ cat ~/trunc-hello-2.0-1.x86_64.rpm| ./rpm2extents SHA256 > /dev/null

+ rpmfiArchiveReadToFile failed with -32784

+ Validator failed

+ Unable to write input length 9000

+ Failed to write digestsValidator failed

+ ```

+ ---

+  rpm2extents.c | 120 ++++++++++++++++++++++++++++++--------------------

+  1 file changed, 72 insertions(+), 48 deletions(-)

+ 

+ diff --git a/rpm2extents.c b/rpm2extents.c

+ index a326e3857..e1a19fedb 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -84,13 +84,15 @@ static int FDWriteDigests(

+  

+      len = sizeof(fdilength);

+      if (Fwrite(&fdilength, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);

+ +	rpmlog(RPMLOG_ERR, _("Unable to write input length %zd: %d, %s\n"),

+ +	       fdilength, errno, strerror(errno));

+  	goto exit;

+      }

+      len = sizeof(algos_len);

+      if (Fwrite(&algos_len, len, 1, fdo) != len) {

+  	algo_digest_len = (uint32_t)filedigest_len;

+ -	fprintf(stderr, _("Unable to write number of digests\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write number of digests: %d, %s\n"),

+ +	       errno, strerror(errno));

+  	goto exit;

+      }

+      for (algo = 0; algo < algos_len; algo++) {

+ @@ -102,24 +104,28 @@ static int FDWriteDigests(

+  

+  	len = sizeof(algo_name_len);

+  	if (Fwrite(&algo_name_len, len, 1, fdo) != len) {

+ -	    fprintf(stderr,

+ -		    _("Unable to write digest algo name length\n"));

+ +	    rpmlog(RPMLOG_ERR,

+ +		   _("Unable to write digest algo name length: %d, %s\n"),

+ +		   errno, strerror(errno));

+  	    goto exit;

+  	}

+  	len = sizeof(algo_digest_len);

+  	if (Fwrite(&algo_digest_len, len, 1, fdo) != len) {

+ -	    fprintf(stderr,

+ -		    _("Unable to write number of bytes for digest\n"));

+ +	    rpmlog(RPMLOG_ERR,

+ +		   _("Unable to write number of bytes for digest: %d, %s\n"),

+ +		   errno, strerror(errno));

+  	     goto exit;

+  	}

+  	if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) {

+ -	    fprintf(stderr, _("Unable to write digest algo name\n"));

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write digest algo name: %d, %s\n"),

+ +		   errno, strerror(errno));

+  	    goto exit;

+  	}

+  	if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) {

+ -	    fprintf(stderr,

+ -		    _("Unable to write digest value %u, %zu\n"),

+ -		    algo_digest_len, filedigest_len);

+ +	    rpmlog(RPMLOG_ERR,

+ +		   _("Unable to write digest value %u, %zu: %d, %s\n"),

+ +		   algo_digest_len, filedigest_len,

+ +		   errno, strerror(errno));

+  	    goto exit;

+  	}

+      }

+ @@ -133,22 +139,29 @@ static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) {

+      rpmRC rc = RPMRC_FAIL;

+  

+      if(rpmvsrc){

+ -	fprintf(stderr, _("Error verifying package signatures\n"));

+ +	rpmlog(RPMLOG_WARNING,

+ +	       _("Error verifying package signatures:\n%s\n"), msg);

+      }

+  

+      len = sizeof(rpmvsrc);

+      if (Fwrite(&rpmvsrc, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write signature verification RC code %d\n"), rpmvsrc);

+ +	rpmlog(RPMLOG_ERR,

+ +	       _("Unable to write signature verification RC code %d: %d, %s\n"),

+ +	       rpmvsrc, errno, strerror(errno));

+  	goto exit;

+      }

+      size_t content_len = msg ? strlen(msg) : 0;

+      len = sizeof(content_len);

+      if (Fwrite(&content_len, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write signature verification output length %zd\n"), content_len);

+ +	rpmlog(RPMLOG_ERR,

+ +	       _("Unable to write signature verification output length %zd: %d, %s\n"),

+ +	       content_len, errno, strerror(errno));

+  	goto exit;

+      }

+      if (Fwrite(msg, content_len, 1, fdo) != content_len) {

+ -	fprintf(stderr, _("Unable to write signature verification output %s\n"), msg);

+ +	rpmlog(RPMLOG_ERR,

+ +	       _("Unable to write signature verification output %s: %d, %s\n"),

+ +	       msg, errno, strerror(errno));

+  	goto exit;

+      }

+  

+ @@ -174,12 +187,16 @@ static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo,

+  

+      // Write result of digest computation

+      if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) {

+ -	fprintf(stderr, _("Failed to write digests"));

+ +	rpmlog(RPMLOG_ERR, _("Failed to write digests: %d, %s\n"),

+ +	       errno, strerror(errno));

+  	goto exit;

+      }

+  

+      // Write result of signature validation.

+      if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) {

+ +	rpmlog(RPMLOG_ERR,

+ +	       _("Failed to write signature verification result: %d, %s\n"),

+ +	       errno, strerror(errno));

+  	goto exit;

+      }

+      rc = RPMRC_OK;

+ @@ -226,24 +243,24 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      fdo = fdDup(STDOUT_FILENO);

+  

+      if (rpmReadPackageRaw(fdi, &sigh, &h)) {

+ -	fprintf(stderr, _("Error reading package\n"));

+ +	rpmlog(RPMLOG_ERR, _("Error reading package\n"));

+  	exit(EXIT_FAILURE);

+      }

+  

+      if (rpmLeadWrite(fdo, h))

+      {

+ -	fprintf(stderr, _("Unable to write package lead: %s\n"),

+ +	rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),

+  		Fstrerror(fdo));

+  	exit(EXIT_FAILURE);

+      }

+  

+      if (rpmWriteSignature(fdo, sigh)) {

+ -	fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), Fstrerror(fdo));

+  	exit(EXIT_FAILURE);

+      }

+  

+      if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {

+ -	fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), Fstrerror(fdo));

+  	exit(EXIT_FAILURE);

+      }

+  

+ @@ -257,7 +274,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      free(rpmio_flags);

+  

+      if (gzdi == NULL) {

+ -	fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));

+ +	rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));

+  	exit(EXIT_FAILURE);

+      }

+  

+ @@ -300,7 +317,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	}

+  	pad = pad_to(pos, fundamental_block_size);

+  	if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {

+ -	    fprintf(stderr, _("Unable to write padding\n"));

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ @@ -313,7 +330,12 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	size = rpmfiFSize(fi);

+  	rc = rpmfiArchiveReadToFile(fi, fdo, 0);

+  	if (rc != RPMRC_OK) {

+ -	    fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);

+ +	    char *errstr = rpmfileStrerror(rc);

+ +	    rpmlog(RPMLOG_ERR,

+ +		   _("rpmfiArchiveReadToFile failed while extracting "\

+ +		   "\"%s\" with RC %d: %s\n"),

+ +		   rpmfiFN(fi), rc, errstr);

+ +	    free(errstr);

+  	    goto exit;

+  	}

+  	pos += size;

+ @@ -326,7 +348,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      validation_pos = pos;

+      ssize_t validation_len = ufdCopy(validationi, fdo);

+      if (validation_len == -1) {

+ -	fprintf(stderr, _("validation output ufdCopy failed\n"));

+ +	rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ @@ -335,25 +357,25 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  

+      len = sizeof(offset_ix);

+      if (Fwrite(&offset_ix, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write length of table\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write length of table\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      len = sizeof(diglen);

+      if (Fwrite(&diglen, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write length of digest\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      len = sizeof(rpm_loff_t);

+      for (int x = 0; x < offset_ix; x++) {

+  	if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {

+ -	    fprintf(stderr, _("Unable to write digest\n"));

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+  	if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {

+ -	    fprintf(stderr, _("Unable to write offset\n"));

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ @@ -365,7 +387,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  

+      ssize_t digest_len = ufdCopy(digestori, fdo);

+      if (digest_len == -1) {

+ -	fprintf(stderr, _("digest table ufdCopy failed\n"));

+ +	rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ @@ -378,30 +400,30 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +

+  		 sizeof(uint64_t)), fundamental_block_size);

+      if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {

+ -	fprintf(stderr, _("Unable to write final padding\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      zeros = _free(zeros);

+      if (Fwrite(&validation_pos, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write offset of validation output\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write offset of validation output\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      if (Fwrite(&digest_table_pos, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write offset of digest table\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write offset of digest table\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      if (Fwrite(&digest_pos, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write offset of validation table\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write offset of validation table\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+      extents_magic_t magic = EXTENTS_MAGIC;

+      len = sizeof(magic);

+      if (Fwrite(&magic, len, 1, fdo) != len) {

+ -	fprintf(stderr, _("Unable to write magic\n"));

+ +	rpmlog(RPMLOG_ERR, _("Unable to write magic\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ @@ -426,7 +448,9 @@ static off_t ufdTee(FD_t sfd, FD_t *fds, int len)

+  	    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]));

+ +		    rpmlog(RPMLOG_ERR,

+ +			   _("Error wriing to FD %d: %s\n"),

+ +			   i, Fstrerror(fds[i]));

+  		    total = -1;

+  		    break;

+  		}

+ @@ -460,22 +484,22 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {

+      FD_t fds[2];

+  

+       if (pipe(processorpipefd) == -1) {

+ -	fprintf(stderr, _("Processor pipe failure\n"));

+ +	rpmlog(RPMLOG_ERR, _("Processor pipe failure\n"));

+  	return RPMRC_FAIL;

+      }

+  

+      if (pipe(validatorpipefd) == -1) {

+ -	fprintf(stderr, _("Validator pipe failure\n"));

+ +	rpmlog(RPMLOG_ERR, _("Validator pipe failure\n"));

+  	return RPMRC_FAIL;

+      }

+  

+      if (pipe(meta_digestpipefd) == -1) {

+ -	fprintf(stderr, _("Meta digest pipe failure\n"));

+ +	rpmlog(RPMLOG_ERR, _("Meta digest pipe failure\n"));

+  	return RPMRC_FAIL;

+      }

+  

+      if (pipe(meta_rpmsignpipefd) == -1) {

+ -	fprintf(stderr, _("Meta rpm signature pipe failure\n"));

+ +	rpmlog(RPMLOG_ERR, _("Meta rpm signature pipe failure\n"));

+  	return RPMRC_FAIL;

+      }

+  

+ @@ -494,7 +518,7 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {

+  	close(meta_rpmsignpipefd[1]);

+  	rc = validator(fdi, digesto, sigo, algos, algos_len);

+  	if(rc != RPMRC_OK) {

+ -	    fprintf(stderr, _("Validator failed\n"));

+ +	    rpmlog(RPMLOG_ERR, _("Validator failed with RC %d\n"), rc);

+  	}

+  	Fclose(fdi);

+  	Fclose(digesto);

+ @@ -522,7 +546,7 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {

+  

+  	    rc = process_package(fdi, digestori, sigi);

+  	    if(rc != RPMRC_OK) {

+ -		fprintf(stderr, _("Validator failed\n"));

+ +		rpmlog(RPMLOG_ERR, _("Package processor failed: %d\n"), rc);

+  	    }

+  	    Fclose(digestori);

+  	    Fclose(sigi);

+ @@ -552,19 +576,19 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {

+  	    rc = RPMRC_OK;

+  	    offt = ufdTee(fdi, fds, 2);

+  	    if(offt == -1){

+ -		fprintf(stderr, _("Failed to tee RPM\n"));

+ +		rpmlog(RPMLOG_ERR, _("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"));

+ +		rpmlog(RPMLOG_ERR, _("waitpid cpids[0] failed\n"));

+  		rc = RPMRC_FAIL;

+  	    }

+  	    w = waitpid(cpids[1], &wstatus, 0);

+  	    if (w == -1) {

+ -		fprintf(stderr, _("waitpid cpids[1] failed\n"));

+ +		rpmlog(RPMLOG_ERR, _("waitpid cpids[1] failed\n"));

+  		rc = RPMRC_FAIL;

+  	    }

+  	}

+ @@ -585,8 +609,8 @@ int main(int argc, char *argv[]) {

+      poptSetOtherOptionHelp(optCon, "[OPTIONS]* <DIGESTALGO>");

+  

+      if (poptPeekArg(optCon) == NULL) {

+ -	fprintf(stderr,

+ -		_("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));

+ +	rpmlog(RPMLOG_ERR,

+ +	       _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));

+  	poptPrintUsage(optCon, stderr, 0);

+  	exit(EXIT_FAILURE);

+      }

+ @@ -598,9 +622,9 @@ int main(int argc, char *argv[]) {

+      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"),

+ -		    args[x]);

+ +	    rpmlog(RPMLOG_ERR,

+ +		   _("Unable to resolve '%s' as a digest algorithm, exiting\n"),

+ +		   args[x]);

+  	    exit(EXIT_FAILURE);

+  	}

+      }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,33 @@ 

+ From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Tue, 14 Apr 2020 10:33:32 -0400

+ Subject: [PATCH 24/33] Generate a zero-length signature for symlinks

+ 

+ The fsverity utility follows the symlink when generating a signature.

+ Since we don't want to sign the same file twice, we need to skip these

+ links, and instead just generate a dummy zero-length signature here.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  sign/rpmsignverity.c | 5 ++++-

+  1 file changed, 4 insertions(+), 1 deletion(-)

+ 

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 177561957..2c7d21620 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -45,7 +45,10 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      uint8_t *sig = NULL;

+      int status;

+  

+ -    file_size = rpmfiFSize(fi);

+ +    if (S_ISLNK(rpmfiFMode(fi)))

+ +	file_size = 0;

+ +    else

+ +	file_size = rpmfiFSize(fi);

+  

+      memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));

+      params.version = 1;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,200 @@ 

+ From aabaa6c6587c37b84a1b9cfd98bff31f1b69345e Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Wed, 16 Feb 2022 17:00:09 -0800

+ Subject: [PATCH 24/30] [rpm2extents] create footer struct and helpers

+ 

+ new extents_footer and extents_footer_offset struct with a function to

+ load offsets from an FD.

+ Change existing code to use new struct/functions

+ ---

+  lib/rpmchecksig.c         | 16 +++-------------

+  lib/rpmextents.c          | 26 +++++++++++++++++---------

+  lib/rpmextents_internal.h | 31 ++++++++++++++++++++++++++++++-

+  rpm2extents.c             | 23 ++++-------------------

+  4 files changed, 54 insertions(+), 42 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index dc1726a18..729f79f9f 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -223,29 +223,19 @@ exit:

+  

+  static int rpmpkgVerifySigsTranscoded(FD_t fd){

+      rpm_loff_t current;

+ -    uint64_t magic;

+ -    rpm_loff_t offset;

+      int32_t rc;

+      size_t len;

+      uint64_t content_len;

+      char *content = NULL;

+ +    struct extents_footer_t footer;

+  

+      current = Ftell(fd);

+  

+ -    if(Fseek(fd, -(sizeof(magic) + 3 * sizeof(offset) ), SEEK_END) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: failed to seek for offset\n"));

+ +    if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) {

+  	rc = -1;

+  	goto exit;

+      }

+ -

+ -    len = sizeof(offset);

+ -    if (Fread(&offset, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification offset\n"));

+ -	rc = -1;

+ -	goto exit;

+ -    }

+ -

+ -    if(Fseek(fd,  offset, SEEK_SET) < 0) {

+ +    if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) {

+  	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n"));

+  	rc = -1;

+  	goto exit;

+ diff --git a/lib/rpmextents.c b/lib/rpmextents.c

+ index 015277751..46b7aadff 100644

+ --- a/lib/rpmextents.c

+ +++ b/lib/rpmextents.c

+ @@ -3,13 +3,16 @@

+  

+  #include <rpm/rpmlog.h>

+  #include <rpm/rpmio.h>

+ +#include <string.h>

+ +#include <errno.h>

+ +

+  

+  #include "lib/rpmextents_internal.h"

+  

+ -rpmRC isTranscodedRpm(FD_t fd) {

+ +rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) {

+ +

+      rpmRC rc = RPMRC_NOTFOUND;

+      rpm_loff_t current;

+ -    extents_magic_t magic;

+      size_t len;

+  

+      // If the file is not seekable, we cannot detect whether or not it is transcoded.

+ @@ -18,19 +21,19 @@ rpmRC isTranscodedRpm(FD_t fd) {

+      }

+      current = Ftell(fd);

+  

+ -    if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n"));

+ +    len = sizeof(struct extents_footer_t);

+ +    if(Fseek(fd, -len, SEEK_END) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for footer: %s\n"), strerror(errno));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ -    len = sizeof(magic);

+ -    if (Fread(&magic, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n"));

+ +    if (Fread(footer, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read footer\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ -    if (magic != EXTENTS_MAGIC) {

+ -	rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n"));

+ +    if (footer->magic != EXTENTS_MAGIC) {

+ +	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: not transcoded\n"));

+  	rc = RPMRC_NOTFOUND;

+  	goto exit;

+      }

+ @@ -43,4 +46,9 @@ exit:

+      return rc;

+  }

+  

+ +rpmRC isTranscodedRpm(FD_t fd) {

+ +    struct extents_footer_t footer;

+ +    return extentsFooterFromFD(fd, &footer);

+ +}

+ +

+  

+ diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h

+ index 57cecfc31..f0c29c807 100644

+ --- a/lib/rpmextents_internal.h

+ +++ b/lib/rpmextents_internal.h

+ @@ -7,6 +7,10 @@ extern "C" {

+  

+  #include <stdint.h>

+  

+ +/** \ingroup rpmextents

+ + * RPM extents library

+ + */

+ +

+  /* magic value at end of file (64 bits) that indicates this is a transcoded

+   * rpm.

+   */

+ @@ -14,9 +18,34 @@ extern "C" {

+  

+  typedef uint64_t extents_magic_t;

+  

+ +struct __attribute__ ((__packed__)) extents_footer_offsets_t {

+ +    off64_t checksig_offset;

+ +    off64_t table_offset;

+ +    off64_t csum_offset;

+ +};

+ +

+ +struct __attribute__ ((__packed__)) extents_footer_t {

+ +    struct extents_footer_offsets_t offsets;

+ +    extents_magic_t magic;

+ +};

+ +

+ +

+ +/** \ingroup rpmextents

+ + * Read the RPM Extents footer from a file descriptor.

+ + * @param fd		The FD_t of the transcoded RPM

+ + * @param[out] footer	A pointer to an allocated extents_footer_t with a copy of the footer.

+ + * @return		RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure.

+ + */

+ +rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer);

+ +

+ +/** \ingroup rpmextents

+ + * Check if a RPM is a transcoded RPM

+ + * @param fd	The FD_t of the transcoded RPM

+ + * return	RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure.

+ + */

+  rpmRC isTranscodedRpm(FD_t fd);

+  

+  #ifdef __cplusplus

+  }

+  #endif

+ -#endif

+ +#endif /* _RPMEXTENTS_INTERNAL_H */

+ diff --git a/rpm2extents.c b/rpm2extents.c

+ index e1a19fedb..7dd5128de 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -405,25 +405,10 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	goto exit;

+      }

+      zeros = _free(zeros);

+ -    if (Fwrite(&validation_pos, len, 1, fdo) != len) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write offset of validation output\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    if (Fwrite(&digest_table_pos, len, 1, fdo) != len) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write offset of digest table\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    if (Fwrite(&digest_pos, len, 1, fdo) != len) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write offset of validation table\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    extents_magic_t magic = EXTENTS_MAGIC;

+ -    len = sizeof(magic);

+ -    if (Fwrite(&magic, len, 1, fdo) != len) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write magic\n"));

+ +    struct extents_footer_t footer = {.offsets = {validation_pos, digest_table_pos, digest_pos}, .magic = EXTENTS_MAGIC};

+ +    len = sizeof(footer);

+ +    if (Fwrite(&footer, len, 1, fdo) != len) {

+ +	rpmlog(RPMLOG_ERR, _("Unable to write footer\n"));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,176 @@ 

+ From 8235711d92d8783abe63d6e4f29afd495fc4b22e Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Wed, 16 Feb 2022 23:21:14 -0800

+ Subject: [PATCH 25/30] [extents] move more functions/helpers behind

+  rpmextents_internal.h

+ 

+ ---

+  lib/rpmchecksig.c         | 58 ++-------------------------------------

+  lib/rpmextents.c          | 56 +++++++++++++++++++++++++++++++++++++

+  lib/rpmextents_internal.h |  6 ++++

+  3 files changed, 64 insertions(+), 56 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index 729f79f9f..5e8794e2d 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -221,61 +221,6 @@ exit:

+      return rc;

+  }

+  

+ -static int rpmpkgVerifySigsTranscoded(FD_t fd){

+ -    rpm_loff_t current;

+ -    int32_t rc;

+ -    size_t len;

+ -    uint64_t content_len;

+ -    char *content = NULL;

+ -    struct extents_footer_t footer;

+ -

+ -    current = Ftell(fd);

+ -

+ -    if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) {

+ -	rc = -1;

+ -	goto exit;

+ -    }

+ -    if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n"));

+ -	rc = -1;

+ -	goto exit;

+ -    }

+ -    len = sizeof(rc);

+ -    if (Fread(&rc, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification RC\n"));

+ -	rc = -1;

+ -	goto exit;

+ -    }

+ -

+ -    len = sizeof(content_len);

+ -    if (Fread(&content_len, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content length\n"));

+ -	goto exit;

+ -    }

+ -

+ -    content = malloc(content_len + 1);

+ -    if(content == NULL) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to allocate memory to read signature content\n"));

+ -	goto exit;

+ -    }

+ -    content[content_len] = 0;

+ -    if (Fread(content, content_len, 1, fd) != content_len) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content\n"));

+ -	goto exit;

+ -    }

+ -

+ -    rpmlog(RPMLOG_NOTICE, "%s", content);

+ -exit:

+ -    if(content){

+ -	free(content);

+ -    }

+ -    if (Fseek(fd, current, SEEK_SET) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: unable to seek back to original location\n"));

+ -    }

+ -    return rc;

+ -

+ -}

+ -

+  static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+  			   FD_t fd, const char *fn)

+  {

+ @@ -289,8 +234,9 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+      rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : "");

+  

+      if(isTranscodedRpm(fd) == RPMRC_OK){

+ -	return rpmpkgVerifySigsTranscoded(fd);

+ +	return extentsVerifySigs(fd);

+      }

+ +

+      struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+  

+      rc = rpmpkgRead(vs, fd, NULL, NULL, &msg);

+ diff --git a/lib/rpmextents.c b/lib/rpmextents.c

+ index 46b7aadff..f28596f0b 100644

+ --- a/lib/rpmextents.c

+ +++ b/lib/rpmextents.c

+ @@ -9,6 +9,62 @@

+  

+  #include "lib/rpmextents_internal.h"

+  

+ +

+ +int extentsVerifySigs(FD_t fd){

+ +    rpm_loff_t current;

+ +    int32_t rc;

+ +    size_t len;

+ +    uint64_t content_len;

+ +    char *content = NULL;

+ +    struct extents_footer_t footer;

+ +

+ +    current = Ftell(fd);

+ +

+ +    if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) {

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +    if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to seek signature verification offset\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +    len = sizeof(rc);

+ +    if (Fread(&rc, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read Signature Verification RC\n"));

+ +	rc = -1;

+ +	goto exit;

+ +    }

+ +

+ +    len = sizeof(content_len);

+ +    if (Fread(&content_len, len, 1, fd) != len) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n"));

+ +	goto exit;

+ +    }

+ +

+ +    content = rmalloc(content_len + 1);

+ +    if(content == NULL) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n"));

+ +	goto exit;

+ +    }

+ +    content[content_len] = 0;

+ +    if (Fread(content, content_len, 1, fd) != content_len) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n"));

+ +	goto exit;

+ +    }

+ +

+ +    rpmlog(RPMLOG_NOTICE, "%s", content);

+ +exit:

+ +    if(content){

+ +	rfree(content);

+ +    }

+ +    if (Fseek(fd, current, SEEK_SET) < 0) {

+ +	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: unable to seek back to original location\n"));

+ +    }

+ +    return rc;

+ +

+ +}

+ +

+  rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) {

+  

+      rpmRC rc = RPMRC_NOTFOUND;

+ diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h

+ index f0c29c807..380c08425 100644

+ --- a/lib/rpmextents_internal.h

+ +++ b/lib/rpmextents_internal.h

+ @@ -29,6 +29,12 @@ struct __attribute__ ((__packed__)) extents_footer_t {

+      extents_magic_t magic;

+  };

+  

+ +/** \ingroup rpmextents

+ + * Checks the results of the signature verification ran during transcoding.

+ + * @param fd	The FD_t of the transcoded RPM

+ + * @return	The number of checks that `rpmvsVerify` failed during transcoding.

+ + */

+ +int extentsVerifySigs(FD_t fd);

+  

+  /** \ingroup rpmextents

+   * Read the RPM Extents footer from a file descriptor.

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,40 @@ 

+ From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Tue, 14 Apr 2020 12:08:09 -0400

+ Subject: [PATCH 25/33] rpmsignverity.c: Clean up debug logging

+ 

+ Put most logging in one place and avoid printing the same info twice.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  sign/rpmsignverity.c | 5 -----

+  1 file changed, 5 deletions(-)

+ 

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 2c7d21620..445e1197c 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -104,7 +104,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);

+      rpmts ts = rpmtsCreate();

+      struct rpmtd_s td;

+ -    rpm_loff_t file_size;

+      off_t offset = Ftell(fd);

+      const char *compr;

+      char *rpmio_flags = NULL;

+ @@ -158,12 +157,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+  	   nr_files, rpmfiFC(fi));

+  

+      while (rpmfiNext(fi) >= 0) {

+ -	file_size = rpmfiFSize(fi);

+  	idx = rpmfiFX(fi);

+  

+ -	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),

+ -	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));

+ -

+  	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);

+      }

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,25 @@ 

+ From 3372e6c917e54b3a84c04ca4274000da04a98e86 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Thu, 17 Feb 2022 08:54:47 -0800

+ Subject: [PATCH 26/30] fix integer underflow in vfyFDCb

+ 

+ ---

+  lib/rpmchecksig.c | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index 5e8794e2d..7ad4e7034 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -345,7 +345,7 @@ static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata)

+      struct vfydatafd_s *vd = cbdata;

+      char *vmsg, *msg;

+      size_t n;

+ -    size_t remainder = BUFSIZ - vd->len;

+ +    size_t remainder = BUFSIZ - vd->len >= 0 ? BUFSIZ - vd->len : 0;

+  

+      vmsg = rpmsinfoMsg(sinfo);

+      rasprintf(&msg, "    %s\n", vmsg);

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,161 @@ 

+ From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 20 Apr 2020 13:40:26 -0400

+ Subject: [PATCH 26/33] fsverity - add tag for fsverity algorithm

+ 

+ The default algorith is SHA256, but fsverity allows for other

+ algorithms, so add a tag to handle this.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/package.c        |  1 +

+  lib/rpmfi.c          |  2 ++

+  lib/rpmtag.h         |  2 ++

+  sign/rpmsignverity.c | 32 ++++++++++++++++++++++++++++----

+  4 files changed, 33 insertions(+), 4 deletions(-)

+ 

+ diff --git a/lib/package.c b/lib/package.c

+ index c6108f686..3c761d365 100644

+ --- a/lib/package.c

+ +++ b/lib/package.c

+ @@ -46,6 +46,7 @@ struct taglate_s {

+      { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },

+      { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },

+      { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },

+ +    { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 },

+      { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },

+      { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },

+      { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },

+ diff --git a/lib/rpmfi.c b/lib/rpmfi.c

+ index 5fdbe02a2..70f05f509 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -118,6 +118,7 @@ struct rpmfiles_s {

+      int digestalgo;		/*!< File digest algorithm */

+      uint32_t *signatureoffs;	/*!< File signature offsets */

+      int veritysiglength;	/*!< Verity signature length */

+ +    uint16_t verityalgo;	/*!< Verity algorithm */

+      unsigned char * digests;	/*!< File digests in binary. */

+      unsigned char * signatures; /*!< File signatures in binary. */

+      unsigned char * veritysigs; /*!< Verity signatures in binary. */

+ @@ -1667,6 +1668,7 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)

+  

+      fi->veritysigs = NULL;

+      if (!(flags & RPMFI_NOVERITYSIGNATURES)) {

+ +	fi->verityalgo = headerGetNumber(h, RPMTAG_VERITYSIGNATUREALGO);

+  	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,

+  				  totalfc, &fi->veritysiglength);

+      }

+ diff --git a/lib/rpmtag.h b/lib/rpmtag.h

+ index 478457ecb..8d1efcc79 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -68,6 +68,7 @@ typedef enum rpmTag_e {

+      /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */

+      /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */

+      RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */

+ +    RPMTAG_VERITYSIGNATUREALGO	= RPMTAG_SIG_BASE+21,	/* i */

+  

+      RPMTAG_NAME  		= 1000,	/* s */

+  #define	RPMTAG_N	RPMTAG_NAME	/* s */

+ @@ -431,6 +432,7 @@ typedef enum rpmSigTag_e {

+      RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,

+      RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,

+      RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,

+ +    RPMSIGTAG_VERITYSIGNATUREALGO	= RPMTAG_VERITYSIGNATUREALGO,

+  } rpmSigTag;

+  

+  

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 445e1197c..55096e732 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -35,7 +35,7 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)

+  }

+  

+  static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+ -			       char *keypass, char *cert)

+ +			       char *keypass, char *cert, uint16_t algo)

+  {

+      struct libfsverity_merkle_tree_params params;

+      struct libfsverity_signature_params sig_params;

+ @@ -52,7 +52,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+  

+      memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));

+      params.version = 1;

+ -    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ +    params.hash_algorithm = algo;

+      params.block_size = RPM_FSVERITY_BLKSZ;

+      params.salt_size = 0 /* salt_size */;

+      params.salt = NULL /* salt */;

+ @@ -111,6 +111,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      char **signatures = NULL;

+      size_t sig_size;

+      int nr_files, idx;

+ +    uint16_t algo;

+ +    uint32_t algo32;

+  

+      Fseek(fd, 0, SEEK_SET);

+      rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |

+ @@ -142,6 +144,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+       * Should this be sigh from the cloned fd or the sigh we received?

+       */

+      headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);

+ +    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);

+  

+      /*

+       * The payload doesn't include special files, like ghost files, and

+ @@ -153,20 +156,24 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      nr_files = rpmfiFC(hfi);

+      signatures = xcalloc(nr_files, sizeof(char *));

+  

+ +    algo = FS_VERITY_HASH_ALG_SHA256;

+ +

+      rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),

+  	   nr_files, rpmfiFC(fi));

+  

+      while (rpmfiNext(fi) >= 0) {

+  	idx = rpmfiFX(fi);

+  

+ -	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);

+ +	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert,

+ +					    algo);

+      }

+  

+      while (rpmfiNext(hfi) >= 0) {

+  	idx = rpmfiFX(hfi);

+  	if (signatures[idx])

+  	    continue;

+ -	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);

+ +	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert,

+ +					    algo);

+      }

+  

+      rpmtdReset(&td);

+ @@ -187,6 +194,23 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+  	signatures[idx] = NULL;

+      }

+  

+ +    if (sig_size == 0) {

+ +	rpmlog(RPMLOG_ERR, _("Zero length fsverity signature\n"));

+ +	rc = RPMRC_FAIL;

+ +	goto out;

+ +    }

+ +

+ +    rpmtdReset(&td);

+ +

+ +    /* RPM doesn't like new 16 bit types, so use a 32 bit tag */

+ +    algo32 = algo;

+ +    rpmtdReset(&td);

+ +    td.tag = RPMSIGTAG_VERITYSIGNATUREALGO;

+ +    td.type = RPM_INT32_TYPE;

+ +    td.data = &algo32;

+ +    td.count = 1;

+ +    headerPut(sigh, &td, HEADERPUT_DEFAULT);

+ +

+      rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));

+  

+      rc = RPMRC_OK;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,257 @@ 

+ From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 20 Apr 2020 11:11:25 -0400

+ Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures

+ 

+ This plugin installs fsverity signatures for regular files, when a signature

+ is found in the RPM. It tries to enable them unconditionally, but fails

+ gracefully if fsverity isn't supported or enabled.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  configure.ac        |  29 ++++++++

+  macros.in           |   4 +

+  plugins/Makefile.am |   7 ++

+  plugins/fsverity.c  | 177 ++++++++++++++++++++++++++++++++++++++++++++

+  4 files changed, 217 insertions(+)

+  create mode 100644 plugins/fsverity.c

+ 

+ diff --git a/configure.ac b/configure.ac

+ index cc7144440..7d3c31831 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -1049,6 +1049,11 @@ AS_IF([test "$enable_plugins" != no],[

+  ])

+  AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])

+  

+ +AS_IF([test "$enable_plugins" != no],[

+ +AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"])

+ +])

+ +AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes])

+ +

+  #=================

+  # Check for fapolicyd support

+  AC_ARG_WITH(fapolicyd,

+ diff --git a/macros.in b/macros.in

+ index fe8862903..3c722146b 100644

+ --- a/macros.in

+ +++ b/macros.in

+ @@ -767,6 +767,9 @@ package or when debugging this package.\

+  # a wrong or missing signature.

+  #%_ima_sign_config_files	0

+  

+ +# Set to 1 to have fsverity signatures written for %config files.

+ +#%_fsverity_sign_config_files	0

+ +

+  #

+  # Default output format string for rpm -qa

+  #

+ @@ -1185,6 +1188,7 @@ package or when debugging this package.\

+  %__transaction_syslog		%{__plugindir}/syslog.so

+  %__transaction_ima		%{__plugindir}/ima.so

+  %__transaction_fapolicyd	%{__plugindir}/fapolicyd.so

+ +%__transaction_fsverity		%{__plugindir}/fsverity.so

+  %__transaction_prioreset	%{__plugindir}/prioreset.so

+  %__transaction_audit		%{__plugindir}/audit.so

+  

+ diff --git a/plugins/Makefile.am b/plugins/Makefile.am

+ index cbfb81e19..e51b71f62 100644

+ --- a/plugins/Makefile.am

+ +++ b/plugins/Makefile.am

+ @@ -48,3 +48,10 @@ audit_la_sources = audit.c

+  audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@

+  plugins_LTLIBRARIES += audit.la

+  endif

+ +

+ +if FSVERITY_IOCTL

+ +fsverity_la_sources = fsverity.c

+ +fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la

+ +plugins_LTLIBRARIES += fsverity.la

+ +endif

+ +

+ diff --git a/plugins/fsverity.c b/plugins/fsverity.c

+ new file mode 100644

+ index 000000000..15ddcf33e

+ --- /dev/null

+ +++ b/plugins/fsverity.c

+ @@ -0,0 +1,177 @@

+ +/**

+ + * Copyright (C) 2020 Facebook

+ + *

+ + * Author: Jes Sorensen <jsorensen@fb.com>

+ + */

+ +

+ +#include "system.h"

+ +

+ +#include <errno.h>

+ +#include <fcntl.h>

+ +#include <sys/ioctl.h>

+ +#include <linux/fsverity.h>

+ +

+ +#include <rpm/rpmfi.h>

+ +#include <rpm/rpmte.h>

+ +#include <rpm/rpmfiles.h>

+ +#include <rpm/rpmtypes.h>

+ +#include <rpm/rpmlog.h>

+ +#include <rpmio/rpmstring.h>

+ +#include <rpmio/rpmmacro.h>

+ +

+ +#include "lib/rpmfs.h"

+ +#include "lib/rpmplugin.h"

+ +#include "lib/rpmte_internal.h"

+ +

+ +#include "sign/rpmsignverity.h"

+ +

+ +static int sign_config_files = 0;

+ +

+ +/*

+ + * This unconditionally tries to apply the fsverity signature to a file,

+ + * but fails gracefully if the file system doesn't support it or the

+ + * verity feature flag isn't enabled in the file system (ext4).

+ + */

+ +static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+ +				       const char *path, const char *dest,

+ +				       mode_t file_mode, rpmFsmOp op)

+ +{

+ +    struct fsverity_enable_arg arg;

+ +    const unsigned char * signature = NULL;

+ +    size_t len;

+ +    int rc = RPMRC_OK;

+ +    int fd;

+ +    rpmFileAction action = XFO_ACTION(op);

+ +    char *buffer;

+ +

+ +    /* Ignore skipped files and unowned directories */

+ +    if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {

+ +	rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n",

+ +	       path, dest);

+ +	goto exit;

+ +    }

+ +

+ +    /*

+ +     * Do not install signatures for config files unless the

+ +     * user explicitly asks for it.

+ +     */

+ +    if (rpmfiFFlags(fi) & RPMFILE_CONFIG) {

+ +	if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) &&

+ +	    !sign_config_files) {

+ +	    rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n",

+ +		   path, dest);

+ +

+ +	    goto exit;

+ +	}

+ +    }

+ +

+ +    /*

+ +     * Right now fsverity doesn't deal with symlinks or directories, so do

+ +     * not try to install signatures for non regular files.

+ +     */

+ +    if (!S_ISREG(rpmfiFMode(fi))) {

+ +	rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n",

+ +	       path, dest);

+ +	goto exit;

+ +    }

+ +

+ +    signature = rpmfiVSignature(fi, &len);

+ +    if (!signature || !len) {

+ +	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",

+ +	       path, dest);

+ +	goto exit;

+ +    }

+ +

+ +    memset(&arg, 0, sizeof(arg));

+ +    arg.version = 1;

+ +    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ +    arg.block_size = RPM_FSVERITY_BLKSZ;

+ +    arg.sig_ptr = (uintptr_t)signature;

+ +    arg.sig_size = len;

+ +

+ +    buffer = pgpHexStr(signature, arg.sig_size);

+ +    rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer);

+ +    free(buffer);

+ +

+ +    fd = open(path, O_RDONLY);

+ +    if (fd < 0) {

+ +	rpmlog(RPMLOG_ERR, "failed to open path %s\n", path);

+ +	goto exit;

+ +    }

+ +

+ +    /*

+ +     * Enable fsverity on the file.

+ +     * fsverity not supported by file system (ENOTTY) and fsverity not

+ +     * enabled on file system are expected and not considered

+ +     * errors. Every other non-zero error code will result in the

+ +     * installation failing.

+ +     */

+ +    if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) {

+ +	switch(errno) {

+ +	case EBADMSG:

+ +	    rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case EEXIST:

+ +	    rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n",

+ +		   path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case EINVAL:

+ +	    rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case EKEYREJECTED:

+ +	    rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case EMSGSIZE:

+ +	    rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case ENOPKG:

+ +	    rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n",

+ +		   arg.hash_algorithm, path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case ETXTBSY:

+ +	    rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n",

+ +		   path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	case ENOTTY:

+ +	    rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n",

+ +		   path);

+ +	    break;

+ +	case EOPNOTSUPP:

+ +	    rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n",

+ +		   path);

+ +	    break;

+ +	default:

+ +	    rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n",

+ +		   errno, path);

+ +	    rc = RPMRC_FAIL;

+ +	    break;

+ +	}

+ +    }

+ +

+ +    rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n",

+ +	   path, dest);

+ +    close(fd);

+ +exit:

+ +    return rc;

+ +}

+ +

+ +static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts)

+ +{

+ +    sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}");

+ +

+ +    rpmlog(RPMLOG_DEBUG, "fsverity_init\n");

+ +

+ +    return RPMRC_OK;

+ +}

+ +

+ +struct rpmPluginHooks_s fsverity_hooks = {

+ +    .init = fsverity_init,

+ +    .fsm_file_prepare = fsverity_fsm_file_prepare,

+ +};

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,169 @@ 

+ From 1e0850cf7649578e1d7da815751efaa8101773e7 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Fri, 18 Feb 2022 11:29:06 -0800

+ Subject: [PATCH 27/30] [rpmchecksig] Refactor rpmpkgVerifySigs with custom

+  verify callback

+ 

+ The current `rpmpkgVerifySigs` was conflating logging and the actual

+ package verification.

+ 

+ This change makes it possible to pass the verify callback and its data to

+ `rpmpkgVerifySigs` so callers can customize how they handle the outcome

+ of signature verifications.

+ ---

+  lib/rpmchecksig.c | 78 ++++++++++++++++++++++-------------------------

+  lib/rpmextents.c  |  1 -

+  2 files changed, 36 insertions(+), 43 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index 7ad4e7034..c9fc3bbc9 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -222,16 +222,11 @@ exit:

+  }

+  

+  static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+ -			   FD_t fd, const char *fn)

+ +			   FD_t fd, rpmsinfoCb cb, void *cbdata)

+  {

+      char *msg = NULL;

+ -    struct vfydata_s vd = { .seen = 0,

+ -			    .bad = 0,

+ -			    .verbose = rpmIsVerbose(),

+ -    };

+      int rc;

+  

+ -    rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : "");

+  

+      if(isTranscodedRpm(fd) == RPMRC_OK){

+  	return extentsVerifySigs(fd);

+ @@ -244,19 +239,7 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+      if (rc)

+  	goto exit;

+  

+ -    rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);

+ -

+ -    if (!vd.verbose) {

+ -	if (vd.seen & RPMSIG_DIGEST_TYPE) {

+ -	    rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ?

+ -					_("DIGESTS") : _("digests"));

+ -	}

+ -	if (vd.seen & RPMSIG_SIGNATURE_TYPE) {

+ -	    rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?

+ -					_("SIGNATURES") : _("signatures"));

+ -	}

+ -	rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));

+ -    }

+ +    rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata);

+  

+  exit:

+      if (rc && msg)

+ @@ -266,38 +249,39 @@ exit:

+      return rc;

+  }

+  

+ -static int rpmpkgVerifySigsFD(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+ -			   FD_t fd, rpmsinfoCb cb, void *cbdata)

+ -{

+ -    char *msg = NULL;

+ -    int rc;

+ -    struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+ -

+ -    rc = rpmpkgRead(vs, fd, NULL, NULL, &msg);

+ -

+ -    if (rc)

+ -	goto exit;

+ -

+ -    rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata);

+ -

+ -exit:

+ -    if (rc && msg)

+ -	rpmlog(RPMLOG_ERR, "%s\n", msg);

+ -    rpmvsFree(vs);

+ -    free(msg);

+ -    return rc;

+ +static void rpmkgVerifySigsPreLogging(struct vfydata_s *vd, const char *fn){

+ +    rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd->verbose ? "\n" : "");

+  }

+  

+ +static void rpmkgVerifySigsPostLogging(struct vfydata_s *vd, int rc){

+ +    if (!vd->verbose) {

+ +	if (vd->seen & RPMSIG_DIGEST_TYPE) {

+ +	    rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_DIGEST_TYPE) ?

+ +					_("DIGESTS") : _("digests"));

+ +	}

+ +	if (vd->seen & RPMSIG_SIGNATURE_TYPE) {

+ +	    rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_SIGNATURE_TYPE) ?

+ +					_("SIGNATURES") : _("signatures"));

+ +	}

+ +	rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));

+ +    }

+ +}

+  

+  /* Wrapper around rpmkVerifySigs to preserve API */

+  int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)

+  {

+      int rc = 1; /* assume failure */

+ +    struct vfydata_s vd = { .seen = 0,

+ +			    .bad = 0,

+ +			    .verbose = rpmIsVerbose(),

+ +    };

+      if (ts && qva && fd && fn) {

+  	rpmKeyring keyring = rpmtsGetKeyring(ts, 1);

+  	rpmVSFlags vsflags = rpmtsVfyFlags(ts);

+  	int vfylevel = rpmtsVfyLevel(ts);

+ -	rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, fn);

+ +	rpmkgVerifySigsPreLogging(&vd, fn);

+ +	rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, vfyCb, &vd);

+ +	rpmkgVerifySigsPostLogging(&vd, rc);

+      	rpmKeyringFree(keyring);

+      }

+      return rc;

+ @@ -319,12 +303,22 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)

+  

+      while ((arg = *argv++) != NULL) {

+  	FD_t fd = Fopen(arg, "r.ufdio");

+ +	struct vfydata_s vd = { .seen = 0,

+ +				.bad = 0,

+ +				.verbose = rpmIsVerbose(),

+ +	};

+  	if (fd == NULL || Ferror(fd)) {

+  	    rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), 

+  		     arg, Fstrerror(fd));

+  	    res++;

+ -	} else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, arg)) {

+ +	} else {

+ +	    rpmkgVerifySigsPreLogging(&vd, arg);

+ +	    int rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd,

+ +				      vfyCb, &vd);

+ +	    rpmkgVerifySigsPostLogging(&vd, rc);

+ +	    if (rc) {

+  	    res++;

+ +	    }

+  	}

+  

+  	Fclose(fd);

+ @@ -373,7 +367,7 @@ int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg)

+  	rpmtsSetVfyLevel(ts, vfylevel);

+      }

+  

+ -    if (!rpmpkgVerifySigsFD(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) {

+ +    if (!rpmpkgVerifySigs(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) {

+  	rc = RPMRC_OK;

+      }

+      *msg = strdup(vd.msg);

+ diff --git a/lib/rpmextents.c b/lib/rpmextents.c

+ index f28596f0b..59ba427a4 100644

+ --- a/lib/rpmextents.c

+ +++ b/lib/rpmextents.c

+ @@ -89,7 +89,6 @@ rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) {

+  	goto exit;

+      }

+      if (footer->magic != EXTENTS_MAGIC) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: not transcoded\n"));

+  	rc = RPMRC_NOTFOUND;

+  	goto exit;

+      }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,116 @@ 

+ From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 20 Apr 2020 14:13:51 -0400

+ Subject: [PATCH 28/33] fsverity plugin: Use tag for algorithm

+ 

+ This uses the algorithm from the tag, if available. Fallback is SHA256.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  lib/rpmfi.c        | 9 ++++++---

+  lib/rpmfi.h        | 3 ++-

+  lib/rpmfiles.h     | 3 ++-

+  plugins/fsverity.c | 8 ++++++--

+  4 files changed, 16 insertions(+), 7 deletions(-)

+ 

+ diff --git a/lib/rpmfi.c b/lib/rpmfi.c

+ index 70f05f509..3e2b4e676 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -585,7 +585,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)

+      return signature;

+  }

+  

+ -const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)

+ +const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,

+ +					 uint16_t *algo)

+  {

+      const unsigned char *vsignature = NULL;

+  

+ @@ -594,6 +595,8 @@ const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)

+  	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);

+  	if (len)

+  	    *len = fi->veritysiglength;

+ +	if (algo)

+ +	    *algo = fi->verityalgo;

+      }

+      return vsignature;

+  }

+ @@ -1963,9 +1966,9 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)

+      return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);

+  }

+  

+ -const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)

+ +const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len, uint16_t *algo)

+  {

+ -    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);

+ +    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len, algo);

+  }

+  

+  uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)

+ diff --git a/lib/rpmfi.h b/lib/rpmfi.h

+ index fcb9d3acd..6fd2747d6 100644

+ --- a/lib/rpmfi.h

+ +++ b/lib/rpmfi.h

+ @@ -194,9 +194,10 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);

+   * Return current verity (binary) signature of file info set iterator.

+   * @param fi		file info set iterator

+   * @retval siglen	signature length (pass NULL to ignore)

+ + * @retval algo		fsverity algorithm

+   * @return		current verity signature, NULL on invalid

+   */

+ -const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);

+ +const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen, uint16_t *algo);

+  

+  /** \ingroup rpmfi

+   * Return current file linkto (i.e. symlink(2) target) from file info set iterator.

+ diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h

+ index 81b3d01a1..64b33281a 100644

+ --- a/lib/rpmfiles.h

+ +++ b/lib/rpmfiles.h

+ @@ -450,7 +450,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);

+   * @retval len       signature length (pass NULL to ignore)

+   * @return              verity signature, NULL on invalid

+   */

+ -const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);

+ +const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,

+ +					 uint16_t *algo);

+  

+  /** \ingroup rpmfiles

+   * Return file rdev from file info set.

+ diff --git a/plugins/fsverity.c b/plugins/fsverity.c

+ index 15ddcf33e..1e7f38b38 100644

+ --- a/plugins/fsverity.c

+ +++ b/plugins/fsverity.c

+ @@ -39,6 +39,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+      struct fsverity_enable_arg arg;

+      const unsigned char * signature = NULL;

+      size_t len;

+ +    uint16_t algo = 0;

+      int rc = RPMRC_OK;

+      int fd;

+      rpmFileAction action = XFO_ACTION(op);

+ @@ -75,7 +76,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+  	goto exit;

+      }

+  

+ -    signature = rpmfiVSignature(fi, &len);

+ +    signature = rpmfiVSignature(fi, &len, &algo);

+      if (!signature || !len) {

+  	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",

+  	       path, dest);

+ @@ -84,7 +85,10 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+  

+      memset(&arg, 0, sizeof(arg));

+      arg.version = 1;

+ -    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+ +    if (algo)

+ +	arg.hash_algorithm = algo;

+ +    else

+ +	arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;

+      arg.block_size = RPM_FSVERITY_BLKSZ;

+      arg.sig_ptr = (uintptr_t)signature;

+      arg.sig_size = len;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,117 @@ 

+ From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Fri, 25 Mar 2022 08:13:08 -0700

+ Subject: [PATCH 28/30] [reflink] remove requirement for executable stack flag

+ 

+ reflink was calling `bsearch` with a nested function comparator which

+ make GCC require the executable stack flag (see `man execstack`).

+ selinux prevents the use of this flag:

+ ```

+ error: Failed to dlopen /usr/lib64/rpm-plugins/reflink.so

+ /usr/lib64/rpm-plugins/reflink.so: cannot enable executable stack as

+ shared object requires: Permission denied

+ ```

+ 

+ To fix this, either rpm could be granted the correct selinux permission,

+ but this would open up execstack for more the whole rpm process.

+ Fundamentally, this is happening because there is no re-entrant version

+ of `bsearch`. We could probably use a global variable and be done with

+ it given that each rpm is processed sequencially, but that contract may

+ not hold true for ever.

+ Here we are copying stdlib's `bsearch` and making it re-entrant by

+ allowing to pass an void * data parameter where we can pass the key

+ size.

+ 

+ After applying this patch, when reflink.o is installed, it has the executable

+ flag cleared:

+ ```

+ - /usr/lib64/rpm-plugins/reflink.so

+ ```

+ ---

+  plugins/reflink.c | 60 +++++++++++++++++++++++++++++++++++++----------

+  1 file changed, 48 insertions(+), 12 deletions(-)

+ 

+ diff --git a/plugins/reflink.c b/plugins/reflink.c

+ index 4fc1d74d1..69e6b51e6 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -59,6 +59,50 @@ struct reflink_state_s {

+  

+  typedef struct reflink_state_s * reflink_state;

+  

+ +/*

+ + * bsearch_r: implements a re-entrant version of stdlib's bsearch.

+ + * code taken and adapted from /usr/include/bits/stdlib-bsearch.h

+ + */

+ +inline void *

+ +bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size,

+ +	 __compar_d_fn_t __compar, void *__arg)

+ +{

+ +  size_t __l, __u, __idx;

+ +  const void *__p;

+ +  int __comparison;

+ +

+ +  __l = 0;

+ +  __u = __nmemb;

+ +  while (__l < __u)

+ +    {

+ +      __idx = (__l + __u) / 2;

+ +      __p = (const void *) (((const char *) __base) + (__idx * __size));

+ +      __comparison = (*__compar) (__key, __p, __arg);

+ +      if (__comparison < 0)

+ +	__u = __idx;

+ +      else if (__comparison > 0)

+ +	__l = __idx + 1;

+ +      else

+ +	{

+ +#if __GNUC_PREREQ(4, 6)

+ +# pragma GCC diagnostic push

+ +# pragma GCC diagnostic ignored "-Wcast-qual"

+ +#endif

+ +	  return (void *) __p;

+ +#if __GNUC_PREREQ(4, 6)

+ +# pragma GCC diagnostic pop

+ +#endif

+ +	}

+ +    }

+ +

+ +  return NULL;

+ +}

+ +

+ +static int cmpdigest(const void *k1, const void *k2, void *data) {

+ +    rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);

+ +    return memcmp(k1, k2, *(int *)data);

+ +}

+ +

+  static int inodeCmp(rpm_ino_t a, rpm_ino_t b)

+  {

+      return (a != b);

+ @@ -198,21 +242,13 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)

+  rpm_loff_t find(const unsigned char *digest, reflink_state state);

+  

+  rpm_loff_t find(const unsigned char *digest, reflink_state state) {

+ -# if defined(__GNUC__)

+ -    /* GCC nested function because bsearch's comparison function can't access

+ -     * state-keysize otherwise

+ -     */

+ -    int cmpdigest(const void *k1, const void *k2) {

+ -	rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);

+ -	return memcmp(k1, k2, state->keysize);

+ -    }

+ -# endif

+      rpmlog(RPMLOG_DEBUG,

+ -	   _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"),

+ +	   _("reflink: bsearch_r(key=%p, base=%p, nmemb=%d, size=%lu)\n"),

+  	   digest, state->table, state->keys,

+  	   state->keysize + sizeof(rpm_loff_t));

+ -    char *entry = bsearch(digest, state->table, state->keys,

+ -			  state->keysize + sizeof(rpm_loff_t), cmpdigest);

+ +    char *entry = bsearch_r(digest, state->table, state->keys,

+ +			    state->keysize + sizeof(rpm_loff_t), cmpdigest,

+ +			    &state->keysize);

+      if (entry == NULL) {

+  	return NOT_FOUND;

+      }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,28 @@ 

+ From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 20 Apr 2020 18:52:08 -0400

+ Subject: [PATCH 29/33] Add fsverity tags to rpmgeneral.at

+ 

+ Make sure we pass the checks with the new tags in place.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  tests/rpmgeneral.at | 2 ++

+  1 file changed, 2 insertions(+)

+ 

+ diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at

+ index 45d38698b..8a7dc827f 100644

+ --- a/tests/rpmgeneral.at

+ +++ b/tests/rpmgeneral.at

+ @@ -291,6 +291,8 @@ VERBOSE

+  VERIFYSCRIPT

+  VERIFYSCRIPTFLAGS

+  VERIFYSCRIPTPROG

+ +VERITYSIGNATUREALGO

+ +VERITYSIGNATURES

+  VERSION

+  XPM

+  ])

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,109 @@ 

+ From 5753b178a08043316e6f3556754741cdd9cd19c5 Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Mon, 28 Mar 2022 14:00:13 -0700

+ Subject: [PATCH 29/30] [extentsVerifySigs] Make it optional to print the

+  signature verification output

+ 

+ ---

+  lib/rpmchecksig.c         |  2 +-

+  lib/rpmextents.c          | 39 ++++++++++++++++++++-------------------

+  lib/rpmextents_internal.h |  3 ++-

+  3 files changed, 23 insertions(+), 21 deletions(-)

+ 

+ diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c

+ index c9fc3bbc9..7f856154e 100644

+ --- a/lib/rpmchecksig.c

+ +++ b/lib/rpmchecksig.c

+ @@ -229,7 +229,7 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,

+  

+  

+      if(isTranscodedRpm(fd) == RPMRC_OK){

+ -	return extentsVerifySigs(fd);

+ +	return extentsVerifySigs(fd, 1);

+      }

+  

+      struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);

+ diff --git a/lib/rpmextents.c b/lib/rpmextents.c

+ index 59ba427a4..ac43264af 100644

+ --- a/lib/rpmextents.c

+ +++ b/lib/rpmextents.c

+ @@ -10,7 +10,7 @@

+  #include "lib/rpmextents_internal.h"

+  

+  

+ -int extentsVerifySigs(FD_t fd){

+ +int extentsVerifySigs(FD_t fd, int print_content){

+      rpm_loff_t current;

+      int32_t rc;

+      size_t len;

+ @@ -36,24 +36,26 @@ int extentsVerifySigs(FD_t fd){

+  	goto exit;

+      }

+  

+ -    len = sizeof(content_len);

+ -    if (Fread(&content_len, len, 1, fd) != len) {

+ -	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n"));

+ -	goto exit;

+ -    }

+ -

+ -    content = rmalloc(content_len + 1);

+ -    if(content == NULL) {

+ -	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n"));

+ -	goto exit;

+ +    if(print_content) {

+ +	len = sizeof(content_len);

+ +	if (Fread(&content_len, len, 1, fd) != len) {

+ +	    rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n"));

+ +	    goto exit;

+ +	}

+ +

+ +	content = rmalloc(content_len + 1);

+ +	if(content == NULL) {

+ +	    rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n"));

+ +	    goto exit;

+ +	}

+ +	content[content_len] = 0;

+ +	if (Fread(content, content_len, 1, fd) != content_len) {

+ +	    rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n"));

+ +	    goto exit;

+ +	}

+ +

+ +	rpmlog(RPMLOG_NOTICE, "%s", content);

+      }

+ -    content[content_len] = 0;

+ -    if (Fread(content, content_len, 1, fd) != content_len) {

+ -	rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n"));

+ -	goto exit;

+ -    }

+ -

+ -    rpmlog(RPMLOG_NOTICE, "%s", content);

+  exit:

+      if(content){

+  	rfree(content);

+ @@ -79,7 +81,6 @@ rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) {

+  

+      len = sizeof(struct extents_footer_t);

+      if(Fseek(fd, -len, SEEK_END) < 0) {

+ -	rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for footer: %s\n"), strerror(errno));

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h

+ index 380c08425..0a3318c8e 100644

+ --- a/lib/rpmextents_internal.h

+ +++ b/lib/rpmextents_internal.h

+ @@ -32,9 +32,10 @@ struct __attribute__ ((__packed__)) extents_footer_t {

+  /** \ingroup rpmextents

+   * Checks the results of the signature verification ran during transcoding.

+   * @param fd	The FD_t of the transcoded RPM

+ + * @param print_content Whether or not to print the result from rpmsig

+   * @return	The number of checks that `rpmvsVerify` failed during transcoding.

+   */

+ -int extentsVerifySigs(FD_t fd);

+ +int extentsVerifySigs(FD_t fd, int print_content);

+  

+  /** \ingroup rpmextents

+   * Read the RPM Extents footer from a file descriptor.

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,117 @@ 

+ From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Mon, 13 Apr 2020 18:24:31 -0400

+ Subject: [PATCH 30/33] Add --delfilesign flag to delete IMA and fsverity file

+  signatures

+ 

+ This allows a user to remove both types of file signatures from the

+ package. Previously there was no way to delete IMA signatures, only

+ replace them by first removing the package signature and then

+ resigning the package and the files.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  rpmsign.c        | 12 ++++++++++++

+  sign/rpmgensig.c | 17 ++++++++++++++++-

+  sign/rpmsign.h   |  9 +++++++++

+  3 files changed, 37 insertions(+), 1 deletion(-)

+ 

+ diff --git a/rpmsign.c b/rpmsign.c

+ index 074dd8b13..e43811e9f 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -14,6 +14,7 @@ enum modes {

+      MODE_ADDSIGN = (1 << 0),

+      MODE_RESIGN  = (1 << 1),

+      MODE_DELSIGN = (1 << 2),

+ +    MODE_DELFILESIGN = (1 << 3),

+  };

+  

+  static int mode = MODE_NONE;

+ @@ -35,6 +36,10 @@ static struct poptOption signOptsTable[] = {

+  	N_("sign package(s) (identical to --addsign)"), NULL },

+      { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,

+  	N_("delete package signatures"), NULL },

+ +#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+ +    { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode,

+ +      MODE_DELFILESIGN,	N_("delete IMA and fsverity file signatures"), NULL },

+ +#endif

+      { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),

+  	&sargs.signflags, RPMSIGN_FLAG_RPMV3,

+  	N_("create rpm v3 header+payload signatures") },

+ @@ -207,6 +212,13 @@ int main(int argc, char *argv[])

+  		ec++;

+  	}

+  	break;

+ +    case MODE_DELFILESIGN:

+ +	ec = 0;

+ +	while ((arg = poptGetArg(optCon)) != NULL) {

+ +	    if (rpmPkgDelFileSign(arg, &sargs) < 0)

+ +		ec++;

+ +	}

+ +	break;

+      case MODE_NONE:

+  	printUsage(optCon, stderr, 0);

+  	break;

+ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c

+ index 8d5c5858f..02cf0bc62 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -336,6 +336,14 @@ static void deleteSigs(Header sigh)

+      headerDel(sigh, RPMSIGTAG_PGP5);

+  }

+  

+ +static void deleteFileSigs(Header sigh)

+ +{

+ +    headerDel(sigh, RPMSIGTAG_FILESIGNATURELENGTH);

+ +    headerDel(sigh, RPMSIGTAG_FILESIGNATURES);

+ +    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);

+ +    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);

+ +}

+ +

+  static int haveSignature(rpmtd sigtd, Header h)

+  {

+      pgpDigParams sig1 = NULL;

+ @@ -580,7 +588,9 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	    goto exit;

+      }

+  

+ -    if (deleting) {	/* Nuke all the signature tags. */

+ +    if (deleting == 2) {	/* Nuke IMA + fsverity file signature tags. */

+ +	deleteFileSigs(sigh);

+ +    } else if (deleting) {	/* Nuke all the signature tags. */

+  	deleteSigs(sigh);

+      } else {

+  	/* Signature target containing header + payload */

+ @@ -745,3 +755,8 @@ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args)

+  {

+      return rpmSign(path, 1, 0);

+  }

+ +

+ +int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args)

+ +{

+ +    return rpmSign(path, 2, 0);

+ +}

+ diff --git a/sign/rpmsign.h b/sign/rpmsign.h

+ index 2b8a10a1a..5169741dd 100644

+ --- a/sign/rpmsign.h

+ +++ b/sign/rpmsign.h

+ @@ -44,6 +44,15 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args);

+   */

+  int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args);

+  

+ +

+ +/** \ingroup rpmsign

+ + * Delete file signature(s) from a package

+ + * @param path		path to package

+ + * @param args		signing parameters (or NULL for defaults)

+ + * @return		0 on success

+ + */

+ +int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args);

+ +

+  #ifdef __cplusplus

+  }

+  #endif

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,98 @@ 

+ From dc53b002bd3d03a21e9af406a9aff5e588710b5b Mon Sep 17 00:00:00 2001

+ From: chantra <chantr4@gmail.com>

+ Date: Mon, 28 Mar 2022 19:42:39 -0700

+ Subject: [PATCH 30/30] [rpmcow] Make rpm -i install package without the need

+  of --nodigest

+ 

+ When using transcoded files, the logic to check signature is different

+ and was done while the file was transcoded. This change the code path

+ used by `rpm -{i,U}` to check if the file is transcoded, and in such

+ cases, assume it was already verified.

+ ---

+  lib/transaction.c    | 29 ++++++++++++++++++-----------

+  tests/rpm2extents.at |  6 +++---

+  2 files changed, 21 insertions(+), 14 deletions(-)

+ 

+ diff --git a/lib/transaction.c b/lib/transaction.c

+ index 36c2a7a64..703e4140c 100644

+ --- a/lib/transaction.c

+ +++ b/lib/transaction.c

+ @@ -37,6 +37,7 @@

+  #include "lib/rpmfi_internal.h"	/* only internal apis */

+  #include "lib/rpmte_internal.h"	/* only internal apis */

+  #include "lib/rpmts_internal.h"

+ +#include "lib/rpmextents_internal.h"

+  #include "lib/rpmvs.h"

+  #include "rpmio/rpmhook.h"

+  #include "lib/rpmtriggers.h"

+ @@ -1286,19 +1287,25 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)

+  

+  	rpmtsNotify(ts, p, RPMCALLBACK_VERIFY_PROGRESS, oc++, total);

+  	FD_t fd = rpmtsNotify(ts, p, RPMCALLBACK_INST_OPEN_FILE, 0, 0);

+ -	if (fd != NULL) {

+ -	    prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg);

+ -	    rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);

+ +	if(fd != NULL && isTranscodedRpm(fd) == RPMRC_OK) {

+ +	    /* Transcoded RPMs are validated at transcoding time */

+ +	    prc = RPMRC_OK;

+ +	    verified = 1;

+ +	} else {

+ +	    if (fd != NULL) {

+ +		prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg);

+ +		rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);

+ +	    }

+ +	    if (prc == RPMRC_OK)

+ +		prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);

+ +

+ +	    /* Record verify result */

+ +	    if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK)

+ +		verified |= RPMSIG_SIGNATURE_TYPE;

+ +	    if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK)

+ +		verified |= RPMSIG_DIGEST_TYPE;

+  	}

+  

+ -	if (prc == RPMRC_OK)

+ -	    prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);

+ -

+ -	/* Record verify result */

+ -	if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK)

+ -	    verified |= RPMSIG_SIGNATURE_TYPE;

+ -	if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK)

+ -	    verified |= RPMSIG_DIGEST_TYPE;

+  	rpmteSetVerified(p, verified);

+  

+  	if (prc)

+ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at

+ index 5c66de7f6..5135c9cf8 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -102,7 +102,7 @@ AT_CHECK([

+  RPMDB_INIT

+  

+  runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null

+ -runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm

+ +runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm

+  test -f ${RPMTEST}/usr/bin/hello

+  ],

+  [0],

+ @@ -115,7 +115,7 @@ AT_KEYWORDS([reflink])

+  AT_CHECK([

+  RPMDB_INIT

+  

+ -runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $?

+ +runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $?

+  # Check that the file is properly installed in chroot

+  test -f ${RPMTEST}/usr/bin/hello

+  ],

+ @@ -132,7 +132,7 @@ RPMDB_INIT

+  

+  PKG=hlinktest-1.0-1.noarch.rpm

+  runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null

+ -runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG}

+ +runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG}

+  ],

+  [0],

+  [],

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,72 @@ 

+ From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Tue, 12 May 2020 13:42:34 -0400

+ Subject: [PATCH 31/33] Update man page for rpmsign

+ 

+ This documents the new arguments --signverity and --certpath required

+ to sign a package with fsverity signatures.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  doc/rpmsign.8 | 20 ++++++++++++++++++++

+  1 file changed, 20 insertions(+)

+ 

+ diff --git a/doc/rpmsign.8 b/doc/rpmsign.8

+ index f7ceae89b..a212746fe 100644

+ --- a/doc/rpmsign.8

+ +++ b/doc/rpmsign.8

+ @@ -9,6 +9,8 @@ rpmsign \- RPM Package Signing

+  

+  \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR

+  

+ +\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR

+ +

+  .SS "rpmsign-options"

+  .PP

+  [\fb--rpmv3\fR]

+ @@ -30,6 +32,12 @@ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode.

+  .PP

+  Delete all signatures from each package \fIPACKAGE_FILE\fR given.

+  

+ +\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR

+ +

+ +.PP

+ +Delete all IMA and fsverity file signatures from each package

+ +\fIPACKAGE_FILE\fR given.

+ +

+  .SS "SIGN OPTIONS"

+  .PP

+  .TP

+ @@ -44,12 +52,23 @@ signature verifiable with rpm < 4.14 or other interoperability reasons.

+  \fB--fskpath \fIKEY\fB\fR

+  Used with \fB--signfiles\fR, use file signing key \fIKey\fR.

+  .TP

+ +\fB--certpath \fICERT\fB\fR

+ +Used with \fB--signverity\fR, use file signing certificate \fICert\fR.

+ +.TP

+  \fB--signfiles\fR

+  Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must

+  be set to a supported algorithm before building the package. The

+  supported algorithms are SHA1, SHA256, SHA384, and SHA512, which are

+  represented as 2, 8, 9, and 10 respectively.  The file signing key (RSA

+  private key) must be set before signing the package, it can be configured on the command line with \fB--fskpath\fR or the macro %_file_signing_key.

+ +.TP

+ +\fB--signverity\fR

+ +Sign package files with fsverity signatures. The file signing key (RSA

+ +private key) and the signing certificate must be set before signing

+ +the package. The key can be configured on the command line with

+ +\fB--fskpath\fR or the macro %_file_signing_key, and the cert can be

+ +configured on the command line with \fB--certpath\fR or the macro

+ +%_file_signing_cert.

+  

+  .SS "USING GPG TO SIGN PACKAGES"

+  .PP

+ @@ -110,4 +129,5 @@ Jeff Johnson <jbj@redhat.com>

+  Erik Troan <ewt@redhat.com>

+  Panu Matilainen <pmatilai@redhat.com>

+  Fionnuala Gunter <fin@linux.vnet.ibm.com>

+ +Jes Sorensen <jsorensen@fb.com>

+  .fi

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,168 @@ 

+ From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Wed, 10 Jun 2020 12:30:54 -0400

+ Subject: [PATCH 32/33] rpmsign: Add argument to specify algorithm for fsverity

+  signatures

+ 

+ The argument --verity-algo can be used to specify the algorithm for

+ the fsverity signatures. If nothing is specified, this will default to

+ sha256. The available algorithms depend on libfsverity, currently

+ sha256 and sha512 are supported.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  doc/rpmsign.8        |  3 +++

+  rpmsign.c            |  7 +++++++

+  sign/rpmgensig.c     | 22 ++++++++++++++++++++--

+  sign/rpmsignverity.c |  6 +++---

+  sign/rpmsignverity.h |  2 +-

+  5 files changed, 34 insertions(+), 6 deletions(-)

+ 

+ diff --git a/doc/rpmsign.8 b/doc/rpmsign.8

+ index a212746fe..5165e39f9 100644

+ --- a/doc/rpmsign.8

+ +++ b/doc/rpmsign.8

+ @@ -55,6 +55,9 @@ Used with \fB--signfiles\fR, use file signing key \fIKey\fR.

+  \fB--certpath \fICERT\fB\fR

+  Used with \fB--signverity\fR, use file signing certificate \fICert\fR.

+  .TP

+ +\fB--verityalgo \fIALG\fB\fR

+ +Used with \fB--signverity\fR, to specify the signing algorithm. sha256 and sha512 are supported, with sha256 being the default if this argument is not specified. This can also be specified with the macro %_verity_algorithm

+ +.TP

+  \fB--signfiles\fR

+  Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must

+  be set to a supported algorithm before building the package. The

+ diff --git a/rpmsign.c b/rpmsign.c

+ index e43811e9f..12299379c 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -25,6 +25,7 @@ static char * fileSigningKey = NULL;

+  #endif

+  #ifdef WITH_FSVERITY

+  static char * fileSigningCert = NULL;

+ +static char * verityAlgorithm = NULL;

+  #endif

+  

+  static struct rpmSignArgs sargs = {NULL, 0, 0};

+ @@ -52,6 +53,9 @@ static struct poptOption signOptsTable[] = {

+      { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),

+  	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,

+  	N_("generate fsverity signatures for package(s) files"), NULL},

+ +    { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0,

+ +	N_("algorithm to use for verity signatures, default sha256"),

+ +	N_("<algorithm>") },

+      { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,

+  	N_("use file signing cert <cert>"),

+  	N_("<cert>") },

+ @@ -138,6 +142,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+      if (fileSigningCert) {

+  	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);

+      }

+ +    if (verityAlgorithm) {

+ +	rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL);

+ +    }

+  #endif

+  

+      if (flags_sign_files(sargs->signflags)) {

+ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c

+ index 02cf0bc62..b3b02828a 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -8,6 +8,10 @@

+  #include <sys/wait.h>

+  #include <popt.h>

+  #include <fcntl.h>

+ +#include <fcntl.h>

+ +#ifdef WITH_FSVERITY

+ +#include <libfsverity.h>

+ +#endif

+  

+  #include <rpm/rpmlib.h>			/* RPMSIGTAG & related */

+  #include <rpm/rpmmacro.h>

+ @@ -458,23 +462,37 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)

+  static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)

+  {

+  #ifdef WITH_FSVERITY

+ -    rpmRC rc;

+ +    rpmRC rc = RPMRC_OK;

+      char *key = rpmExpand("%{?_file_signing_key}", NULL);

+      char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);

+      char *cert = rpmExpand("%{?_file_signing_cert}", NULL);

+ +    char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL);

+ +    uint16_t algo = 0;

+  

+      if (rstreq(keypass, "")) {

+  	free(keypass);

+  	keypass = NULL;

+      }

+  

+ +    if (algorithm && strlen(algorithm) > 0) {

+ +	    algo = libfsverity_find_hash_alg_by_name(algorithm);

+ +	    rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"),

+ +		   algorithm, algo);

+ +	    if (!algo) {

+ +		    rpmlog(RPMLOG_ERR, _("Unsupported fsverity algorithm %s\n"),

+ +			   algorithm);

+ +		    rc = RPMRC_FAIL;

+ +		    goto out;

+ +	    }

+ +    }

+      if (key && cert) {

+ -	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);

+ +	    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo);

+      } else {

+  	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));

+  	rc = RPMRC_FAIL;

+      }

+  

+ + out:

+      free(keypass);

+      free(key);

+      free(cert);

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index 55096e732..e6c830cdc 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -95,7 +95,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+  }

+  

+  rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ -		    char *keypass, char *cert)

+ +		    char *keypass, char *cert, uint16_t algo)

+  {

+      int rc;

+      FD_t gzdi;

+ @@ -111,7 +111,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      char **signatures = NULL;

+      size_t sig_size;

+      int nr_files, idx;

+ -    uint16_t algo;

+      uint32_t algo32;

+  

+      Fseek(fd, 0, SEEK_SET);

+ @@ -156,7 +155,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      nr_files = rpmfiFC(hfi);

+      signatures = xcalloc(nr_files, sizeof(char *));

+  

+ -    algo = FS_VERITY_HASH_ALG_SHA256;

+ +    if (!algo)

+ +	    algo = FS_VERITY_HASH_ALG_SHA256;

+  

+      rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),

+  	   nr_files, rpmfiFC(fi));

+ diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h

+ index 69bbaf7f7..d869e8d8e 100644

+ --- a/sign/rpmsignverity.h

+ +++ b/sign/rpmsignverity.h

+ @@ -27,7 +27,7 @@ extern "C" {

+   */

+  RPM_GNUC_INTERNAL

+  rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ -		    char *keypass, char *cert);

+ +		    char *keypass, char *cert, uint16_t algo);

+  

+  #ifdef _cplusplus

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,27 @@ 

+ From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001

+ From: Jes Sorensen <jsorensen@fb.com>

+ Date: Fri, 28 Aug 2020 11:10:41 -0400

+ Subject: [PATCH 33/33] Enable fsverity in CI

+ 

+ Add fsverity-utils and fsverity-utils-devel as dependencies.

+ 

+ Signed-off-by: Jes Sorensen <jsorensen@fb.com>

+ ---

+  Makefile.am | 1 +

+  1 file changed, 1 insertion(+)

+ 

+ diff --git a/Makefile.am b/Makefile.am

+ index 8e92f0cde..3c1451049 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -17,6 +17,7 @@ DISTCHECK_CONFIGURE_FLAGS = \

+ 	--with-selinux \

+  	--with-imaevm \

+  	--with-fapolicyd \

+ +	--with-fsverity \

+  	--disable-dependency-tracking

+  

+  include $(top_srcdir)/rpm.am

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,257 @@ 

+ From aee5af8e4fe7908df90649eb699c3a1decf06b0c Mon Sep 17 00:00:00 2001

+ From: Yu Wu <wuyu@fb.com>

+ Date: Wed, 3 Nov 2021 23:13:15 -0700

+ Subject: [PATCH 1/2] rpmsign: Adopting PKCS#11 opaque keys support in

+  libfsverity for fsverity signatures

+ 

+ ---

+  rpmsign.c            | 29 ++++++++++++++++++++----

+  sign/rpmgensig.c     | 53 +++++++++++++++++++++++++++++++++++++++-----

+  sign/rpmsignverity.c | 24 +++++++++++++-------

+  sign/rpmsignverity.h |  9 +++++---

+  4 files changed, 94 insertions(+), 21 deletions(-)

+ 

+ diff --git a/rpmsign.c b/rpmsign.c

+ index 12299379ce..63b8616382 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -24,6 +24,9 @@ static int fskpass = 0;

+  static char * fileSigningKey = NULL;

+  #endif

+  #ifdef WITH_FSVERITY

+ +static char * pkcs11Engine = NULL;

+ +static char * pkcs11Module = NULL;

+ +static char * pkcs11KeyId = NULL;

+  static char * fileSigningCert = NULL;

+  static char * verityAlgorithm = NULL;

+  #endif

+ @@ -59,6 +62,15 @@ static struct poptOption signOptsTable[] = {

+      { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,

+  	N_("use file signing cert <cert>"),

+  	N_("<cert>") },

+ +    { "pkcs11_engine", '\0', POPT_ARG_STRING, &pkcs11Engine, 0,

+ +	N_("use pkcs#11 token for fsverity signing key with openssl engine <pkcs11_engine>"),

+ +	N_("<pkcs11_engine>") },

+ +    { "pkcs11_module", '\0', POPT_ARG_STRING, &pkcs11Module, 0,

+ +	N_("use pkcs#11 token for fsverity signing key with openssl module <pkcs11_module>"),

+ +	N_("<pkcs11_module>") },

+ +    { "pkcs11_keyid", '\0', POPT_ARG_STRING, &pkcs11KeyId, 0,

+ +	N_("use pkcs#11 token for fsverity signing key with keyid <pkcs11_keyid>"),

+ +	N_("<pkcs11_keyid>") },

+  #endif

+  #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)

+      { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,

+ @@ -139,6 +151,15 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+      }

+  

+  #ifdef WITH_FSVERITY

+ +    if (pkcs11Engine) {

+ +    rpmPushMacro(NULL, "_pkcs11_engine", NULL, pkcs11Engine, RMIL_GLOBAL);

+ +    }

+ +    if (pkcs11Module) {

+ +    rpmPushMacro(NULL, "_pkcs11_module", NULL, pkcs11Module, RMIL_GLOBAL);

+ +    }

+ +    if (pkcs11KeyId) {

+ +    rpmPushMacro(NULL, "_pkcs11_keyid", NULL, pkcs11KeyId, RMIL_GLOBAL);

+ +    }

+      if (fileSigningCert) {

+  	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);

+      }

+ @@ -149,9 +170,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  

+      if (flags_sign_files(sargs->signflags)) {

+  	char *fileSigningKeyPassword = NULL;

+ -	char *key = rpmExpand("%{?_file_signing_key}", NULL);

+ -	if (rstreq(key, "")) {

+ -	    fprintf(stderr, _("You must set \"%%_file_signing_key\" in your macro file or on the command line with --fskpath\n"));

+ +	char *cert = rpmExpand("%{?_file_signing_cert}", NULL);

+ +	if (rstreq(cert, "")) {

+ +	    fprintf(stderr, _("You must set \"%%_file_signing_cert\" in your macro file or on the command line with --certpath\n"));

+  	    goto exit;

+  	}

+  

+ @@ -166,7 +187,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)

+  	    free(fileSigningKeyPassword);

+  	}

+  

+ -	free(key);

+ +	free(cert);

+      }

+  #endif

+  

+ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c

+ index d8c84e9377..cb264679b6 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -461,15 +461,56 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)

+      rpmRC rc = RPMRC_OK;

+      char *key = rpmExpand("%{?_file_signing_key}", NULL);

+      char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);

+ +    char *pkcs11_engine = rpmExpand("%{?_pkcs11_engine}", NULL);

+ +    char *pkcs11_module = rpmExpand("%{?_pkcs11_module}", NULL);

+ +    char *pkcs11_keyid = rpmExpand("%{?_pkcs11_keyid}", NULL);

+      char *cert = rpmExpand("%{?_file_signing_cert}", NULL);

+      char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL);

+      uint16_t algo = 0;

+  

+ +    if (rstreq(key, "")) {

+ +	free(key);

+ +	key = NULL;

+ +    }

+ +

+ +    if (rstreq(pkcs11_engine, "")) {

+ +	free(pkcs11_engine);

+ +	pkcs11_engine = NULL;

+ +    }

+ +

+ +    if (rstreq(pkcs11_module, "")) {

+ +	free(pkcs11_module);

+ +	pkcs11_module = NULL;

+ +    }

+ +

+ +    if (rstreq(pkcs11_keyid, "")) {

+ +	free(pkcs11_keyid);

+ +	pkcs11_keyid = NULL;

+ +    }

+ +

+      if (rstreq(keypass, "")) {

+  	free(keypass);

+  	keypass = NULL;

+      }

+  

+ +    if (key) {

+ +        if (pkcs11_engine || pkcs11_module || pkcs11_keyid) {

+ +            rpmlog(

+ +                RPMLOG_ERR,

+ +                _("fsverity signatures require a key specified either by file or by PKCS#11 token, not both\n"));

+ +            rc = RPMRC_FAIL;

+ +            goto out;

+ +        }

+ +    } else {

+ +        if (!pkcs11_engine || !pkcs11_module) {

+ +            rpmlog(

+ +                RPMLOG_ERR,

+ +                _("fsverity signatures require both PKCS#11 engine and module to use PKCS#11 token\n"));

+ +            rc = RPMRC_FAIL;

+ +            goto out;

+ +        }

+ +    }

+ +

+      if (algorithm && strlen(algorithm) > 0) {

+  	    algo = libfsverity_find_hash_alg_by_name(algorithm);

+  	    rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"),

+ @@ -481,16 +522,16 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)

+  		    goto out;

+  	    }

+      }

+ -    if (key && cert) {

+ -	    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo);

+ -    } else {

+ -	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));

+ -	rc = RPMRC_FAIL;

+ -    }

+ +

+ +    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass,

+ +                pkcs11_engine, pkcs11_module, pkcs11_keyid, cert, algo);

+  

+   out:

+      free(keypass);

+      free(key);

+ +    free(pkcs11_engine);

+ +    free(pkcs11_module);

+ +    free(pkcs11_keyid);

+      free(cert);

+      return rc;

+  #else

+ diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c

+ index e6c830cdcb..b7924e7ad1 100644

+ --- a/sign/rpmsignverity.c

+ +++ b/sign/rpmsignverity.c

+ @@ -34,8 +34,9 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)

+  	return retval;

+  }

+  

+ -static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+ -			       char *keypass, char *cert, uint16_t algo)

+ +static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, char *keypass,

+ +			    char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,

+ +			    char *cert, uint16_t algo)

+  {

+      struct libfsverity_merkle_tree_params params;

+      struct libfsverity_signature_params sig_params;

+ @@ -76,6 +77,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+  

+      memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));

+      sig_params.keyfile = key;

+ +    sig_params.pkcs11_engine = pkcs11_engine;

+ +    sig_params.pkcs11_module = pkcs11_module;

+ +    sig_params.pkcs11_keyid = pkcs11_keyid;

+      sig_params.certfile = cert;

+      if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) {

+  	rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));

+ @@ -94,8 +98,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,

+      return sig_base64;

+  }

+  

+ -rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ -		    char *keypass, char *cert, uint16_t algo)

+ +rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass,

+ +	        char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,

+ +	        char *cert, uint16_t algo)

+  {

+      int rc;

+      FD_t gzdi;

+ @@ -125,6 +130,9 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      }

+  

+      rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);

+ +    rpmlog(RPMLOG_DEBUG, _("pkcs11_engine: %s\n"), pkcs11_engine);

+ +    rpmlog(RPMLOG_DEBUG, _("pkcs11_module: %s\n"), pkcs11_module);

+ +    rpmlog(RPMLOG_DEBUG, _("pkcs11_keyid: %s\n"), pkcs11_keyid);

+      rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);

+  

+      compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);

+ @@ -164,16 +172,16 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+      while (rpmfiNext(fi) >= 0) {

+  	idx = rpmfiFX(fi);

+  

+ -	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert,

+ -					    algo);

+ +	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine,

+ +					    pkcs11_module, pkcs11_keyid, cert, algo);

+      }

+  

+      while (rpmfiNext(hfi) >= 0) {

+  	idx = rpmfiFX(hfi);

+  	if (signatures[idx])

+  	    continue;

+ -	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert,

+ -					    algo);

+ +	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine,

+ +					    pkcs11_module, pkcs11_keyid, cert, algo);

+      }

+  

+      rpmtdReset(&td);

+ diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h

+ index d869e8d8e8..32d2d6359a 100644

+ --- a/sign/rpmsignverity.h

+ +++ b/sign/rpmsignverity.h

+ @@ -22,12 +22,15 @@ extern "C" {

+   * @param h		package header

+   * @param key		signing key

+   * @param keypass	signing key password

+ + * @param pkcs11_engine		PKCS#11 engine to use PKCS#11 token support for signing key

+ + * @param pkcs11_module		PKCS#11 module to use PKCS#11 token support for signing key

+ + * @param pkcs11_keyid		PKCS#11 key identifier

+   * @param cert		signing cert

+   * @return		RPMRC_OK on success

+   */

+ -RPM_GNUC_INTERNAL

+ -rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,

+ -		    char *keypass, char *cert, uint16_t algo);

+ +rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass,

+ +		    char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,

+ +		    char *cert, uint16_t algo);

+  

+  #ifdef _cplusplus

+  }

file added
+1162
The added file is too large to be shown here, see it at: 1534.patch
file added
+16
@@ -0,0 +1,16 @@ 

+ TARGETS ?= rpm_hs

+ SHARE ?= /usr/share

+ MODULES ?= ${TARGETS:=.pp.bz2}

+ 

+ all: ${TARGETS:=.pp.bz2}

+ 

+ %.pp.bz2: %.pp

+ 	@echo Compressing $^ -\ $@

+ 	bzip2 -9 $^

+ 

+ %.pp: %.te

+ 	make -f ${SHARE}/selinux/devel/Makefile $@

+ 

+ clean:

+ 	rm -f *~ *.tc *.pp *.pp.bz2

+ 	rm -rf tmp

file added
+279
@@ -0,0 +1,279 @@ 

+ From 517a37ae7beeb77e2b4870be11611f82c1200b3c Mon Sep 17 00:00:00 2001

+ From: Matthew Almond <malmond@fb.com>

+ Date: Thu, 11 Jun 2020 13:01:04 -0700

+ Subject: [PATCH 2/2] Measure plugin

+ 

+ ---

+  macros.in           |   1 +

+  plugins/Makefile.am |   4 +

+  plugins/measure.c   | 231 ++++++++++++++++++++++++++++++++++++++++++++

+  3 files changed, 236 insertions(+)

+  create mode 100644 plugins/measure.c

+ 

+ diff --git a/macros.in b/macros.in

+ index 3cc8a3555..c8a087959 100644

+ --- a/macros.in

+ +++ b/macros.in

+ @@ -1173,6 +1173,7 @@ package or when debugging this package.\

+  # Transaction plugin macros

+  %__plugindir		%{_libdir}/rpm-plugins

+  %__transaction_reflink		%{__plugindir}/reflink.so

+ +%__transaction_measure		%{__plugindir}/measure.so

+  %__transaction_systemd_inhibit	%{__plugindir}/systemd_inhibit.so

+  %__transaction_selinux		%{__plugindir}/selinux.so

+  %__transaction_syslog		%{__plugindir}/syslog.so

+ diff --git a/plugins/Makefile.am b/plugins/Makefile.am

+ index 06393ce8d..daed6423c 100644

+ --- a/plugins/Makefile.am

+ +++ b/plugins/Makefile.am

+ @@ -29,6 +29,10 @@ systemd_inhibit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/

+  plugins_LTLIBRARIES += systemd_inhibit.la

+  endif

+  

+ +measure_la_SOURCES = measure.c

+ +measure_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la

+ +plugins_LTLIBRARIES += measure.la

+ +

+  prioreset_la_SOURCES = prioreset.c

+  prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la

+  plugins_LTLIBRARIES += prioreset.la

+ diff --git a/plugins/measure.c b/plugins/measure.c

+ new file mode 100644

+ index 000000000..2cdfc885e

+ --- /dev/null

+ +++ b/plugins/measure.c

+ @@ -0,0 +1,231 @@

+ +#include "system.h"

+ +#include "time.h"

+ +

+ +#include <rpm/rpmlog.h>

+ +#include <rpm/rpmmacro.h>

+ +#include <rpm/rpmts.h>

+ +#include "lib/rpmlib.h"

+ +

+ +#include "lib/rpmplugin.h"

+ +

+ +struct measurestat {

+ +    /* We're counting psm not packages because packages often run psm_pre/post

+ +       more than once and we want to accumulate the time

+ +    */

+ +    unsigned int psm_count;

+ +    unsigned int scriptlet_count;

+ +    struct timespec plugin_start;

+ +    struct timespec psm_start;

+ +    struct timespec scriptlet_start;

+ +};

+ +

+ +static rpmRC push(const char *format, const char *value, const char *formatted)

+ +{

+ +    char *key = NULL;

+ +    rpmRC rc = RPMRC_FAIL;

+ +    if (formatted == NULL) {

+ +        /* yes we're okay with discarding const here */

+ +        key = (char *)format;

+ +    } else {

+ +        if (rasprintf(&key, format, formatted) == -1) {

+ +            rpmlog(

+ +                RPMLOG_ERR,

+ +                _("measure: Failed to allocate formatted key %s, %s\n"),

+ +                format,

+ +                formatted

+ +            );

+ +            goto exit;

+ +        }

+ +    }

+ +    if (rpmPushMacro(NULL, key, NULL, value, RMIL_GLOBAL)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to set %s\n"), key);

+ +        goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+ +exit:

+ +    if (formatted != NULL) {

+ +        free(key);

+ +    }

+ +    return rc;

+ +}

+ +

+ +static rpmRC diff_ms(char **ms, struct timespec *start, struct timespec *end)

+ +{

+ +    if (rasprintf(ms, "%ld", (

+ +        (end->tv_sec - start->tv_sec) * 1000 +

+ +        (end->tv_nsec - start->tv_nsec) / 1000000

+ +    )) == -1) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted ms\n"));

+ +        return RPMRC_FAIL;

+ +    }

+ +    return RPMRC_OK;

+ +}

+ +

+ +static rpmRC measure_init(rpmPlugin plugin, rpmts ts)

+ +{

+ +    rpmRC rc = RPMRC_FAIL;

+ +    struct measurestat *state = rcalloc(1, sizeof(*state));

+ +    if (clock_gettime(CLOCK_MONOTONIC, &state->plugin_start)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to get plugin_start time\n"));

+ +        goto exit;

+ +    }

+ +    state->psm_count = 0;

+ +    state->scriptlet_count = 0;

+ +    rpmPluginSetData(plugin, state);

+ +    rc = RPMRC_OK;

+ +exit:

+ +    return rc;

+ +}

+ +

+ +static void measure_cleanup(rpmPlugin plugin)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    free(state);

+ +}

+ +

+ +static rpmRC measure_tsm_post(rpmPlugin plugin, rpmts ts, int res)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    char *psm_count = NULL, *scriptlet_count = NULL;

+ +    rpmRC rc = RPMRC_FAIL;

+ +

+ +    if (rasprintf(&psm_count, "%d", state->psm_count) == -1) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted psm_count\n"));

+ +        goto exit;

+ +    }

+ +    if (rasprintf(&scriptlet_count, "%d", state->scriptlet_count) == -1) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted scriptlet_count\n"));

+ +        goto exit;

+ +    }

+ +    if (push("_measure_plugin_psm_count", psm_count, NULL) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("_measure_plugin_scriptlet_count", scriptlet_count, NULL) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+ +exit:

+ +    free(psm_count);

+ +    free(scriptlet_count);

+ +    return rc;

+ +}

+ +

+ +static rpmRC measure_psm_pre(rpmPlugin plugin, rpmte te)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    rpmRC rc = RPMRC_FAIL;

+ +

+ +    if (clock_gettime(CLOCK_MONOTONIC, &state->psm_start)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to get psm_start time\n"));

+ +        goto exit;

+ +    }

+ +    rc = RPMRC_OK;

+ +exit:

+ +    return rc;

+ +}

+ +

+ +static rpmRC measure_psm_post(rpmPlugin plugin, rpmte te, int res)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    struct timespec end;

+ +    char *offset = NULL, *duration = NULL, *prefix = NULL;

+ +    Header h = rpmteHeader(te);

+ +    rpmRC rc = RPMRC_FAIL;

+ +

+ +    if (clock_gettime(CLOCK_MONOTONIC, &end)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to get psm end time\n"));

+ +        goto exit;

+ +    }

+ +    if (rasprintf(&prefix, "_measure_plugin_package_%u", state->psm_count) == -1) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to allocate prefix\n"));

+ +        goto exit;

+ +    }

+ +    if (diff_ms(&offset, &state->plugin_start, &state->psm_start) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (diff_ms(&duration, &state->psm_start, &end) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_nevra", rpmteNEVRA(te), prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_compressor", headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR), prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_offset", offset, prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_ms", duration, prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    state->psm_count += 1;

+ +    rc = RPMRC_OK;

+ +exit:

+ +    headerFree(h);

+ +    free(prefix);

+ +    free(duration);

+ +    free(offset);

+ +    return rc;

+ +}

+ +

+ +static rpmRC measure_scriptlet_pre(rpmPlugin plugin,

+ +					const char *s_name, int type)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    if (clock_gettime(CLOCK_MONOTONIC, &state->scriptlet_start)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to get scriptlet_start time\n"));

+ +        return RPMRC_FAIL;

+ +    }

+ +    return RPMRC_OK;

+ +}

+ +

+ +static rpmRC measure_scriptlet_post(rpmPlugin plugin,

+ +					const char *s_name, int type, int res)

+ +{

+ +    struct measurestat *state = rpmPluginGetData(plugin);

+ +    struct timespec end;

+ +    char *offset = NULL, *duration = NULL, *prefix = NULL;

+ +    rpmRC rc = RPMRC_FAIL;

+ +

+ +    if (clock_gettime(CLOCK_MONOTONIC, &end)) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to get end time\n"));

+ +        goto exit;

+ +    }

+ +

+ +    if (rasprintf(&prefix, "_measure_plugin_scriptlet_%d", state->scriptlet_count) == -1) {

+ +        rpmlog(RPMLOG_ERR, _("measure: Failed to allocate formatted prefix\n"));

+ +        goto exit;

+ +    }

+ +    if (diff_ms(&offset, &state->plugin_start, &state->scriptlet_start) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (diff_ms(&duration, &state->scriptlet_start, &end) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_name", s_name, prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_offset", offset, prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    if (push("%s_ms", duration, prefix) != RPMRC_OK) {

+ +        goto exit;

+ +    }

+ +    state->scriptlet_count += 1;

+ +    rc = RPMRC_OK;

+ +exit:

+ +    free(prefix);

+ +    free(duration);

+ +    free(offset);

+ +    return rc;

+ +}

+ +

+ +struct rpmPluginHooks_s measure_hooks = {

+ +    .init = measure_init,

+ +    .cleanup = measure_cleanup,

+ +    .tsm_post = measure_tsm_post,

+ +    .psm_pre = measure_psm_pre,

+ +    .psm_post = measure_psm_post,

+ +    .scriptlet_pre = measure_scriptlet_pre,

+ +    .scriptlet_post = measure_scriptlet_post,

+ +};

+ -- 

+ 2.24.1

+ 

@@ -0,0 +1,57 @@ 

+ diff --git a/scripts/rpm2cpio.sh b/scripts/rpm2cpio.sh

+ index 4531271cc..74aeed851 100755

+ --- a/scripts/rpm2cpio.sh

+ +++ b/scripts/rpm2cpio.sh

+ @@ -15,13 +15,23 @@ _dd() {

+  }

+  

+  calcsize() {

+ +

+ +	case "$(_dd $1 bs=4 count=1 | tr -d '\0')" in

+ +		"$(printf '\216\255\350')"*) ;; # '\x8e\xad\xe8'

+ +		*) fatal "File doesn't look like rpm: $pkg" ;;

+ +	esac

+ +

+  	offset=$(($1 + 8))

+  

+  	local i b b0 b1 b2 b3 b4 b5 b6 b7

+  

+  	i=0

+  	while [ $i -lt 8 ]; do

+ -		b="$(_dd $(($offset + $i)) bs=1 count=1)"

+ +		# add . to not loose \n

+ +		# strip \0 as it gets dropped with warning otherwise

+ +		b="$(_dd $(($offset + $i)) bs=1 count=1 | tr -d '\0' ; echo .)"

+ +		b=${b%.}    # strip . again

+ +

+  		[ -z "$b" ] &&

+  			b="0" ||

+  			b="$(exec printf '%u\n' "'$b")"

+ @@ -33,7 +43,7 @@ calcsize() {

+  	offset=$(($offset + $rsize))

+  }

+  

+ -case "$(_dd 0 bs=8 count=1)" in

+ +case "$(_dd 0 bs=4 count=1 | tr -d '\0')" in

+  	"$(printf '\355\253\356\333')"*) ;; # '\xed\xab\xee\xdb'

+  	*) fatal "File doesn't look like rpm: $pkg" ;;

+  esac

+ @@ -44,11 +54,11 @@ sigsize=$rsize

+  calcsize $(($offset + (8 - ($sigsize % 8)) % 8))

+  hdrsize=$rsize

+  

+ -case "$(_dd $offset bs=3 count=1)" in

+ -	"$(printf '\102\132')"*) _dd $offset | bunzip2 ;; # '\x42\x5a'

+ -	"$(printf '\037\213')"*) _dd $offset | gunzip  ;; # '\x1f\x8b'

+ -	"$(printf '\375\067')"*) _dd $offset | xzcat   ;; # '\xfd\x37'

+ -	"$(printf '\135\000')"*) _dd $offset | unlzma  ;; # '\x5d\x00'

+ -	"$(printf '\050\265')"*) _dd $offset | unzstd  ;; # '\x28\xb5'

+ -	*) fatal "Unrecognized rpm file: $pkg" ;;

+ +case "$(_dd $offset bs=2 count=1 | tr -d '\0')" in

+ +	"$(printf '\102\132')") _dd $offset | bunzip2 ;; # '\x42\x5a'

+ +	"$(printf '\037\213')") _dd $offset | gunzip  ;; # '\x1f\x8b'

+ +	"$(printf '\375\067')") _dd $offset | xzcat   ;; # '\xfd\x37'

+ +	"$(printf '\135')") _dd $offset | unlzma      ;; # '\x5d\x00'

+ +	"$(printf '\050\265')") _dd $offset | unzstd  ;; # '\x28\xb5'

+ +	*) fatal "Unrecognized payload compression format in rpm file: $pkg" ;;

+  esac

@@ -1,4 +1,4 @@ 

- From ce8af503733b5661efa046cc7f5f68ee0dad75cc Mon Sep 17 00:00:00 2001

+ From ba659220886c1a315f50fb91b9af4615b1a8757e Mon Sep 17 00:00:00 2001

  From: Michal Domonkos <mdomonko@redhat.com>

  Date: Mon, 16 Aug 2021 18:21:02 +0200

  Subject: [PATCH] Add support for RPMDBI_BASENAMES on file queries
@@ -14,8 +14,11 @@ 

  

  Resolves: rhbz#1940895

  

- Combined with d1aebda01033bc8ba0d748b49f6fad9a5c0caa3f and backported

- for 4.16.1.3.

+ Combined with:

+ d1aebda01033bc8ba0d748b49f6fad9a5c0caa3f

+ f62b6d27cd741406a52a7e9c5b1d6f581dbd3af8

+ 

+ Backported for 4.16.1.3.

  ---

   doc/rpm.8         |  9 ++++++--

   lib/poptQV.c      |  6 +++++-
@@ -115,17 +118,17 @@ 

   	    mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0);

   

  diff --git a/lib/rpmcli.h b/lib/rpmcli.h

- index 4886c2453..8ef992ff2 100644

+ index 4886c2453..3961418e7 100644

  --- a/lib/rpmcli.h

  +++ b/lib/rpmcli.h

- @@ -81,6 +81,7 @@ rpmcliFini(poptContext optCon);

-  enum rpmQVSources_e {

-      RPMQV_PACKAGE = 0,	/*!< ... from package name db search. */

-      RPMQV_PATH,		/*!< ... from file path db search. */

+ @@ -101,6 +101,7 @@ enum rpmQVSources_e {

+      RPMQV_SPECBUILTRPMS,	/*!< ... from pkgs which would be built from spec */

+      RPMQV_WHATOBSOLETES,	/*!< ... from obsoletes db search. */

+      RPMQV_WHATCONFLICTS,	/*!< ... from conflicts db search. */

  +    RPMQV_PATH_ALL,	/*!< ... from file path db search (all states). */

-      RPMQV_ALL,		/*!< ... from each installed package. */

-      RPMQV_RPM, 		/*!< ... from reading binary rpm package. */

-      RPMQV_GROUP,	/*!< ... from group db search. */

+  };

+  

+  typedef rpmFlags rpmQVSources;

  diff --git a/tests/rpmquery.at b/tests/rpmquery.at

  index 9a4f1cb76..335d5ee0d 100644

  --- a/tests/rpmquery.at
@@ -190,5 +193,5 @@ 

   AT_SETUP([integer array query])

   AT_KEYWORDS([query])

  -- 

- 2.34.1

+ 2.35.1

  

@@ -0,0 +1,20 @@ 

+ --- rpm.orig/macros.in	2022-06-30 11:37:18.975312592 +0100

+ +++ rpm-4.16.1.3/macros.in	2022-06-30 11:37:43.145158323 +0100

+ @@ -167,6 +167,9 @@

+  #	A spec file can %%define _find_debuginfo_opts to pass options to

+  #	the script.  See the script for details.

+  #

+ +#	Vendor spec files (eg redhat-rpm-config:macros) can %%define

+ +#       _find_debuginfo_vendor_opts to pass options to the script.

+ +#

+  %__debug_install_post   \

+      %{_rpmconfigdir}/find-debuginfo.sh \\\

+      %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} \\\

+ @@ -179,6 +182,7 @@

+      %{?_unique_debug_srcs:--unique-debug-src-base "%{name}-%{VERSION}-%{RELEASE}.%{_arch}"} \\\

+      %{?_find_debuginfo_dwz_opts} \\\

+      %{?_find_debuginfo_opts} \\\

+ +    %{?_find_debuginfo_vendor_opts} \\\

+      %{?_debugsource_packages:-S debugsourcefiles.list} \\\

+      "%{_builddir}/%{?buildsubdir}"\

+  %{nil}

@@ -0,0 +1,12 @@ 

+ diff '--color=auto' -rup rpm-4.16.1.3-orig/macros.in rpm-4.16.1.3/macros.in

+ --- rpm-4.16.1.3-orig/macros.in	2020-09-30 03:48:01.216567738 -0400

+ +++ rpm-4.16.1.3/macros.in	2022-03-03 00:20:16.830231123 -0500

+ @@ -153,7 +153,7 @@

+  %_bzip2bin		%{__bzip2}

+  

+  #	The location of the rpm database file(s).

+ -%_dbpath		%{_var}/lib/rpm

+ +%_dbpath		%{_usr}/lib/sysimage/rpm

+  

+  #	The location of the rpm database file(s) after "rpm --rebuilddb".

+  %_dbpath_rebuild	%{_dbpath}

file modified
+243 -13
@@ -15,6 +15,16 @@ 

  %bcond_without libarchive

  # build with libimaevm.so

  %bcond_without libimaevm

+ %ifarch ppc64le

+ # no fsverity on RHEL based ppc64le

+ # due to PAGESIZE == 64k

+ # https://pagure.io/centos-sig-hyperscale/package-bugs/issue/8

+ # build without libfsverity.so

+ %bcond_with libfsverity

+ %else

+ # build with libfsverity.so

+ %bcond_without libfsverity

+ %endif

  # build with zstd support?

  %bcond_without zstd

  # build with ndb backend?
@@ -32,7 +42,7 @@ 

  

  %global rpmver 4.16.1.3

  #global snapver rc1

- %global rel 11

+ %global rel 17.1

  %global sover 9

  

  %global srcver %{rpmver}%{?snapver:-%{snapver}}
@@ -57,6 +67,16 @@ 

  

  Source10: rpmdb-rebuild.service

  

+ Source20: rpmdb-migrate.service

+ Source21: rpmdb_migrate

+ 

+ # Needed for selinux subpackage

+ Source100: Makefile.selinux

+ Source101: rpm_hs.te

+ Source102: rpm_hs.fc

+ 

+ # Set rpmdb path to /usr/lib/sysimage/rpm

+ Patch0: rpm-4.16.x-rpm_dbpath.patch

  # Disable autoconf config.site processing (#962837)

  Patch1: rpm-4.15.x-siteconfig.patch

  # In current Fedora, man-pages pkg owns all the localized man directories
@@ -82,11 +102,13 @@ 

  Patch111: rpm-4.16.1.3-skip-recorded-symlinks-in-setperms.patch

  Patch112: rpm-4.16.1.3-fix-regression-reading-rpm-v3-pkgs.patch

  Patch113: rpm-4.16.1.3-fix-spurious-transfiletriggerpostun-execution.patch

+ Patch114: rpm-4.16.1.3-Make-rpm2cpio.sh-more-robust.patch

  

  # These are not yet upstream

  Patch906: rpm-4.7.1-geode-i686.patch

  # Probably to be upstreamed in slightly different form

  Patch907: rpm-4.15.x-ldflags.patch

+ Patch908: 0001-Give-warning-on-not-supported-hash-for-RSA-keys.patch

  

  # Not yet (all) upstream, debugedit DWARF5

  # https://code.wildebeest.org/git/user/mjw/rpm/log/?h=gcc-dwarf5-4.16.1.2
@@ -99,6 +121,69 @@ 

  

  # Downstream-only patches

  Patch1000: rpm-4.16.1.3-hashtab-use-after-free-fix.patch

+ Patch1001: rpm-4.16.1.3-find_debuginfo_vendor_opts.patch

+ 

+ # fsverity support

+ %if %{with libfsverity}

+ Patch1964: 0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch

+ Patch1965: 0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch

+ Patch1966: 0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch

+ Patch1967: 0018-rpmsign-Handle-certpath-for-signing-certificate.patch

+ Patch1968: 0019-Implement-rpmSignVerity.patch

+ Patch1969: 0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch

+ Patch1970: 0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch

+ Patch1971: 0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch

+ Patch1972: 0023-Process-verity-tag-on-package-read.patch

+ Patch1973: 0024-Generate-a-zero-length-signature-for-symlinks.patch

+ Patch1974: 0025-rpmsignverity.c-Clean-up-debug-logging.patch

+ Patch1975: 0026-fsverity-add-tag-for-fsverity-algorithm.patch

+ Patch1976: 0027-plugins-fsverity-Install-fsverity-signatures.patch

+ Patch1977: 0028-fsverity-plugin-Use-tag-for-algorithm.patch

+ Patch1978: 0029-Add-fsverity-tags-to-rpmgeneral.at.patch

+ Patch1979: 0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch

+ Patch1980: 0031-Update-man-page-for-rpmsign.patch

+ Patch1981: 0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch

+ Patch1982: 0033-Enable-fsverity-in-CI.patch

+ Patch1983: 0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch

+ %endif

+ 

+ Patch9800: 1534.patch

+ 

+ # Copy-on-Write

+ Patch9901: 0001-RPM-with-Copy-on-Write.patch

+ Patch9902: 0002-Remove-use-of-bool-type-for-consistency.patch

+ Patch9903: 0003-Match-formatting-style-of-existing-code.patch

+ Patch9904: 0004-Fix-printf-formatting-in-reflink.c.patch

+ Patch9905: 0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch

+ Patch9906: 0006-rpm2extents-verify-package-signature-during-transcod.patch

+ Patch9907: 0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch

+ Patch9908: 0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch

+ Patch9909: 0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch

+ Patch9910: 0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch

+ Patch9911: 0011-rpm2extents-Perform-digest-computation-within-the-va.patch

+ Patch9912: 0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch

+ Patch9913: 0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch

+ Patch9914: 0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch

+ Patch9915: 0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch

+ Patch9916: 0016-test-new-runroot_plugins-function-to-run-command-in-.patch

+ Patch9917: 0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch

+ Patch9918: 0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch

+ Patch9919: 0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch

+ Patch9920: 0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch

+ Patch9921: 0021-tests-Fix-tests-AT_KEYWORDS-usage.patch

+ Patch9922: 0022-reflink-fix-support-for-hardlinks.patch

+ Patch9923: 0023-rpm2extents-Improve-logging.patch

+ Patch9924: 0024-rpm2extents-create-footer-struct-and-helpers.patch

+ Patch9925: 0025-extents-move-more-functions-helpers-behind-rpmextent.patch

+ Patch9926: 0026-fix-integer-underflow-in-vfyFDCb.patch

+ Patch9927: 0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch

+ Patch9928: 0028-reflink-remove-requirement-for-executable-stack-flag.patch

+ Patch9929: 0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch

+ Patch9930: 0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch

+ Provides: rpm(pr1470)

+ Provides: rpm(pr1470_1)

+ 

+ Patch9999: measure.patch

  

  # Partially GPL/LGPL dual-licensed and some bits with BSD

  # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD
@@ -161,6 +246,18 @@ 

  BuildRequires: ima-evm-utils-devel >= 1.0

  %endif

  

+ %if %{with libfsverity}

+ BuildRequires: fsverity-utils-devel >= 1.4

+ %endif

+ 

+ # For the rpmdb migration scriptlet (#2055033)

+ Requires(pre): coreutils

+ Requires(pre): findutils

+ Requires(pre): sed

+ 

+ # Force the SELinux module to be installed if SELinux policy is installed

+ Requires:      (%{name}-selinux = %{version}-%{release} if selinux-policy)

+ 

  %description

  The RPM Package Manager (RPM) is a powerful command line driven

  package management system capable of installing, uninstalling,
@@ -308,6 +405,17 @@ 

  %description plugin-ima

  %{summary}.

  

+ %if %{with libfsverity}

+ %package plugin-fsverity

+ Summary: Rpm plugin fsverity file signatures

+ Group: System Environment/Base

+ Requires: rpm-libs%{_isa} = %{version}-%{release}

+ 

+ %description plugin-fsverity

+ %{summary}

+ 

+ %endif

+ 

  %package plugin-fapolicyd

  Summary: Rpm plugin for fapolicyd functionality

  Requires: rpm-libs%{_isa} = %{version}-%{release}
@@ -317,6 +425,13 @@ 

  %description plugin-fapolicyd

  %{summary}.

  

+ %package plugin-reflink

+ Summary: Rpm plugin for reflink functionality

+ Requires: rpm-libs%{_isa} = %{version}-%{release}

+ 

+ %description plugin-reflink

+ %{summary}.

+ 

  %package plugin-prioreset

  Summary: Rpm plugin for resetting scriptlet priorities for SysV init

  Requires: rpm-libs%{_isa} = %{version}-%{release}
@@ -334,9 +449,35 @@ 

  %description plugin-audit

  %{summary}.

  

+ %package plugin-measure

+ Summary: Rpm plugin for measure

+ Group: System Environment/Base

+ Requires: rpm-libs%{_isa} = %{version}-%{release}

+ 

+ %description plugin-measure

+ Adds measure support

+ 

  # with plugins

  %endif

  

+ %package selinux

+ Summary:        SELinux module for rpm

+ BuildArch:      noarch

+ BuildRequires:  bzip2

+ BuildRequires:  make

+ BuildRequires:  selinux-policy

+ BuildRequires:  selinux-policy-devel

+ Requires(post): selinux-policy-base >= %{_selinux_policy_version}

+ Requires(post): policycoreutils

+ Requires(post): policycoreutils-python-utils

+ Requires(pre):  libselinux-utils

+ Requires(post): libselinux-utils

+ 

+ %description selinux

+ This package provides the SELinux policy module to ensure rpm

+ runs properly under an environment with SELinux enabled.

+ 

+ 

  %prep

  %autosetup -n rpm-%{srcver} %{?with_int_bdb:-a 1} -p1

  
@@ -349,6 +490,10 @@ 

  sed -i -e "/_db_backend/ s/ bdb/ sqlite/g" macros.in

  %endif

  

+ # SELinux policy files

+ mkdir selinux-policy

+ cp %{SOURCE100} %{SOURCE101} %{SOURCE102} selinux-policy

+ 

  %build

  %set_build_flags

  
@@ -380,6 +525,7 @@ 

      %{?with_ndb: --enable-ndb} \

      %{!?with_libarchive: --without-archive} \

      %{?with_libimaevm: --with-imaevm} \

+     %{?with_libfsverity: --with-fsverity} \

      %{?with_zstd: --enable-zstd} \

      %{?with_sqlite: --enable-sqlite} \

      %{?with_bdb_ro: --enable-bdb-ro} \
@@ -393,6 +539,10 @@ 

  %py3_build

  popd

  

+ pushd selinux-policy

+ %{__make} -f Makefile.selinux SHARE="%{_datadir}" TARGETS="rpm_hs"

+ popd

+ 

  %install

  %make_install

  
@@ -402,8 +552,15 @@ 

  %py3_install

  popd

  

+ install -d -p %{buildroot}%{_datadir}/selinux/packages

+ install -p -m 0644 selinux-policy/rpm_hs.pp.bz2 %{buildroot}%{_datadir}/selinux/packages

+ 

  mkdir -p $RPM_BUILD_ROOT%{_unitdir}

  install -m 644 %{SOURCE10} $RPM_BUILD_ROOT/%{_unitdir}

+ install -m 644 %{SOURCE20} $RPM_BUILD_ROOT/%{_unitdir}

+ 

+ mkdir -p $RPM_BUILD_ROOT%{rpmhome}

+ install -m 755 %{SOURCE21} $RPM_BUILD_ROOT/%{rpmhome}

  

  # Save list of packages through cron

  mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/cron.daily
@@ -414,17 +571,17 @@ 

  

  %if %{with bdb}

  mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir}

- echo "r /var/lib/rpm/__db.*" > ${RPM_BUILD_ROOT}%{_tmpfilesdir}/rpm.conf

+ echo "r /usr/lib/sysimage/rpm/__db.*" > ${RPM_BUILD_ROOT}%{_tmpfilesdir}/rpm.conf

  %endif

  

  mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm

  mkdir -p $RPM_BUILD_ROOT%{rpmhome}/macros.d

- mkdir -p $RPM_BUILD_ROOT/var/lib/rpm

+ mkdir -p $RPM_BUILD_ROOT/usr/lib/sysimage/rpm

  

  # init an empty database for %ghost'ing for all supported backends

  for be in %{?with_ndb:ndb} %{?with_sqlite:sqlite} %{?with_bdb:bdb}; do

      ./rpmdb --define "_db_backend ${be}" --dbpath=${PWD}/${be} --initdb

-     cp -va ${be}/. $RPM_BUILD_ROOT/var/lib/rpm/

+     cp -va ${be}/. $RPM_BUILD_ROOT/usr/lib/sysimage/rpm/

  done

  

  %find_lang rpm
@@ -443,16 +600,42 @@ 

  make clean

  %endif

  

- # Handle rpmdb rebuild service on erasure of old to avoid ordering issues

- # https://pagure.io/fesco/issue/2382

- %triggerun -- rpm < 4.15.90-0.git14971.10

+ %pre

+ # Symlink all rpmdb files to the new location if we're still using /var/lib/rpm

+ if [ -d /var/lib/rpm ]; then

+     mkdir -p /usr/lib/sysimage/rpm

+     rpmdb_files=$(find /var/lib/rpm -maxdepth 1 -type f | sed 's|^/var/lib/rpm/||g' | sort)

+     for rpmdb_file in ${rpmdb_files[@]}; do

+         ln -sfr /var/lib/rpm/${rpmdb_file} /usr/lib/sysimage/rpm/${rpmdb_file}

+     done

+ fi

+ 

+ %triggerun -- rpm < 4.16.1.3-11.3

+ # Handle rpmdb migrate service on erasure of old to avoid ordering issues

  if [ -x /usr/bin/systemctl ]; then

-     systemctl --no-reload preset rpmdb-rebuild ||:

+     systemctl --no-reload preset rpmdb-migrate ||:

  fi

  

  %posttrans

- if [ -f /var/lib/rpm/Packages ]; then

-     touch /var/lib/rpm/.rebuilddb

+ if [ -d /var/lib/rpm ]; then

+     touch /var/lib/rpm/.migratedb

+ fi

+ 

+ %pre selinux

+ %selinux_relabel_pre

+ 

+ %post selinux

+ %selinux_modules_install %{_datadir}/selinux/packages/rpm_hs.pp.bz2

+ %selinux_relabel_post

+ 

+ %posttrans selinux

+ %selinux_relabel_post

+ 

+ %postun selinux

+ %selinux_modules_uninstall rpm_hs

+ 

+ if [ $1 -eq 0 ]; then

+     %selinux_relabel_post

  fi

  

  %files -f rpm.lang
@@ -464,12 +647,13 @@ 

  %endif

  

  %{_unitdir}/rpmdb-rebuild.service

+ %{_unitdir}/rpmdb-migrate.service

  

  %dir %{_sysconfdir}/rpm

  

- %attr(0755, root, root) %dir /var/lib/rpm

- %attr(0644, root, root) %ghost %config(missingok,noreplace) /var/lib/rpm/*

- %attr(0644, root, root) %ghost /var/lib/rpm/.*.lock

+ %attr(0755, root, root) %dir /usr/lib/sysimage/rpm

+ %attr(0644, root, root) %ghost %config(missingok,noreplace) /usr/lib/sysimage/rpm/*

+ %attr(0644, root, root) %ghost /usr/lib/sysimage/rpm/.*.lock

  

  %{_bindir}/rpm

  %if %{with libarchive}
@@ -525,6 +709,11 @@ 

  %if %{with plugins}

  %dir %{_libdir}/rpm-plugins

  

+ %if %{with libfsverity}

+ %files plugin-fsverity

+ %{_libdir}/rpm-plugins/fsverity.so

+ %endif

+ 

  %files plugin-syslog

  %{_libdir}/rpm-plugins/syslog.so

  %{_mandir}/man8/rpm-plugin-syslog.8*
@@ -545,6 +734,11 @@ 

  %{_libdir}/rpm-plugins/fapolicyd.so

  %{_mandir}/man8/rpm-plugin-fapolicyd.8*

  

+ %files plugin-reflink

+ %{_bindir}/rpm2extents

+ %{_bindir}/rpm2extents_dump

+ %{_libdir}/rpm-plugins/reflink.so

+ 

  %files plugin-prioreset

  %{_libdir}/rpm-plugins/prioreset.so

  %{_mandir}/man8/rpm-plugin-prioreset.8*
@@ -552,6 +746,9 @@ 

  %files plugin-audit

  %{_libdir}/rpm-plugins/audit.so

  %{_mandir}/man8/rpm-plugin-audit.8*

+ 

+ %files plugin-measure

+ %{_libdir}/rpm-plugins/measure.so

  # with plugins

  %endif

  
@@ -610,7 +807,40 @@ 

  %license COPYING

  %doc doc/librpm/html/*

  

+ %files selinux

+ %{_datadir}/selinux/packages/rpm_hs.pp.bz2

+ 

  %changelog

+ * Thu Aug 18 2022 Manu Bretelle <chantra@fb.com> - 4.16.1.3-17.1

+ - Rebuild for hyperscale

+ 

+ * Wed Aug 03 2022 Florian Festi <ffesti@redhat.com> - 4.16.1.3-17

+ - Make rpm2cpio.sh more robust (#1983015)

+ 

+ * Thu Jun 30 2022 Nick Clifton  <nickc@redhat.com> - 4.16.1.3-15

+ - Pass _find_debuginfo_vendor_opts to the find-debuginfo script.  (#2099617)

+ 

+ * Tue Jun 28 2022 Florian Festi <ffesti@redhat.com> - 4.16.1.3-14

+ - Warning for failed key import (#2069877)

+ 

+ * Tue Apr 05 2022 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-12

+ - Fix minor ABI regression in rpmcli.h (#2037352)

+ 

+ * Sun Apr 03 2022 Neal Gompa <ngompa@centosproject.org> - 4.16.1.3-11.3

+ - Migrate rpmdb to /usr/lib/sysimage/rpm

+   https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr

+ 

+ * Tue Mar 29 2022 Manu Bretelle <chantra@fb.com> - 4.16.1.3-11.2

+ - Make `rpm -i` work without `--nodigest`

+ - Remove need of executable stack for reflink plugin

+ - Split RPM CoW diffs in individual patches

+ 

+ * Fri Feb 25 2022 Manu Bretelle <chantra@fb.com> - 4.16.1.3-11.1

+ - Added fsverity backport

+ - Added measure plugin support

+ - Apply GH1534 in preparation of RPM cow patch

+ - Add support for RPM CoW

+ 

  * Mon Feb 14 2022 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-11

  - Fix IMA signature lengths assumed constant, take III (#2018937)

  - Fix regression reading rpm v3 and other rare packages (#2037186)

file added
+2
@@ -0,0 +1,2 @@ 

+ # This is in /usr, but is expected to be variable content from a policy perspective (#2042149)

+ /usr/lib/sysimage/rpm(/.*)?		gen_context(system_u:object_r:rpm_var_lib_t,s0)

file added
+11
@@ -0,0 +1,11 @@ 

+ policy_module(rpm_hs,0.0.1)

+ 

+ # rpm overrides

+ gen_require(`

+ 	type rpm_t;

+ 	type rpmdb_t;

+ 	type rpm_var_lib_t;

+ ')

+ 

+ # Allow rpmdb create directory in /usr/lib/sysimage (#2061141)

+ files_usr_filetrans(rpmdb_t, rpm_var_lib_t, dir)

@@ -0,0 +1,18 @@ 

+ [Unit]

+ Description=RPM database migration to /usr

+ ConditionPathExists=/var/lib/rpm/.migratedb

+ 

+ # This should run before any daemons that may open the rpmdb

+ DefaultDependencies=no

+ After=sysinit.target

+ Before=basic.target shutdown.target

+ Conflicts=shutdown.target

+ # In case /var is remote-mounted

+ RequiresMountsFor=/var

+ 

+ [Service]

+ Type=oneshot

+ ExecStart=/usr/lib/rpm/rpmdb_migrate

+ 

+ [Install]

+ WantedBy=basic.target

file modified
+4 -4
@@ -1,19 +1,19 @@ 

  [Unit]

  Description=RPM database rebuild

- ConditionPathExists=/var/lib/rpm/.rebuilddb

+ ConditionPathExists=/usr/lib/sysimage/rpm/.rebuilddb

  

  # This should run before any daemons that may open the rpmdb

  DefaultDependencies=no

  After=sysinit.target

  Before=basic.target shutdown.target

  Conflicts=shutdown.target

- # In case /var is remote-mounted

- RequiresMountsFor=/var

+ # In case /usr is remote-mounted

+ RequiresMountsFor=/usr

  

  [Service]

  Type=oneshot

  ExecStart=/usr/bin/rpmdb --rebuilddb

- ExecStartPost=rm -f /var/lib/rpm/.rebuilddb

+ ExecStartPost=rm -f /usr/lib/sysimage/rpm/.rebuilddb

  

  [Install]

  WantedBy=basic.target

file added
+40
@@ -0,0 +1,40 @@ 

+ #!/bin/bash

+ # Script to migrate rpmdb from /var/lib/rpm to new rpmdb path in /usr

+ 

+ # Copyright (C) 2022 Neal Gompa <ngompa@fedoraproject.org>.

+ #

+ # Fedora-License-Identifier: GPLv2+

+ # SPDX-2.0-License-Identifier: GPL-2.0+

+ # SPDX-3.0-License-Identifier: GPL-2.0-or-later

+ #

+ # This program is free software.

+ # For more information on the license, see COPYING or

+ # <https://www.gnu.org/licenses/gpl-2.0.en.html>.

+ # For more information on free software, see

+ # <https://www.gnu.org/philosophy/free-sw.en.html>.

+ 

+ 

+ set -euo pipefail

+ 

+ # Script to migrate the rpmdb to /usr

+ rpmdb_path="$(rpm --eval '%_dbpath')"

+ rpmdb_path_old="/var/lib/rpm"

+ rpmdb_path_new="${rpmdb_path}"

+ 

+ 

+ if [ "${rpmdb_path}" = "${rpmdb_path_old}" ]; then

+ 	echo "The rpmdb path is still in /var, exiting!"

+ 	exit 0

+ fi

+ 

+ if [ -L "${rpmdb_path_old}" ]; then

+ 	echo "The rpmdb has already been migrated, exiting!"

+ 	rm -v "${rpmdb_path_old}/.migratedb"

+ 	exit 0

+ fi

+ 

+ rpm --verbose --rebuilddb

+ 

+ rm -rfv ${rpmdb_path_old}

+ 

+ ln -srv ${rpmdb_path_new} ${rpmdb_path_old}

Metadata
Changes Summary 64
+40
file added
0001-Give-warning-on-not-supported-hash-for-RSA-keys.patch
+1344
file added
0001-RPM-with-Copy-on-Write.patch
+53
file added
0002-Remove-use-of-bool-type-for-consistency.patch
+1249
file added
0003-Match-formatting-style-of-existing-code.patch
+27
file added
0004-Fix-printf-formatting-in-reflink.c.patch
+73
file added
0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
+431
file added
0006-rpm2extents-verify-package-signature-during-transcod.patch
+282
file added
0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch
+116
file added
0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch
+70
file added
0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
+204
file added
0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch
+389
file added
0011-rpm2extents-Perform-digest-computation-within-the-va.patch
+299
file added
0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
+109
file added
0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
+79
file added
0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch
+33
file added
0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch
+28
file added
0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
+136
file added
0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
+33
file added
0016-test-new-runroot_plugins-function-to-run-command-in-.patch
+51
file added
0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
+63
file added
0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch
+97
file added
0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch
+52
file added
0018-rpmsign-Handle-certpath-for-signing-certificate.patch
+243
file added
0019-Implement-rpmSignVerity.patch
+156
file added
0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch
+95
file added
0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
+35
file added
0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch
+206
file added
0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
+43
file added
0021-tests-Fix-tests-AT_KEYWORDS-usage.patch
+132
file added
0022-reflink-fix-support-for-hardlinks.patch
+162
file added
0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
+189
file added
0023-Process-verity-tag-on-package-read.patch
+393
file added
0023-rpm2extents-Improve-logging.patch
+33
file added
0024-Generate-a-zero-length-signature-for-symlinks.patch
+200
file added
0024-rpm2extents-create-footer-struct-and-helpers.patch
+176
file added
0025-extents-move-more-functions-helpers-behind-rpmextent.patch
+40
file added
0025-rpmsignverity.c-Clean-up-debug-logging.patch
+25
file added
0026-fix-integer-underflow-in-vfyFDCb.patch
+161
file added
0026-fsverity-add-tag-for-fsverity-algorithm.patch
+257
file added
0027-plugins-fsverity-Install-fsverity-signatures.patch
+169
file added
0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch
+116
file added
0028-fsverity-plugin-Use-tag-for-algorithm.patch
+117
file added
0028-reflink-remove-requirement-for-executable-stack-flag.patch
+28
file added
0029-Add-fsverity-tags-to-rpmgeneral.at.patch
+109
file added
0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch
+117
file added
0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
+98
file added
0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch
+72
file added
0031-Update-man-page-for-rpmsign.patch
+168
file added
0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
+27
file added
0033-Enable-fsverity-in-CI.patch
+257
file added
0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch
+1162
file added
1534.patch
+16
file added
Makefile.selinux
+279
file added
measure.patch
+57
file added
rpm-4.16.1.3-Make-rpm2cpio.sh-more-robust.patch
+15 -12
file changed
rpm-4.16.1.3-add-path-query-option.patch
+20
file added
rpm-4.16.1.3-find_debuginfo_vendor_opts.patch
+12
file added
rpm-4.16.x-rpm_dbpath.patch
+243 -13
file changed
rpm.spec
+2
file added
rpm_hs.fc
+11
file added
rpm_hs.te
+18
file added
rpmdb-migrate.service
+4 -4
file changed
rpmdb-rebuild.service
+40
file added
rpmdb_migrate