#16 DO NOT MERGE: Merge upstream changes for Hyperscale
Opened 2 months ago by dcavalca. Modified 2 months ago
rpms/ dcavalca/rpm c8s-sig-hyperscale  into  c8s-sig-hyperscale

file added
+1
@@ -0,0 +1,1 @@ 

+ 3f8c3ef08f93eaeef12008055a43f6872306f8a2 SOURCES/rpm-4.14.3.tar.bz2

@@ -0,0 +1,32 @@ 

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

+ From: "Vladimir D. Seleznev" <vseleznv@altlinux.org>

+ Date: Tue, 13 Mar 2018 00:04:45 +0300

+ Subject: [PATCH 01/33] Add RPMTAG_AUTOINSTALLED reservation

+ 

+ This tag is needed to track automatically installed packages with rpmdb.

+ Zero value means that a package was installed manually, other values

+ mean that the package was installed automatically as some else package

+ dependency.

+ 

+ This tag is reserved for ALT Linux Team and marked as unimplemented.

+ 

+ Signed-off-by: Vladimir D. Seleznev <vseleznv@altlinux.org>

+ ---

+  lib/rpmtag.h | 1 +

+  1 file changed, 1 insertion(+)

+ 

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

+ index 57b10a706..664561156 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -368,6 +368,7 @@ typedef enum rpmTag_e {

+      RPMTAG_FILESIGNATURELENGTH  = 5091, /* i */

+      RPMTAG_PAYLOADDIGEST	= 5092, /* s[] */

+      RPMTAG_PAYLOADDIGESTALGO	= 5093, /* i */

+ +    RPMTAG_AUTOINSTALLED	= 5094, /* i reservation (unimplemented) */

+      RPMTAG_MODULARITYLABEL	= 5096, /* s */

+  

+      RPMTAG_FIRSTFREE_TAG	/*!< internal */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,107 @@ 

+ From 186e0ab025b9ad92d900697f611633a6f6162f3b Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Wed, 9 Feb 2022 14:47:14 +0200

+ Subject: [PATCH] Add optional callback on directory changes during rpmfi

+  iteration

+ 

+ Internal only for now in case we need to fiddle with the API some more,

+ but no reason this couldn't be made public later.

+ ---

+  lib/rpmfi.c          | 24 ++++++++++++++++++++----

+  lib/rpmfi_internal.h | 17 +++++++++++++++++

+  2 files changed, 37 insertions(+), 4 deletions(-)

+ 

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

+ index aec8220a3..6c631fdb5 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -53,6 +53,9 @@ struct rpmfi_s {

+      int intervalStart;		/*!< Start of iterating interval. */

+      int intervalEnd;		/*!< End of iterating interval. */

+  

+ +    rpmfiChdirCb onChdir;	/*!< Callback for directory changes */

+ +    void *onChdirData;		/*!< Caller private callback data */

+ +

+      rpmfiles files;		/*!< File info set */

+      rpmcpio_t archive;		/*!< Archive with payload */

+      unsigned char * found;	/*!< Bit field of files found in the archive */

+ @@ -298,11 +301,16 @@ rpm_count_t rpmfiDC(rpmfi fi)

+      return (fi != NULL ? rpmfilesDC(fi->files) : 0);

+  }

+  

+ -#ifdef	NOTYET

+ -int rpmfiDI(rpmfi fi)

+ +int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data)

+  {

+ +    int rc = -1;

+ +    if (fi != NULL) {

+ +	fi->onChdir = cb;

+ +	fi->onChdirData = data;

+ +	rc = 0;

+ +    }

+ +    return rc;

+  }

+ -#endif

+  

+  int rpmfiFX(rpmfi fi)

+  {

+ @@ -314,9 +322,17 @@ int rpmfiSetFX(rpmfi fi, int fx)

+      int i = -1;

+  

+      if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {

+ +	int dx = fi->j;

+  	i = fi->i;

+  	fi->i = fx;

+  	fi->j = rpmfilesDI(fi->files, fi->i);

+ +	i = fi->i;

+ +

+ +	if (fi->j != dx && fi->onChdir) {

+ +	    int chrc = fi->onChdir(fi, fi->onChdirData);

+ +	    if (chrc < 0)

+ +		i = chrc;

+ +	}

+      }

+      return i;

+  }

+ @@ -1682,9 +1698,9 @@ static rpmfi initIter(rpmfiles files, int itype, int link)

+      if (files && itype>=0 && itype<=RPMFILEITERMAX) {

+  	fi = xcalloc(1, sizeof(*fi)); 

+  	fi->i = -1;

+ +	fi->j = -1;

+  	fi->files = link ? rpmfilesLink(files) : files;

+  	fi->next = nextfuncs[itype];

+ -	fi->i = -1;

+  	if (itype == RPMFI_ITER_BACK) {

+  	    fi->i = rpmfilesFC(fi->files);

+  	} else if (itype >=RPMFI_ITER_READ_ARCHIVE

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

+ index dccc6ccbe..37f1d45f5 100644

+ --- a/lib/rpmfi_internal.h

+ +++ b/lib/rpmfi_internal.h

+ @@ -13,6 +13,23 @@

+  extern "C" {

+  #endif

+  

+ +/** \ingroup rpmfi

+ + * Callback on file iterator directory changes

+ + * @param fi		file info

+ + * @param data		caller private callback data

+ + * @return		0 on success, < 0 on error (to stop iteration)

+ + */

+ +typedef int (*rpmfiChdirCb)(rpmfi fi, void *data);

+ +

+ +/** \ingroup rpmfi

+ + * Set a callback for directory changes during iteration.

+ + * @param fi		file info

+ + * @param cb		callback function

+ + * @param data		caller private callback data

+ + * @return		string pool handle (weak reference)

+ + */

+ +int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data);

+ +

+  /** \ingroup rpmfi

+   * Return file info set string pool handle

+   * @param fi		file info

+ -- 

+ 2.41.0

+ 

@@ -0,0 +1,30 @@ 

+ From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Wed, 13 Dec 2023 11:57:50 +0200

+ Subject: [PATCH] Don't warn about missing user/group on skipped files

+ 

+ There's no reason to complain about missing user/group for entities

+ we don't create at all. It's cosmetical only, but "regressed" in the

+ 4.17 fsm robustness rewrite.

+ 

+ Reported in https://issues.redhat.com/browse/RHEL-18037

+ ---

+  lib/fsm.c | 2 +-

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

+ 

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

+ index 2189bd84c..a54e43bae 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

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

+  	fp->fpath = fsmFsPath(fi, fp->suffix);

+  

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

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

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

+  

+  	/* Hardlinks are tricky and handled elsewhere for install */

+  	fp->setmeta = (fp->skip == 0) &&

+ -- 

+ 2.43.0

+ 

@@ -0,0 +1,35 @@ 

+ From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Thu, 10 Feb 2022 10:23:22 +0200

+ Subject: [PATCH] Eliminate code duplication from rpmfiNext()

+ 

+ Now that we can, let rpmfiSetFX() take care of the details.

+ ---

+  lib/rpmfi.c | 11 ++---------

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

+ 

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

+ index 689ead2c5..aec8220a3 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -856,15 +856,8 @@ int rpmfiNext(rpmfi fi)

+  	    next = fi->next(fi);

+  	} while (next == RPMERR_ITER_SKIP);

+  

+ -	if (next >= 0 && next < rpmfilesFC(fi->files)) {

+ -	    fi->i = next;

+ -	    fi->j = rpmfilesDI(fi->files, fi->i);

+ -	} else {

+ -	    fi->i = -1;

+ -	    if (next >= 0) {

+ -		next = -1;

+ -	    }

+ -	}

+ +	if (next >= 0)

+ +	    next = rpmfiSetFX(fi, next);

+      }

+      return next;

+  }

+ -- 

+ 2.41.0

+ 

@@ -0,0 +1,66 @@ 

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Mon, 27 Nov 2023 11:52:34 +0200

+ Subject: [PATCH] Emit full paths for file disposition diagnostics on

+  --fsmdebug

+ 

+ The full path is visible in the actual file operations later, but the

+ pre-flight disposition diagnostics is unreadable without the full path.

+ This regressed in the switch to relative paths for the *at() API family

+ for the symlink CVE fixes.

+ ---

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

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

+ 

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

+ index 091e90554..fcd764648 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -482,14 +482,14 @@ static void removeSBITS(int dirfd, const char *path)

+      }

+  }

+  

+ -static void fsmDebug(const char *fpath, rpmFileAction action,

+ +static void fsmDebug(const char *dn, const char *fpath, rpmFileAction action,

+  		     const struct stat *st)

+  {

+ -    rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",

+ +    rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s%s\n",

+  	   fileActionString(action), (int)st->st_mode,

+  	   (int)st->st_nlink, (int)st->st_uid,

+  	   (int)st->st_gid, (int)st->st_size,

+ -	    (fpath ? fpath : ""));

+ +	    (dn ? dn : ""), (fpath ? fpath : ""));

+  }

+  

+  static int fsmSymlink(const char *opath, int dirfd, const char *path)

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

+  		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);

+  

+  	setFileState(fs, fx);

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

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

+  

+  	fp->stage = FILE_PRE;

+      }

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

+  		rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n",

+  			fp->fpath);

+  		fp->action = FA_CREATE;

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

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

+  	    }

+  

+  	    /* When touching we don't need any of this... */

+ @@ -1138,7 +1138,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,

+  

+  	rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb);

+  

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

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

+  

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

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

+ -- 

+ 2.43.0

+ 

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

+ From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 14 Nov 2023 11:37:48 +0200

+ Subject: [PATCH] Fix wrong return code on O_DIRECTORY open of invalid symlink

+ 

+ The dir argument to fsmOpenpath() is supposed to be a rough O_DIRECTORY

+ equivalent, and if the path is actually a misowned symlink it should

+ return ENOTDIR instead of ELOOP. Makes the resulting error messages

+ at least a little more comprehensible.

+ ---

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

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

+ 

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

+ index 51f439ef3..091e90554 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -304,6 +304,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)

+      struct stat lsb, sb;

+      int sflags = flags | O_NOFOLLOW;

+      int fd = openat(dirfd, path, sflags);

+ +    int ffd = fd;

+  

+      /*

+       * Only ever follow symlinks by root or target owner. Since we can't

+ @@ -312,7 +313,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)

+       * it could've only been the link owner or root.

+       */

+      if (fd < 0 && errno == ELOOP && flags != sflags) {

+ -	int ffd = openat(dirfd, path, flags);

+ +	ffd = openat(dirfd, path, flags);

+  	if (ffd >= 0) {

+  	    if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) {

+  		if (fstat(ffd, &sb) == 0) {

+ @@ -327,7 +328,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)

+      }

+  

+      /* O_DIRECTORY equivalent */

+ -    if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {

+ +    if (dir && ((fd != ffd) || (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)))) {

+  	errno = ENOTDIR;

+  	fsmClose(&fd);

+      }

+ -- 

+ 2.43.0

+ 

@@ -0,0 +1,153 @@ 

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 15 Feb 2022 10:43:13 +0200

+ Subject: [PATCH] Pass file descriptor to file prepare plugin hook, use when

+  possible

+ 

+ Sadly the thing that allegedly makes things better mostly just makes

+ things more complicated as symlinks can't be opened, so we'll now have

+ to deal with both cases in plugins too. To make matters worse, most

+ APIs out there support either an fd or a path, but very few support

+ the *at() style dirfd + basename approach so plugins are stuck with

+ absolute paths for now.

+ 

+ This is of course a plugin API/ABI change too.

+ ---

+  lib/rpmplugin.h   |  2 +-

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

+  lib/rpmplugins.h  |  3 ++-

+  plugins/ima.c     |  9 +++++++--

+  plugins/selinux.c | 13 ++++++++-----

+  5 files changed, 20 insertions(+), 11 deletions(-)

+ 

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

+ index fd81aec8d..fab4b3e83 100644

+ --- a/lib/rpmplugin.h

+ +++ b/lib/rpmplugin.h

+ @@ -57,7 +57,7 @@ typedef rpmRC (*plugin_fsm_file_post_func)(rpmPlugin plugin, rpmfi fi,

+  					   const char* path, mode_t file_mode,

+  					   rpmFsmOp op, int res);

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

+ -					      const char* path,

+ +					      int fd, const char* path,

+  					      const char *dest,

+  					      mode_t file_mode, rpmFsmOp op);

+  

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

+ index 65e684e84..923084b78 100644

+ --- a/lib/rpmplugins.c

+ +++ b/lib/rpmplugins.c

+ @@ -384,7 +384,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,

+  }

+  

+  rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

+ -				   const char *path, const char *dest,

+ +				   int fd, const char *path, const char *dest,

+  				   mode_t file_mode, rpmFsmOp op)

+  {

+      plugin_fsm_file_prepare_func hookFunc;

+ @@ -394,7 +394,7 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

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

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

+  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);

+ -	if (hookFunc && hookFunc(plugin, fi, path, dest, file_mode, op) == RPMRC_FAIL) {

+ +	if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {

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

+  	    rc = RPMRC_FAIL;

+  	}

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

+ index 39762c376..ddf5d7048 100644

+ --- a/lib/rpmplugins.h

+ +++ b/lib/rpmplugins.h

+ @@ -156,6 +156,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,

+   * permissions etc, but before committing file to destination path.

+   * @param plugins	plugins structure

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

+ + * @param fd		file descriptor (or -1 if not available)

+   * @param path		file object current path

+   * @param dest		file object destination path

+   * @param mode		file object mode

+ @@ -164,7 +165,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,

+   */

+  RPM_GNUC_INTERNAL

+  rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

+ -                                   const char *path, const char *dest,

+ +                                   int fd, const char *path, const char *dest,

+                                     mode_t mode, rpmFsmOp op);

+  

+  #ifdef __cplusplus

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

+ index 7ac44f0d0..1ff50c30f 100644

+ --- a/plugins/fapolicyd.c

+ +++ b/plugins/fapolicyd.c

+ @@ -145,7 +145,8 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,

+  }

+  

+  static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+ -                                        const char *path, const char *dest,

+ +                                        int fd, const char *path,

+ +					const char *dest,

+                                          mode_t file_mode, rpmFsmOp op)

+  {

+      /* not ready  */

+ --- a/plugins/ima.c	2020-04-28 14:50:11.835399269 +0200

+ +++ b/plugins/ima.c	2023-12-13 11:19:58.835948660 +0100

+ @@ -39,7 +39,7 @@

+  	return (memcmp(fsig, &zero_hdr, sizeof(zero_hdr)) == 0);

+  }

+  

+ -static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+ +static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,

+                                    const char *path,

+                                    const char *dest,

+                                    mode_t file_mode, rpmFsmOp op)

+ @@ -63,8 +63,14 @@

+  

+  	fsig = rpmfiFSignature(fi, &len);

+  	if (fsig && (check_zero_hdr(fsig, len) == 0)) {

+ -	    if (lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0) < 0) {

+ -	        rpmlog(RPMLOG_ERR,

+ +	    int xx;

+ +	    if (fd >= 0)

+ +		xx = fsetxattr(fd, XATTR_NAME_IMA, fsig, len, 0);

+ +	    else

+ +		xx = lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0);

+ +	    if (xx < 0) {

+ +		int is_err = errno != EOPNOTSUPP;

+ + 	        rpmlog(is_err?RPMLOG_ERR:RPMLOG_DEBUG,

+  			"ima: could not apply signature on '%s': %s\n",

+  			path, strerror(errno));

+  	        rc = RPMRC_FAIL;

+ --- a/plugins/selinux.c	2023-12-13 11:21:54.935009141 +0100

+ +++ b/plugins/selinux.c	2023-12-13 11:22:23.172510285 +0100

+ @@ -149,7 +149,7 @@

+      return rc;

+  }

+  

+ -static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,

+ +static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,

+  					const char *path, const char *dest,

+  				        mode_t file_mode, rpmFsmOp op)

+  {

+ @@ -159,14 +159,17 @@

+      if (sehandle && !XFA_SKIPPING(action)) {

+  	security_context_t scon = NULL;

+  	if (selabel_lookup_raw(sehandle, &scon, dest, file_mode) == 0) {

+ -	    int conrc = lsetfilecon(path, scon);

+ +	    int conrc;

+ +	    if (fd >= 0)

+ +		conrc = fsetfilecon(fd, scon);

+ +	    else

+ +		conrc = lsetfilecon(path, scon);

+  

+  	    if (conrc == 0 || (conrc < 0 && errno == EOPNOTSUPP))

+  		rc = RPMRC_OK;

+  

+ -	    rpmlog((rc != RPMRC_OK) ? RPMLOG_ERR : RPMLOG_DEBUG,

+ -		   "lsetfilecon: (%s, %s) %s\n",

+ -		   path, scon, (conrc < 0 ? strerror(errno) : ""));

+ +	    rpmlog((rc != RPMRC_OK) ? RPMLOG_ERR : RPMLOG_DEBUG, "lsetfilecon: (%d %s, %s) %s\n",

+ +		       fd, path, scon, (conrc < 0 ? strerror(errno) : ""));

+  

+  	    freecon(scon);

+  	} else {

@@ -0,0 +1,32 @@ 

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

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

+ Date: Mon, 11 Dec 2023 15:50:15 +0100

+ Subject: [PATCH] Print full path if file removal fails

+ 

+ For normal debug output the basename of the files are sufficient as when

+ debugging is enabled the directories are also printed. But here the

+ warning is given without a debug flag so we need the full context right

+ there.

+ ---

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

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

+ 

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

+ index fcd764648..2189bd84c 100644

+ --- a/lib/fsm.c

+ +++ b/lib/fsm.c

+ @@ -1174,9 +1174,9 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,

+  

+  	    if (rc) {

+  		int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;

+ -		rpmlog(lvl, _("%s %s: remove failed: %s\n"),

+ +		rpmlog(lvl, _("%s %s%s: remove failed: %s\n"),

+  			S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"),

+ -			fp->fpath, strerror(errno));

+ +			rpmfiDN(fi), fp->fpath, strerror(errno));

+              }

+          }

+  

+ -- 

+ 2.43.0

+ 

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

+ From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 15 Feb 2022 11:34:37 +0200

+ Subject: [PATCH] Swap over to dirfd+basename based operation within the fsm

+ 

+ Within fsm this is just a matter of adjusting error messages to include

+ the directory... if it only wasn't for the plugins requiring absolute

+ paths for outside users. For the plugins, we need to assemble absolute

+ paths as needed, both in ensureDir() and plugin file slots.

+ ---

+  lib/rpmplugins.c | 20 +++++++++++++++++---

+  2 files changed, 36 insertions(+), 14 deletions(-)

+ 

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

+ index 703368c0d..f06fd7895 100644

+ --- a/lib/rpmplugins.c

+ +++ b/lib/rpmplugins.c

+ @@ -350,21 +350,31 @@ rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int ty

+      return rc;

+  }

+  

+ +static char *abspath(rpmfi fi, const char *path)

+ +{

+ +    if (*path == '/')

+ +	return xstrdup(path);

+ +    else

+ +	return rstrscat(NULL, rpmfiDN(fi), path, NULL);

+ +}

+ +

+  rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,

+  			       mode_t file_mode, rpmFsmOp op)

+  {

+      plugin_fsm_file_pre_func hookFunc;

+      int i;

+      rpmRC rc = RPMRC_OK;

+ +    char *apath = abspath(fi, path);

+  

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

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

+  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);

+ -	if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {

+ +	if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) {

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

+  	    rc = RPMRC_FAIL;

+  	}

+      }

+ +    free(apath);

+  

+      return rc;

+  }

+ @@ -375,14 +385,16 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,

+      plugin_fsm_file_post_func hookFunc;

+      int i;

+      rpmRC rc = RPMRC_OK;

+ +    char *apath = abspath(fi, path);

+  

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

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

+  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_post);

+ -	if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, res) == RPMRC_FAIL) {

+ +	if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op, res) == RPMRC_FAIL) {

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

+  	}

+      }

+ +    free(apath);

+  

+      return rc;

+  }

+ @@ -394,15 +406,17 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,

+      plugin_fsm_file_prepare_func hookFunc;

+      int i;

+      rpmRC rc = RPMRC_OK;

+ +    char *apath = abspath(fi, path);

+  

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

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

+  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);

+ -	if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {

+ +	if (hookFunc && hookFunc(plugin, fi, fd, apath, dest, file_mode, op) == RPMRC_FAIL) {

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

+  	    rc = RPMRC_FAIL;

+  	}

+      }

+ +    free(apath);

+  

+      return rc;

+  }

+ -- 

+ 2.41.0

+ 

The added file is too large to be shown here, see it at: 0001-Use-file-state-machine-from-rpm-4.19.patch
@@ -0,0 +1,34 @@ 

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

+ From: "Vladimir D. Seleznev" <vseleznv@altlinux.org>

+ Date: Tue, 13 Mar 2018 00:04:46 +0300

+ Subject: [PATCH 02/33] Add RPMTAG_IDENTITY reservation

+ 

+ This tag represents binary package build characteristic: if two binary

+ packages have equal RPMTAG_IDENTITY values, it means that these packages

+ have no significant differences.

+ 

+ One of the applications of RPMTAG_IDENTITY is reproducible build

+ verification.

+ 

+ This tag is reserved for ALT Linux Team and marked as unimplemented.

+ 

+ Signed-off-by: Vladimir D. Seleznev <vseleznv@altlinux.org>

+ ---

+  lib/rpmtag.h | 1 +

+  1 file changed, 1 insertion(+)

+ 

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

+ index 664561156..002492d20 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -369,6 +369,7 @@ typedef enum rpmTag_e {

+      RPMTAG_PAYLOADDIGEST	= 5092, /* s[] */

+      RPMTAG_PAYLOADDIGESTALGO	= 5093, /* i */

+      RPMTAG_AUTOINSTALLED	= 5094, /* i reservation (unimplemented) */

+ +    RPMTAG_IDENTITY		= 5095, /* s reservation (unimplemented) */

+      RPMTAG_MODULARITYLABEL	= 5096, /* s */

+  

+      RPMTAG_FIRSTFREE_TAG	/*!< internal */

+ -- 

+ 2.27.0

+ 

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

+ From 492823ca53f5666b82e94fcfdd422bdcd67005cb Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 11:07:38 +0300

+ Subject: [PATCH 03/33] Use lower-level headerPut() for file signing

+ 

+ Not supposed to affect behavior at all, but we'll need this in the

+ next step.

+ ---

+  sign/rpmsignfiles.c | 19 ++++++++++++++++---

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

+ 

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

+ index 61b73bd40..1fc127cb1 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -82,7 +82,7 @@ char *keypass)

+  

+  rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+  {

+ -    struct rpmtd_s digests;

+ +    struct rpmtd_s digests, td;

+      int algo;

+      int diglen;

+      uint32_t siglen;

+ @@ -110,7 +110,19 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+      headerDel(h, RPMTAG_FILESIGNATURELENGTH);

+      headerDel(h, RPMTAG_FILESIGNATURES);

+      siglen = signatureLength(algoname, diglen, key, keypass);

+ -    headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1);

+ +

+ +    rpmtdReset(&td);

+ +    td.tag = RPMTAG_FILESIGNATURELENGTH;

+ +    td.type = RPM_INT32_TYPE;

+ +    td.data = &siglen;

+ +    td.count = 1;

+ +    headerPut(h, &td, HEADERPUT_DEFAULT);

+ +

+ +    rpmtdReset(&td);

+ +    td.tag = RPMTAG_FILESIGNATURES;

+ +    td.type = RPM_STRING_ARRAY_TYPE;

+ +    td.data = NULL; /* set in the loop below */

+ +    td.count = 1;

+  

+      headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);

+      while ((digest = rpmtdNextString(&digests))) {

+ @@ -120,7 +132,8 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ -	if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {

+ +	td.data = &signature;

+ +	if (!headerPut(h, &td, HEADERPUT_APPEND)) {

+  	    free(signature);

+  	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));

+  	    rc = RPMRC_FAIL;

+ -- 

+ 2.27.0

+ 

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

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 11:44:10 +0300

+ Subject: [PATCH 04/33] Place file signatures into the signature header where

+  they belong

+ 

+ The original file signing puts the file signatures into the main header

+ immutable region, invalidating all previous signatures and digests so

+ the package no longer appears to be what it was when it came out of the

+ assembly line. Which is bad. Doing that also requires recalculating

+ everything again which is just added complexity, and since it adds

+ stuff to different place from the rest of the signing, it requires yet

+ complexity to deal with that. Moving the file signatures into the

+ signature header solves all that and allows removing a big pile of

+ now unnecessary code.

+ 

+ Because this means retrofitting tags bass-ackwards into the signature

+ header, the tag definitions are backwards to everything else. Other

+ options would certainly be possible, but this makes things look more

+ normal on the signature header side. "Users" only ever see the

+ unchanged file signature tags as they have always been.

+ 

+ This also means the signature header can be MUCH bigger than ever before,

+ so bump up the limit (to 64MB, arbitrary something for now), and

+ permit string array types to be migrated from the signature header

+ on package read.

+ 

+ Caveats:

+ This loses the check for identical existing signatures to keep the

+ complexity down, it's hardly a critical thing and can be added back later.

+ While file signing could now be done separately to other signing, that

+ is not handled here.

+ ---

+  lib/rpmtag.h        |   4 ++

+  sign/rpmgensig.c    | 161 +++-----------------------------------------

+  sign/rpmsignfiles.c |  14 ++--

+  sign/rpmsignfiles.h |   5 +-

+  4 files changed, 22 insertions(+), 162 deletions(-)

+ 

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

+ index 002492d20..46719ec75 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -65,6 +65,8 @@ typedef enum rpmTag_e {

+      RPMTAG_LONGARCHIVESIZE	= RPMTAG_SIG_BASE+15,	/* l */

+      /* RPMTAG_SIG_BASE+16 reserved */

+      RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */

+ +    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURELENGTH */

+ +    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURES */

+  

+      RPMTAG_NAME  		= 1000,	/* s */

+  #define	RPMTAG_N	RPMTAG_NAME	/* s */

+ @@ -425,6 +427,8 @@ typedef enum rpmSigTag_e {

+      RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */

+      RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */

+      RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,

+ +    RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 18,

+ +    RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 19,

+  } rpmSigTag;

+  

+  

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

+ index 8f77ad9c1..5fddb56ea 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -417,74 +417,12 @@ static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)

+      }

+  }

+  

+ -#ifdef WITH_IMAEVM

+ -static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp,

+ -			       off_t sigStart, off_t sigTargetSize,

+ -			       char *SHA256, char *SHA1, uint8_t *MD5)

+ -{

+ -    off_t archiveSize;

+ -    rpmRC rc = RPMRC_OK;

+ -

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

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),

+ -		rpm, Fstrerror(fd));

+ -	goto exit;

+ -    }

+ -

+ -    /* Get payload size from signature tag */

+ -    archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE);

+ -    if (!archiveSize) {

+ -	archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE);

+ -    }

+ -

+ -    /* Set reserved space to 0 */

+ -    rpmPushMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL);

+ -

+ -    /* Replace old digests in sigh */

+ -    rc = rpmGenerateSignature(SHA256, SHA1, MD5, sigTargetSize, archiveSize, fd);

+ -    if (rc != RPMRC_OK) {

+ -	rpmlog(RPMLOG_ERR, _("generateSignature failed\n"));

+ -	goto exit;

+ -    }

+ -

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

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),

+ -		rpm, Fstrerror(fd));

+ -	goto exit;

+ -    }

+ -

+ -    headerFree(*sigp);

+ -    rc = rpmReadSignature(fd, sigp, NULL);

+ -    if (rc != RPMRC_OK) {

+ -	rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));

+ -	goto exit;

+ -    }

+ -

+ -exit:

+ -    return rc;

+ -}

+ -#endif

+ -

+ -static rpmRC includeFileSignatures(FD_t fd, const char *rpm,

+ -				   Header *sigp, Header *hdrp,

+ -				   off_t sigStart, off_t headerStart)

+ +static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)

+  {

+  #ifdef WITH_IMAEVM

+ -    FD_t ofd = NULL;

+ -    char *trpm = NULL;

+ +    rpmRC rc;

+      char *key;

+      char *keypass;

+ -    char *SHA1 = NULL;

+ -    char *SHA256 = NULL;

+ -    uint8_t *MD5 = NULL;

+ -    off_t sigTargetSize;

+ -    rpmRC rc = RPMRC_OK;

+ -    struct rpmtd_s osigtd;

+ -    char *o_sha1 = NULL;

+ -

+ -    unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE);

+  

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

+  

+ @@ -494,94 +432,10 @@ static rpmRC includeFileSignatures(FD_t fd, const char *rpm,

+  	keypass = NULL;

+      }

+  

+ -    rc = rpmSignFiles(*hdrp, key, keypass);

+ -    if (rc != RPMRC_OK) {

+ -	goto exit;

+ -    }

+ -

+ -    *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE);

+ -    if (*hdrp == NULL) {

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("headerReload failed\n"));

+ -	goto exit;

+ -    }

+ -

+ -    ofd = rpmMkTempFile(NULL, &trpm);

+ -    if (ofd == NULL || Ferror(ofd)) {

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));

+ -	goto exit;

+ -    }

+ -

+ -    /* Copy archive to temp file */

+ -    if (copyFile(&fd, rpm, &ofd, trpm)) {

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));

+ -	goto exit;

+ -    }

+ -

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

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),

+ -		rpm, Fstrerror(fd));

+ -	goto exit;

+ -    }

+ +    rc = rpmSignFiles(*sigp, *hdrp, key, keypass);

+  

+ -    /* Start MD5 calculation */

+ -    fdInitDigestID(fd, PGPHASHALGO_MD5, RPMSIGTAG_MD5, 0);

+ -

+ -    /* Write header to rpm and recalculate digests */

+ -    fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMSIGTAG_SHA1, 0);

+ -    fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMSIGTAG_SHA256, 0);

+ -    rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES);

+ -    if (rc != RPMRC_OK) {

+ -	rpmlog(RPMLOG_ERR, _("headerWrite failed\n"));

+ -	goto exit;

+ -    }

+ -    fdFiniDigest(fd, RPMSIGTAG_SHA1, (void **)&SHA1, NULL, 1);

+ -    /* Only add SHA256 if it was there to begin with */

+ -    if (headerIsEntry(*sigp, RPMSIGTAG_SHA256))

+ -	fdFiniDigest(fd, RPMSIGTAG_SHA256, (void **)&SHA256, NULL, 1);

+ -

+ -    /* Copy archive from temp file */

+ -    if (Fseek(ofd, 0, SEEK_SET) < 0) {

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),

+ -		rpm, Fstrerror(fd));

+ -	goto exit;

+ -    }

+ -    if (copyFile(&ofd, trpm, &fd, rpm)) {

+ -	rc = RPMRC_FAIL;

+ -	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));

+ -	goto exit;

+ -    }

+ -    unlink(trpm);

+ -

+ -    sigTargetSize = Ftell(fd) - headerStart;

+ -    fdFiniDigest(fd, RPMSIGTAG_MD5, (void **)&MD5, NULL, 0);

+ -

+ -    if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) {

+ -	o_sha1 = xstrdup(osigtd.data);

+ -	rpmtdFreeData(&osigtd);

+ -    }

+ -

+ -    if (strcmp(SHA1, o_sha1) == 0)

+ -	rpmlog(RPMLOG_WARNING,

+ -	       _("%s already contains identical file signatures\n"),

+ -	       rpm);

+ -    else

+ -	replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA256, SHA1, MD5);

+ -

+ -exit:

+ -    free(trpm);

+ -    free(MD5);

+ -    free(SHA1);

+ -    free(SHA256);

+ -    free(o_sha1);

+      free(keypass);

+      free(key);

+ -    if (ofd)

+ -	(void) closeFile(&ofd);

+      return rc;

+  #else

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

+ @@ -674,13 +528,14 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)

+  	goto exit;

+      }

+  

+ -    if (signfiles) {

+ -	includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);

+ -    }

+ -

+      unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);

+      origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);

+  

+ +    if (signfiles) {

+ +	if (includeFileSignatures(&sigh, &h))

+ +	    goto exit;

+ +    }

+ +

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

+  	deleteSigs(sigh);

+      } else {

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

+ index 1fc127cb1..2dcc50400 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -80,7 +80,7 @@ char *keypass)

+      return siglen + 1;

+  }

+  

+ -rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+ +rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  {

+      struct rpmtd_s digests, td;

+      int algo;

+ @@ -107,19 +107,19 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+  	return RPMRC_FAIL;

+      }

+  

+ -    headerDel(h, RPMTAG_FILESIGNATURELENGTH);

+ -    headerDel(h, RPMTAG_FILESIGNATURES);

+ +    headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);

+ +    headerDel(sigh, RPMTAG_FILESIGNATURES);

+      siglen = signatureLength(algoname, diglen, key, keypass);

+  

+      rpmtdReset(&td);

+ -    td.tag = RPMTAG_FILESIGNATURELENGTH;

+ +    td.tag = RPMSIGTAG_FILESIGNATURELENGTH;

+      td.type = RPM_INT32_TYPE;

+      td.data = &siglen;

+      td.count = 1;

+ -    headerPut(h, &td, HEADERPUT_DEFAULT);

+ +    headerPut(sigh, &td, HEADERPUT_DEFAULT);

+  

+      rpmtdReset(&td);

+ -    td.tag = RPMTAG_FILESIGNATURES;

+ +    td.tag = RPMSIGTAG_FILESIGNATURES;

+      td.type = RPM_STRING_ARRAY_TYPE;

+      td.data = NULL; /* set in the loop below */

+      td.count = 1;

+ @@ -133,7 +133,7 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)

+  	    goto exit;

+  	}

+  	td.data = &signature;

+ -	if (!headerPut(h, &td, HEADERPUT_APPEND)) {

+ +	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {

+  	    free(signature);

+  	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));

+  	    rc = RPMRC_FAIL;

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

+ index 4163fafde..2ff623cdf 100644

+ --- a/sign/rpmsignfiles.h

+ +++ b/sign/rpmsignfiles.h

+ @@ -9,14 +9,15 @@ extern "C" {

+  #endif

+  

+  /**

+ - * Sign file digests in header and store the signatures in header

+ + * Sign file digests in header into signature header

+ + * @param sigh		package signature header

+   * @param h		package header

+   * @param key		signing key

+   * @param keypass	signing key password

+   * @return		RPMRC_OK on success

+   */

+  RPM_GNUC_INTERNAL

+ -rpmRC rpmSignFiles(Header h, const char *key, char *keypass);

+ +rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass);

+  

+  #ifdef _cplusplus

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,30 @@ 

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 14:40:05 +0300

+ Subject: [PATCH 05/33] Unbreak file signing from previous commit

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

+ 

+ Commit f558e886050c4e98f6cdde391df679a411b3f62c essentially broke

+ file signing because signatures never get migrated into the package

+ header. This is what happens when you play around with too many

+ variants of the same thing and forget to test what ultimately got

+ committed, which was subtly different from anything else so far... :(

+ ---

+  lib/package.c | 2 ++

+  1 file changed, 2 insertions(+)

+ 

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

+ index 211fd3902..b7d996a12 100644

+ --- a/lib/package.c

+ +++ b/lib/package.c

+ @@ -43,6 +43,8 @@ struct taglate_s {

+      { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 },

+      /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */

+      { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },

+ +    { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },

+ +    { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },

+      { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },

+      { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },

+      { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },

+ -- 

+ 2.27.0

+ 

@@ -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([rpmmacro.at])

+  m4_include([rpmpython.at])

+  m4_include([rpmdepmatch.at])

+ +m4_include([rpm2extents.at])

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,71 @@ 

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 14:43:58 +0300

+ Subject: [PATCH 06/33] Assume failure in rpmSignFiles()

+ 

+ Doesn't make it any shorter yet, but makes more sense in the next steps.

+ Just refactoring.

+ ---

+  sign/rpmsignfiles.c | 16 ++++++++--------

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

+ 

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

+ index 2dcc50400..c1d227a07 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -88,23 +88,24 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+      uint32_t siglen;

+      const char *algoname;

+      const char *digest;

+ -    char *signature;

+ -    rpmRC rc = RPMRC_OK;

+ +    char *signature = NULL;

+ +    rpmRC rc = RPMRC_FAIL;

+  

+ +    rpmtdReset(&digests);

+      algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);

+      if (!algo) {

+          /* use default algorithm */

+          algo = PGPHASHALGO_MD5;

+      } else if (algo < 0 || algo >= ARRAY_SIZE(hash_algo_name)) {

+  	rpmlog(RPMLOG_ERR, _("File digest algorithm id is invalid"));

+ -	return RPMRC_FAIL;

+ +	goto exit;

+      }

+  

+      diglen = rpmDigestLength(algo);

+      algoname = hash_algo_name[algo];

+      if (!algoname) {

+  	rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));

+ -	return RPMRC_FAIL;

+ +	goto exit;

+      }

+  

+      headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);

+ @@ -129,20 +130,19 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  	signature = signFile(algoname, digest, diglen, key, keypass);

+  	if (!signature) {

+  	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));

+ -	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+  	td.data = &signature;

+  	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {

+ -	    free(signature);

+  	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));

+ -	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ -	free(signature);

+ +	signature = _free(signature);

+      }

+ +    rc = RPMRC_OK;

+  

+  exit:

+ +    free(signature);

+      rpmtdFreeData(&digests);

+      return rc;

+  }

+ -- 

+ 2.27.0

+ 

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

+ From 0a7318ab4467d3156723c7a265dbd3456b8d1e20 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 14:44:18 +0300

+ Subject: [PATCH 07/33] Use rpm file info sets instead of header for retrieving

+  file data

+ 

+ Simplifies the code a little, but more imporantly it avoids duplicating

+ code and special knowledge like the default digest algo and converting

+ hex to binary. As a side-effect, this fixes RPMTAG_FILESIGNATURELENGTH

+ inadvertly getting added into packages that have no files at all.

+ ---

+  sign/rpmsignfiles.c | 36 +++++++++++++++++-------------------

+  1 file changed, 17 insertions(+), 19 deletions(-)

+ 

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

+ index c1d227a07..de7a73cfd 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

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

+  #include "imaevm.h"

+  

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

+ -#include <rpm/rpmstring.h>	/* rnibble */

+ +#include <rpm/rpmfi.h>

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

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

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

+ @@ -32,7 +32,7 @@ static const char *hash_algo_name[] = {

+  

+  #define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))

+  

+ -static char *signFile(const char *algo, const char *fdigest, int diglen,

+ +static char *signFile(const char *algo, const uint8_t *fdigest, int diglen,

+  const char *key, char *keypass)

+  {

+      char *fsignature;

+ @@ -40,15 +40,11 @@ const char *key, char *keypass)

+      unsigned char signature[MAX_SIGNATURE_LENGTH];

+      int siglen;

+  

+ -    /* convert file digest hex to binary */

+ -    memset(digest, 0, diglen);

+      /* some entries don't have a digest - we return an empty signature */

+ -    if (strlen(fdigest) != diglen * 2)

+ +    memset(digest, 0, diglen);

+ +    if (memcmp(digest, fdigest, diglen) == 0)

+          return strdup("");

+  

+ -    for (int i = 0; i < diglen; ++i, fdigest += 2)

+ -	digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);

+ -

+      /* prepare file signature */

+      memset(signature, 0, MAX_SIGNATURE_LENGTH);

+      signature[0] = '\x03';

+ @@ -82,21 +78,23 @@ char *keypass)

+  

+  rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  {

+ -    struct rpmtd_s digests, td;

+ +    struct rpmtd_s td;

+      int algo;

+      int diglen;

+      uint32_t siglen;

+      const char *algoname;

+ -    const char *digest;

+ +    const uint8_t *digest;

+      char *signature = NULL;

+      rpmRC rc = RPMRC_FAIL;

+ +    rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);

+ +

+ +    if (rpmfiFC(fi) == 0) {

+ +	rc = RPMRC_OK;

+ +	goto exit;

+ +    }

+  

+ -    rpmtdReset(&digests);

+ -    algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);

+ -    if (!algo) {

+ -        /* use default algorithm */

+ -        algo = PGPHASHALGO_MD5;

+ -    } else if (algo < 0 || algo >= ARRAY_SIZE(hash_algo_name)) {

+ +    algo = rpmfiDigestAlgo(fi);

+ +    if (algo >= ARRAY_SIZE(hash_algo_name)) {

+  	rpmlog(RPMLOG_ERR, _("File digest algorithm id is invalid"));

+  	goto exit;

+      }

+ @@ -125,8 +123,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+      td.data = NULL; /* set in the loop below */

+      td.count = 1;

+  

+ -    headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);

+ -    while ((digest = rpmtdNextString(&digests))) {

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

+ +	digest = rpmfiFDigest(fi, NULL, NULL);

+  	signature = signFile(algoname, digest, diglen, key, keypass);

+  	if (!signature) {

+  	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));

+ @@ -143,6 +141,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  

+  exit:

+      free(signature);

+ -    rpmtdFreeData(&digests);

+ +    rpmfiFree(fi);

+      return rc;

+  }

+ -- 

+ 2.27.0

+ 

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

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 15:04:38 +0300

+ Subject: [PATCH 08/33] Eliminate redundant signature length calculation

+  function

+ 

+ The actual signing function knows the length already, we just need to

+ return it and then we can insert it if there was anything at all

+ to sign.

+ ---

+  sign/rpmsignfiles.c | 40 ++++++++++++++--------------------------

+  1 file changed, 14 insertions(+), 26 deletions(-)

+ 

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

+ index de7a73cfd..9fe6e6d41 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -33,7 +33,7 @@ static const char *hash_algo_name[] = {

+  #define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))

+  

+  static char *signFile(const char *algo, const uint8_t *fdigest, int diglen,

+ -const char *key, char *keypass)

+ +const char *key, char *keypass, uint32_t *siglenp)

+  {

+      char *fsignature;

+      unsigned char digest[diglen];

+ @@ -56,32 +56,18 @@ const char *key, char *keypass)

+  	return NULL;

+      }

+  

+ +    *siglenp = siglen + 1;

+      /* convert file signature binary to hex */

+      fsignature = pgpHexStr(signature, siglen+1);

+      return fsignature;

+  }

+  

+ -static uint32_t signatureLength(const char *algo, int diglen, const char *key,

+ -char *keypass)

+ -{

+ -    unsigned char digest[diglen];

+ -    unsigned char signature[MAX_SIGNATURE_LENGTH];

+ -

+ -    memset(digest, 0, diglen);

+ -    memset(signature, 0, MAX_SIGNATURE_LENGTH);

+ -    signature[0] = '\x03';

+ -

+ -    uint32_t siglen = sign_hash(algo, digest, diglen, key, keypass,

+ -				signature+1);

+ -    return siglen + 1;

+ -}

+ -

+  rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  {

+      struct rpmtd_s td;

+      int algo;

+      int diglen;

+ -    uint32_t siglen;

+ +    uint32_t siglen = 0;

+      const char *algoname;

+      const uint8_t *digest;

+      char *signature = NULL;

+ @@ -108,14 +94,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  

+      headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);

+      headerDel(sigh, RPMTAG_FILESIGNATURES);

+ -    siglen = signatureLength(algoname, diglen, key, keypass);

+ -

+ -    rpmtdReset(&td);

+ -    td.tag = RPMSIGTAG_FILESIGNATURELENGTH;

+ -    td.type = RPM_INT32_TYPE;

+ -    td.data = &siglen;

+ -    td.count = 1;

+ -    headerPut(sigh, &td, HEADERPUT_DEFAULT);

+  

+      rpmtdReset(&td);

+      td.tag = RPMSIGTAG_FILESIGNATURES;

+ @@ -125,7 +103,7 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  

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

+  	digest = rpmfiFDigest(fi, NULL, NULL);

+ -	signature = signFile(algoname, digest, diglen, key, keypass);

+ +	signature = signFile(algoname, digest, diglen, key, keypass, &siglen);

+  	if (!signature) {

+  	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));

+  	    goto exit;

+ @@ -137,6 +115,16 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  	}

+  	signature = _free(signature);

+      }

+ +

+ +    if (siglen > 0) {

+ +	rpmtdReset(&td);

+ +	td.tag = RPMSIGTAG_FILESIGNATURELENGTH;

+ +	td.type = RPM_INT32_TYPE;

+ +	td.data = &siglen;

+ +	td.count = 1;

+ +	headerPut(sigh, &td, HEADERPUT_DEFAULT);

+ +    }

+ +

+      rc = RPMRC_OK;

+  

+  exit:

+ -- 

+ 2.27.0

+ 

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

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

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 15:20:16 +0300

+ Subject: [PATCH 09/33] Drop redundant check on hash algo name

+ 

+ The array is already size-validated, me thinks we can safely

+ assume the array to be populated with non-NULL values.

+ ---

+  sign/rpmsignfiles.c | 4 ----

+  1 file changed, 4 deletions(-)

+ 

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

+ index 9fe6e6d41..4876f66f2 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -87,10 +87,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  

+      diglen = rpmDigestLength(algo);

+      algoname = hash_algo_name[algo];

+ -    if (!algoname) {

+ -	rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));

+ -	goto exit;

+ -    }

+  

+      headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);

+      headerDel(sigh, RPMTAG_FILESIGNATURES);

+ -- 

+ 2.27.0

+ 

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

+ From 3461bd52ef2d403de1c420962aac52834f6e4b34 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Tue, 10 Oct 2017 15:20:16 +0300

+ Subject: [PATCH 10/33] Drop redundant check on hash algo name

+ 

+ The array is already size-validated, me thinks we can safely

+ assume the array to be populated with non-NULL values.

+ ---

+  lib/rpmtag.h | 8 ++++----

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

+ 

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

+ index 46719ec75..40ff5fa5d 100644

+ --- a/lib/rpmtag.h

+ +++ b/lib/rpmtag.h

+ @@ -65,8 +65,8 @@ typedef enum rpmTag_e {

+      RPMTAG_LONGARCHIVESIZE	= RPMTAG_SIG_BASE+15,	/* l */

+      /* RPMTAG_SIG_BASE+16 reserved */

+      RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */

+ -    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURELENGTH */

+ -    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURES */

+ +    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */

+ +    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */

+  

+      RPMTAG_NAME  		= 1000,	/* s */

+  #define	RPMTAG_N	RPMTAG_NAME	/* s */

+ @@ -427,8 +427,8 @@ typedef enum rpmSigTag_e {

+      RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */

+      RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */

+      RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,

+ -    RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 18,

+ -    RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 19,

+ +    RPMSIGTAG_FILESIGNATURES           = RPMTAG_SIG_BASE + 18,

+ +    RPMSIGTAG_FILESIGNATURELENGTH      = RPMTAG_SIG_BASE + 19,

+  } rpmSigTag;

+  

+  

+ -- 

+ 2.27.0

+ 

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

+ +

+  int _print_pkts = 0;

+  

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

+ @@ -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,129 @@ 

+ From 9e1a49197a6ddd0e984c12c9dc15fe7af435b611 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Mon, 2 Mar 2020 13:56:33 +0200

+ Subject: [PATCH 11/33] Generalize file signing to use a generic flags field in

+  signing arguments

+ 

+ There will be any number of signing flags in the future, and we don't

+ want to break the ABI for every single one of them by adding new

+ fields to the sign argument struct. Replace the signfiles field

+ with a bitfield in the common rpm style. No functional changes.

+ 

+ This is an API change of course, but we'll have to bump the soname for

+ the next release anyway so might as well do it now.

+ ---

+  rpmsign.c        | 11 ++++++-----

+  sign/rpmgensig.c |  8 ++++----

+  sign/rpmsign.h   |  8 +++++++-

+  3 files changed, 17 insertions(+), 10 deletions(-)

+ 

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

+ index 1a5cd59c2..57cb36919 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

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

+  static int mode = MODE_NONE;

+  

+  #ifdef WITH_IMAEVM

+ -static int signfiles = 0, fskpass = 0;

+ +static int fskpass = 0;

+  static char * fileSigningKey = NULL;

+  #endif

+  

+ @@ -33,7 +33,8 @@ static struct poptOption signOptsTable[] = {

+      { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,

+  	N_("delete package signatures"), NULL },

+  #ifdef WITH_IMAEVM

+ -    { "signfiles", '\0', POPT_ARG_NONE, &signfiles, 0,

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

+ +	&sargs.signflags, RPMSIGN_FLAG_IMA,

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

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

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

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

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

+      }

+  

+ -    if (signfiles) {

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

+  	char *fileSigningKeyPassword = NULL;

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

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

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

+  	    free(fileSigningKeyPassword);

+  	}

+  

+ -	sargs->signfiles = 1;

+ +	sargs->signflags |= RPMSIGN_FLAG_IMA;

+  	free(key);

+      }

+  #endif

+ @@ -163,7 +164,7 @@ int main(int argc, char *argv[])

+      }

+  

+  #ifdef WITH_IMAEVM

+ -    if (fileSigningKey && !signfiles) {

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

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

+      }

+  #endif

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

+ index 5fddb56ea..1981981f4 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -472,10 +472,10 @@ static int checkPkg(FD_t fd, char **msg)

+   * Create/modify elements in signature header.

+   * @param rpm		path to package

+   * @param deleting	adding or deleting signature?

+ - * @param signfiles	sign files if non-zero

+ + * @param flags

+   * @return		0 on success, -1 on error

+   */

+ -static int rpmSign(const char *rpm, int deleting, int signfiles)

+ +static int rpmSign(const char *rpm, int deleting, int flags)

+  {

+      FD_t fd = NULL;

+      FD_t ofd = NULL;

+ @@ -531,7 +531,7 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)

+      unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);

+      origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);

+  

+ -    if (signfiles) {

+ +    if (flags & RPMSIGN_FLAG_IMA) {

+  	if (includeFileSignatures(&sigh, &h))

+  	    goto exit;

+      }

+ @@ -682,7 +682,7 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args)

+  	}

+      }

+  

+ -    rc = rpmSign(path, 0, args ? args->signfiles : 0);

+ +    rc = rpmSign(path, 0, args ? args->signflags : 0);

+  

+      if (args) {

+  	if (args->hashalgo) {

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

+ index bed8d6245..545e80d2d 100644

+ --- a/sign/rpmsign.h

+ +++ b/sign/rpmsign.h

+ @@ -13,10 +13,16 @@

+  extern "C" {

+  #endif

+  

+ +enum rpmSignFlags_e {

+ +    RPMSIGN_FLAG_NONE		= 0,

+ +    RPMSIGN_FLAG_IMA		= (1 << 0),

+ +};

+ +typedef rpmFlags rpmSignFlags;

+ +

+  struct rpmSignArgs {

+      char *keyid;

+      pgpHashAlgo hashalgo;

+ -    int signfiles;

+ +    rpmSignFlags signflags;

+      /* ... what else? */

+  };

+  

+ -- 

+ 2.27.0

+ 

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

+ From 031b8481a0dfe875e9cf0f5d440b9379a62651a6 Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Mon, 2 Mar 2020 14:47:26 +0200

+ Subject: [PATCH 12/33] Stop adding rpm v3 header+payload signatures by default

+  where not needed

+ 

+ On packages where a separate payload digest exists (ie those built with

+ rpm >= 4.14), rpm v3 header+payload signatures are nothing but expensive

+ legacy baggage, as the payload digest will be signed by a header-only

+ signature already, without having to recalculate the entire file.

+ 

+ Automatically detect the payload digest presence and only add V3

+ signatures on packages that need it, but also add an override switch

+ to force their addition if needed for compatibility or so. A particular

+ use-case would be ability to signature-level verify the entire package

+ on rpm older than 4.14.

+ 

+ Fixes: #863

+ ---

+  doc/rpmsign.8      |  9 +++++++++

+  rpmsign.c          |  3 +++

+  sign/rpmgensig.c   | 24 +++++++++++++++++-------

+  sign/rpmsign.h     |  1 +

+  tests/rpmsigdig.at | 36 ++++++++++++++++++++++++++++++++++--

+  5 files changed, 64 insertions(+), 9 deletions(-)

+ 

+ diff --git a/doc/rpmsign.8 b/doc/rpmsign.8

+ index d895a3b8c..f7ceae89b 100644

+ --- a/doc/rpmsign.8

+ +++ b/doc/rpmsign.8

+ @@ -11,6 +11,7 @@ rpmsign \- RPM Package Signing

+  

+  .SS "rpmsign-options"

+  .PP

+ +[\fb--rpmv3\fR]

+  [\fb--fskpath \fIKEY\fb\fR] [\fB--signfiles\fR]

+  

+  .SH DESCRIPTION

+ @@ -32,6 +33,14 @@ Delete all signatures from each package \fIPACKAGE_FILE\fR given.

+  .SS "SIGN OPTIONS"

+  .PP

+  .TP

+ +\fB--rpmv3\fR

+ +Force RPM V3 header+payload signature addition.

+ +These are expensive and redundant baggage on packages where a separate

+ +payload digest exists (packages built with rpm >= 4.14).  Rpm will

+ +automatically detect the need for V3 signatures, but this option can be

+ +used to force their creation if the packages must be fully 

+ +signature verifiable with rpm < 4.14 or other interoperability reasons.

+ +.TP

+  \fB--fskpath \fIKEY\fB\fR

+  Used with \fB--signfiles\fR, use file signing key \fIKey\fR.

+  .TP

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

+ index 57cb36919..a74948ba8 100644

+ --- a/rpmsign.c

+ +++ b/rpmsign.c

+ @@ -32,6 +32,9 @@ 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 },

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

+ +	&sargs.signflags, RPMSIGN_FLAG_RPMV3,

+ +	N_("create rpm v3 header+payload signatures") },

+  #ifdef WITH_IMAEVM

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

+  	&sargs.signflags, RPMSIGN_FLAG_IMA,

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

+ index 1981981f4..4903a4de1 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -377,14 +377,17 @@ static int replaceSignature(Header sigh, sigTarget sigt_v3, sigTarget sigt_v4)

+  

+      if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)

+  	goto exit;

+ -    rpmtdFree(sigtd);

+  

+ -    /* Assume the same signature test holds for v3 signature too */

+ -    if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)

+ -	goto exit;

+ +    if (sigt_v3) {

+ +	rpmtdFree(sigtd);

+  

+ -    if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)

+ -	goto exit;

+ +	/* Assume the same signature test holds for v3 signature too */

+ +	if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)

+ +	    goto exit;

+ +

+ +	if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)

+ +	    goto exit;

+ +    }

+  

+      rc = 0;

+  exit:

+ @@ -528,6 +531,12 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	goto exit;

+      }

+  

+ +    /* Always add V3 signatures if no payload digest present */

+ +    if (!(headerIsEntry(h, RPMTAG_PAYLOADDIGEST) ||

+ +	  headerIsEntry(h, RPMTAG_PAYLOADDIGESTALT))) {

+ +	flags |= RPMSIGN_FLAG_RPMV3;

+ +    }

+ +

+      unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);

+      origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);

+  

+ @@ -540,6 +549,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	deleteSigs(sigh);

+      } else {

+  	/* Signature target containing header + payload */

+ +	int v3 = (flags & RPMSIGN_FLAG_RPMV3);

+  	sigt_v3.fd = fd;

+  	sigt_v3.start = headerStart;

+  	sigt_v3.fileName = rpm;

+ @@ -549,7 +559,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	sigt_v4 = sigt_v3;

+  	sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES);

+  

+ -	res = replaceSignature(sigh, &sigt_v3, &sigt_v4);

+ +	res = replaceSignature(sigh, v3 ? &sigt_v3 : NULL, &sigt_v4);

+  	if (res != 0) {

+  	    if (res == 1) {

+  		rpmlog(RPMLOG_WARNING,

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

+ index 545e80d2d..7a770d879 100644

+ --- a/sign/rpmsign.h

+ +++ b/sign/rpmsign.h

+ @@ -16,6 +16,7 @@ extern "C" {

+  enum rpmSignFlags_e {

+      RPMSIGN_FLAG_NONE		= 0,

+      RPMSIGN_FLAG_IMA		= (1 << 0),

+ +    RPMSIGN_FLAG_RPMV3		= (1 << 1),

+  };

+  typedef rpmFlags rpmSignFlags;

+  

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

+ index 880e5edd0..12e2221b3 100644

+ --- a/tests/rpmsigdig.at

+ +++ b/tests/rpmsigdig.at

+ @@ -391,7 +391,7 @@ AT_CLEANUP

+  

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

+  # Test --addsign

+ -AT_SETUP([rpmsign --addsign <unsigned>])

+ +AT_SETUP([rpmsign --addsign --rpmv3 <unsigned>])

+  AT_KEYWORDS([rpmsign signature])

+  AT_CHECK([

+  RPMDB_CLEAR

+ @@ -399,7 +399,7 @@ RPMDB_INIT

+  rm -rf "${TOPDIR}"

+  

+  cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/

+ -run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null

+ +run rpmsign --key-id 1964C5FC --rpmv3 --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null

+  echo PRE-IMPORT

+  runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest

+  echo POST-IMPORT

+ @@ -424,6 +424,38 @@ POST-DELSIGN

+  [])

+  AT_CLEANUP

+  

+ +# Test --addsign

+ +AT_SETUP([rpmsign --addsign <unsigned>])

+ +AT_KEYWORDS([rpmsign signature])

+ +AT_CHECK([

+ +RPMDB_CLEAR

+ +RPMDB_INIT

+ +rm -rf "${TOPDIR}"

+ +

+ +cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/

+ +run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null

+ +echo PRE-IMPORT

+ +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest

+ +echo POST-IMPORT

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

+ +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest

+ +run rpmsign --delsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null

+ +echo POST-DELSIGN

+ +runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest

+ +],

+ +[0],

+ +[PRE-IMPORT

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

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

+ +POST-IMPORT

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

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

+ +POST-DELSIGN

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

+ +],

+ +[])

+ +AT_CLEANUP

+ +

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

+  # Test --delsign

+  AT_SETUP([rpmsign --delsign <package>])

+ -- 

+ 2.27.0

+ 

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

+ -

+  int _print_pkts = 0;

+  

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

+ @@ -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,27 @@ 

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

+ From: Igor Kanyuka <ikanyuka@fb.com>

+ Date: Thu, 29 Apr 2021 18:24:48 -0700

+ Subject: [PATCH 13/33] RPMTAG_PAYLOADDIGESTALT is not backported here, don't

+  check if it's in the header

+ 

+ ---

+  sign/rpmgensig.c | 3 +--

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

+ 

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

+ index 4903a4de1..a6e37e71b 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -532,8 +532,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+      }

+  

+      /* Always add V3 signatures if no payload digest present */

+ -    if (!(headerIsEntry(h, RPMTAG_PAYLOADDIGEST) ||

+ -	  headerIsEntry(h, RPMTAG_PAYLOADDIGESTALT))) {

+ +    if (!headerIsEntry(h, RPMTAG_PAYLOADDIGEST)) {

+  	flags |= RPMSIGN_FLAG_RPMV3;

+      }

+  

+ -- 

+ 2.27.0

+ 

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

+ From 6398807623ca24eafac0607b3d09b244cc5dfd5d Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Fri, 27 Mar 2020 15:09:25 +0200

+ Subject: [PATCH 14/33] Drop support for dmalloc

+ 

+ Last dmalloc release is from 2007, and these days there are plenty of

+ other, maintained tools for debugging memory issues.

+ ---

+  configure.ac | 7 -------

+  debug.h      | 4 ----

+  2 files changed, 11 deletions(-)

+ 

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

+ index 57a4f4001..3c102d5eb 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -1030,13 +1030,6 @@ AS_IF([test "$enable_plugins" != no],[

+  ])

+  AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])

+  

+ -with_dmalloc=no

+ -AC_ARG_WITH(dmalloc, [AS_HELP_STRING([--with-dmalloc],[build with dmalloc debugging support])])

+ -if test "$with_dmalloc" = yes ; then

+ -  AC_DEFINE(DMALLOC, 1, [Build with dmalloc support?])

+ -  LIBS="$LIBS -ldmalloc"

+ -fi

+ -

+  user_with_uid0=$(awk -F: '$3==0 {print $1;exit}' /etc/passwd)

+  group_with_gid0=$(awk -F: '$3==0 {print $1;exit}' /etc/group)

+  AC_DEFINE_UNQUOTED([UID_0_USER],["$user_with_uid0"],[Get the user name having userid 0])

+ diff --git a/debug.h b/debug.h

+ index 3d34ea010..db7ea1df9 100644

+ --- a/debug.h

+ +++ b/debug.h

+ @@ -6,10 +6,6 @@

+  

+  #include <assert.h>

+  

+ -#ifdef	DMALLOC

+ -#include <dmalloc.h>

+ -#endif

+ -

+  #define RPMDBG_TOSTR(a)		RPMDBG_TOSTR_ARG(a)

+  #define RPMDBG_TOSTR_ARG(a)	#a

+  

+ -- 

+ 2.27.0

+ 

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

+ 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,14 @@ function runroot()

+      )

+  }

+  

+ +function runroot_plugins()

+ +{

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

+  {

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

+ -- 

+ 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

+  

+  RPM_XFAIL=${RPM_XFAIL-1}

+  

+ +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 run()

+  {

+      "$@" --define "_tmppath ${RPMTEST}/tmp" --define "_topdir ${TOPDIR}" --dbpath="${RPMTEST}/var/lib/rpm/"

+ 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,210 @@ 

+ 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,8 +428,9 @@ typedef enum rpmSigTag_e {

+      RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */

+      RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */

+      RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,

+ -    RPMSIGTAG_FILESIGNATURES           = RPMTAG_SIG_BASE + 18,

+ -    RPMSIGTAG_FILESIGNATURELENGTH      = RPMTAG_SIG_BASE + 19,

+ +    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 */

+      int signaturelength;	/*!< File signature length */

+ +    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->flangs = _free(fi->flangs);

+  	fi->digests = _free(fi->digests);

+  	fi->signatures = _free(fi->signatures);

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

+      }

+  

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

+ @@ -117,6 +117,7 @@ struct rpmfiles_s {

+      int digestalgo;		/*!< File digest algorithm */

+      int signaturelength;	/*!< File signature length */

+      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,281 @@ 

+ 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,35 @@ 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 audit library.

+ +AC_ARG_WITH(audit,

+ +AS_HELP_STRING([--with-audit],[Linux audit plugin]),

+ +with_audit=$withval,

+ +with_audit=auto)

+ +

+ +WITH_AUDIT_LIB=

+ +AS_IF([test "$enable_plugins" != no],[

+ +  AS_IF([test "x$with_audit" != xno],[

+ +    AC_SEARCH_LIBS([audit_open],[audit],[

+ +      WITH_AUDIT_LIB="$ac_res"

+ +      AC_DEFINE(WITH_AUDIT, 1, [libaudit support])

+ +      with_audit=yes

+ +    ],[

+ +      if test "x$with_audit" != xauto; then

+ +        AC_MSG_ERROR([missing audit library])

+ +      fi

+ +    ])

+ +  ])

+ +])

+ +AC_SUBST(WITH_AUDIT_LIB)

+ +AM_CONDITIONAL(AUDIT,[test "$with_audit" = yes])

+ +

+  user_with_uid0=$(awk -F: '$3==0 {print $1;exit}' /etc/passwd)

+  group_with_gid0=$(awk -F: '$3==0 {print $1;exit}' /etc/group)

+  AC_DEFINE_UNQUOTED([UID_0_USER],["$user_with_uid0"],[Get the user name having userid 0])

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

+  # performance for rotational disks)

+  #%_flush_io	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

+  

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

+ 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 @@ fapolicyd_la_sources = fapolicyd.c

+  fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la

+  plugins_LTLIBRARIES += fapolicyd.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,91 @@ 

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

+ @@ -1255,10 +1256,16 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)

+  	    .signature = RPMRC_NOTFOUND,

+  	    .vfylevel = vfylevel,

+  	};

+ +	int verified = 0;

+  	rpmRC prc = RPMRC_FAIL;

+  

+  	rpmtsNotify(ts, p, RPMCALLBACK_VERIFY_PROGRESS, oc++, total);

+  	FD_t fd = rpmtsNotify(ts, p, RPMCALLBACK_INST_OPEN_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);

+ @@ -1267,8 +1274,11 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)

+  	if (prc == RPMRC_OK)

+  	    prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);

+  

+ +	    verified = vd.signature == RPMRC_OK;

+ +	}

+ +

+  	/* Record verify result, signatures only for now */

+ -	rpmteSetVerified(p, vd.signature == RPMRC_OK);

+ +	rpmteSetVerified(p, verified);

+  

+  	if (prc)

+  	    rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0);

+ 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,386 @@ 

+ From: Richard Phibel <richardphibel@meta.com>

+ 

+ Subject: RPM with Copy on Write: add deny list mechanism

+ 

+ commit 3431550e6c92ba4bc6d091cb244f70c158dfbbaa

+ Author: Richard Phibel <richardphibel@meta.com>

+ Date:   Wed Oct 19 23:05:17 2022 +0200

+ 

+     RPM with Copy on Write: add deny list mechanism

+     

+     A couple of issues were encountered when using RPM CoW for some

+     packages. This change adds a deny list mechanism to disable RPM CoW for

+     specific packages.

+ 

+ Signed-off-by: Richard Phibel <richardphibel@meta.com>

+ 

+ diff --git a/build/pack.c b/build/pack.c

+ index 8d6f74935ebb8a4d65aa2bcb666825a99162be9c..e2f05b6412d3e0d814a1160a0dcdfad5c323a8f8 100644

+ --- a/build/pack.c

+ +++ b/build/pack.c

+ @@ -493,7 +493,7 @@ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp,

+      }

+  

+      /* Write the lead section into the package. */

+ -    if (rpmLeadWrite(fd, pkg->header)) {

+ +    if (rpmLeadWriteFromHeader(fd, pkg->header)) {

+  	rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd));

+  	goto exit;

+      }

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

+ index 90bd0d8a719353e8965c140b40e2dceef80a2ed1..fd41abbf6b4df07afa2caf1c47d9724765ee84e8 100644

+ --- a/lib/package.c

+ +++ b/lib/package.c

+ @@ -412,11 +412,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp)

+      Header h = NULL;

+      Header sigh = NULL;

+  

+ -    rpmRC rc = rpmLeadRead(fd, &msg);

+ -    if (rc != RPMRC_OK)

+ -	goto exit;

+ -

+ -    rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg);

+ +    rpmRC rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg);

+      if (rc != RPMRC_OK)

+  	goto exit;

+  

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

+ index 45b1c6f8edacb65549ba8d321de8f6ce8cef4503..82105122724a8efb071aecefdb278ef96ea5e70d 100644

+ --- a/lib/rpmlead.c

+ +++ b/lib/rpmlead.c

+ @@ -24,24 +24,6 @@ static unsigned char const lead_magic[] = {

+      RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3

+  };

+  

+ -/** \ingroup lead

+ - * The lead data structure.

+ - * The lead needs to be 8 byte aligned.

+ - * @deprecated The lead (except for signature_type) is legacy.

+ - * @todo Don't use any information from lead.

+ - */

+ -struct rpmlead_s {

+ -    unsigned char magic[4];

+ -    unsigned char major;

+ -    unsigned char minor;

+ -    short type;

+ -    short archnum;

+ -    char name[66];

+ -    short osnum;

+ -    short signature_type;       /*!< Signature header type (RPMSIG_HEADERSIG) */

+ -    char reserved[16];      /*!< Pad to 96 bytes -- 8 byte aligned! */

+ -};

+ -

+  static int rpmLeadFromHeader(Header h, struct rpmlead_s *l)

+  {

+      if (h != NULL) {

+ @@ -70,13 +52,23 @@ static int rpmLeadFromHeader(Header h, struct rpmlead_s *l)

+  }

+  

+  /* The lead needs to be 8 byte aligned */

+ -rpmRC rpmLeadWrite(FD_t fd, Header h)

+ +rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h)

+  {

+      rpmRC rc = RPMRC_FAIL;

+      struct rpmlead_s l;

+  

+ -    if (rpmLeadFromHeader(h, &l)) {

+ -	

+ +    if (rpmLeadFromHeader(h, &l)) {	

+ +	rc = rpmLeadWrite(fd, l);

+ +    }

+ +

+ +    return rc;

+ +}

+ +

+ +/* The lead needs to be 8 byte aligned */

+ +rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l)

+ +{

+ +    rpmRC rc = RPMRC_FAIL;

+ +

+  	l.type = htons(l.type);

+  	l.archnum = htons(l.archnum);

+  	l.osnum = htons(l.osnum);

+ @@ -84,7 +76,6 @@ rpmRC rpmLeadWrite(FD_t fd, Header h)

+  	    

+  	if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l))

+  	    rc = RPMRC_OK;

+ -    }

+  

+      return rc;

+  }

+ @@ -107,6 +98,11 @@ static rpmRC rpmLeadCheck(struct rpmlead_s *lead, char **msg)

+  }

+  

+  rpmRC rpmLeadRead(FD_t fd, char **emsg)

+ +{

+ +    return rpmLeadReadAndReturn(fd, emsg, NULL);

+ +}

+ +

+ +rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret)

+  {

+      rpmRC rc = RPMRC_OK;

+      struct rpmlead_s l;

+ @@ -136,5 +132,8 @@ rpmRC rpmLeadRead(FD_t fd, char **emsg)

+  	    free(err);

+      }

+  

+ +	if (ret)

+ +		*ret = l;

+ +

+      return rc;

+  }

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

+ index 9d86a8d73b3250d3c306b3a3ac4a33486e6920ec..8a592abc1d0e69822f438c4c7b248cce1cb5ee72 100644

+ --- a/lib/rpmlead.h

+ +++ b/lib/rpmlead.h

+ @@ -19,13 +19,39 @@ extern "C" {

+  

+  #define RPMLEAD_SIZE 96         /*!< Don't rely on sizeof(struct) */

+  

+ +/** \ingroup lead

+ + * The lead data structure.

+ + * The lead needs to be 8 byte aligned.

+ + * @deprecated The lead (except for signature_type) is legacy.

+ + * @todo Don't use any information from lead.

+ + */

+ +struct rpmlead_s {

+ +    unsigned char magic[4];

+ +    unsigned char major;

+ +    unsigned char minor;

+ +    short type;

+ +    short archnum;

+ +    char name[66];

+ +    short osnum;

+ +    short signature_type;       /*!< Signature header type (RPMSIG_HEADERSIG) */

+ +    char reserved[16];      /*!< Pad to 96 bytes -- 8 byte aligned! */

+ +};

+ +

+  /** \ingroup lead

+   * Write lead to file handle.

+   * @param fd		file handle

+   * @param h		package header

+   * @return		RPMRC_OK on success, RPMRC_FAIL on error

+   */

+ -rpmRC rpmLeadWrite(FD_t fd, Header h);

+ +rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h);

+ +

+ +/** \ingroup lead

+ + * Write lead to file handle.

+ + * @param fd		file handle

+ + * @param l		lead

+ + * @return		RPMRC_OK on success, RPMRC_FAIL on error

+ + */

+ +rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l);

+  

+  /** \ingroup lead

+   * Read lead from file handle.

+ @@ -35,6 +61,15 @@ rpmRC rpmLeadWrite(FD_t fd, Header h);

+   */

+  rpmRC rpmLeadRead(FD_t fd, char **emsg);

+  

+ +/** \ingroup lead

+ + * Read lead from file handle and return it.

+ + * @param fd		file handle

+ + * @param[out] emsg		failure message on error (malloced)

+ + * @param[out] ret		address of lead

+ + * @return		RPMRC_OK on success, RPMRC_FAIL/RPMRC_NOTFOUND on error

+ + */

+ +rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret);

+ +

+  #ifdef __cplusplus

+  }

+  #endif

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

+ index 7dd5128decb03781411bd714339b3b6e9b805842..702d3765d76faf618992ca112011d2312d7fcdcc 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -134,6 +134,28 @@ exit:

+      return rc;

+  }

+  

+ +/**

+ + * Check if package is in deny list.

+ + * @param package_name	package name

+ + * @return 		true if package is in deny list

+ + */

+ +static inline int isInDenyList(char * package_name)

+ +{

+ +    int is_in_deny_list = 0;

+ +    if (package_name) {

+ +	char *e_denylist = getenv("LIBREPO_TRANSCODE_RPMS_DENYLIST");

+ +	char *denytlist_item = strtok(e_denylist, ",");

+ +	while (denytlist_item) {

+ +	    if (strstr(package_name, denytlist_item)) {

+ +		is_in_deny_list = 1;

+ +		break;

+ +	    }

+ +	    denytlist_item = strtok(NULL, ",");

+ +	}

+ +    }

+ +	return is_in_deny_list;

+ +}

+ +

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

+      size_t len;

+      rpmRC rc = RPMRC_FAIL;

+ @@ -239,15 +261,41 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      uint32_t offset_ix = 0;

+      size_t len;

+      int next = 0;

+ +	struct rpmlead_s l;

+ +    rpmfiles files = NULL;

+ +    rpmfi fi = NULL;

+ +    char *msg = NULL;

+  

+      fdo = fdDup(STDOUT_FILENO);

+  

+ +    rc = rpmLeadReadAndReturn(fdi, &msg, &l);

+ +    if (rc != RPMRC_OK)

+ +	goto exit;

+ +

+ +    /* Skip conversion if package is in deny list */

+ +    if (isInDenyList(l.name)) {

+ +	if (rpmLeadWrite(fdo, l)) {

+ +		fprintf(stderr, _("Unable to write package lead: %s\n"),

+ +		Fstrerror(fdo));

+ +	    rc = RPMRC_FAIL;

+ +	    goto exit;

+ +	}

+ +

+ +	ssize_t fdilength = ufdCopy(fdi, fdo);

+ +	if (fdilength == -1) {

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

+ +	    rc = RPMRC_FAIL;

+ +	    goto exit;

+ +	}

+ +

+ +	goto exit;

+ +    } else {

+      if (rpmReadPackageRaw(fdi, &sigh, &h)) {

+  	rpmlog(RPMLOG_ERR, _("Error reading package\n"));

+  	exit(EXIT_FAILURE);

+      }

+  

+ -    if (rpmLeadWrite(fdo, h))

+ +    if (rpmLeadWriteFromHeader(fdo, h))

+      {

+  	rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),

+  		Fstrerror(fdo));

+ @@ -264,38 +312,41 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	exit(EXIT_FAILURE);

+      }

+  

+ -    /* Retrieve payload size and compression type. */

+ -    {

+ -	const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);

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

+ -    }

+ +	/* Retrieve payload size and compression type. */

+ +	{

+ +	    const char *compr =

+ +		headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);

+ +	    rpmio_flags =

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

+ +	}

+  

+ -    gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */

+ -    free(rpmio_flags);

+ +	gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */

+ +	free(rpmio_flags);

+  

+      if (gzdi == NULL) {

+  	rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));

+  	exit(EXIT_FAILURE);

+      }

+  

+ -    rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);

+ -    rpmfi fi = rpmfiNewArchiveReader(gzdi, files,

+ -				     RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);

+ +	files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);

+ +	fi = rpmfiNewArchiveReader(gzdi, files,

+ +				   RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);

+  

+ -    /* this is encoded in the file format, so needs to be fixed size (for

+ -     * now?)

+ -     */

+ -    diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi));

+ -    digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp,

+ -				   NULL);

+ -    struct digestoffset offsets[rpmfiFC(fi)];

+ -    pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);

+ +	/* this is encoded in the file format, so needs to be fixed size (for

+ +	 * now?)

+ +	 */

+ +	diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi));

+ +	digestSet ds =

+ +	    digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp,

+ +			    NULL);

+ +	struct digestoffset offsets[rpmfiFC(fi)];

+ +	pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);

+  

+ -    /* main headers are aligned to 8 byte boundry */

+ -    pos += pad_to(pos, 8);

+ -    pos += headerSizeof(h, HEADER_MAGIC_YES);

+ +	/* main headers are aligned to 8 byte boundry */

+ +	pos += pad_to(pos, 8);

+ +	pos += headerSizeof(h, HEADER_MAGIC_YES);

+  

+ -    zeros = xcalloc(fundamental_block_size, 1);

+ +	zeros = xcalloc(fundamental_block_size, 1);

+  

+      while (next >= 0) {

+  	next = rpmfiNext(fi);

+ @@ -342,8 +393,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      }

+      Fclose(gzdi);	/* XXX gzdi == fdi */

+  

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

+ -	  digestoffsetCmp);

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

+ +	      digestoffsetCmp);

+  

+      validation_pos = pos;

+      ssize_t validation_len = ufdCopy(validationi, fdo);

+ @@ -412,6 +463,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	rc = RPMRC_FAIL;

+  	goto exit;

+      }

+ +	}

+  

+  exit:

+      rpmfilesFree(files);

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

+ index b4897f1de444080c8dc6c4913b5f33de20796822..d54e254ff41a0441d04fbcf27f26e4809f563b79 100644

+ --- a/sign/rpmgensig.c

+ +++ b/sign/rpmgensig.c

+ @@ -672,7 +672,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)

+  	}

+  

+  	/* Write the lead/signature of the output rpm */

+ -	rc = rpmLeadWrite(ofd, h);

+ +	rc = rpmLeadWriteFromHeader(ofd, h);

+  	if (rc != RPMRC_OK) {

+  	    rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,

+  		Fstrerror(ofd));

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

+ index 5135c9cf83d9e75e9d9bc0b84186ab10cc0cbcac..c9c79c5acd22b86704460f295712ce7ab5ee3259 100644

+ --- a/tests/rpm2extents.at

+ +++ b/tests/rpm2extents.at

+ @@ -95,6 +95,17 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?

+  [])

+  AT_CLEANUP

+  

+ +# check that package in denylist is not transcoded

+ +AT_SETUP([rpm2extents denylist])

+ +AT_KEYWORDS([rpm2extents])

+ +AT_CHECK([

+ +export LIBREPO_TRANSCODE_RPMS_DENYLIST="vim,hello,cowsay"

+ +runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | runroot_other cmp /data/RPMS/hello-2.0-1.x86_64.rpm -],

+ +[0],

+ +[],

+ +[ignore])

+ +AT_CLEANUP

+ +

+  AT_SETUP([rpm2extents install package])

+  AT_KEYWORDS([rpm2extents reflink])

+  AT_SKIP_IF([$REFLINK_DISABLED])

@@ -0,0 +1,385 @@ 

+ From: Richard Phibel <richardphibel@meta.com>

+ 

+ Subject: RPM with Copy on Write: workaround for corrupt signature header

+ 

+ commit 7976c921f60ec5d20c50c4c702ec5636b39210ba

+ Author: Richard Phibel <richardphibel@meta.com>

+ Date:   Wed Oct 26 18:57:19 2022 +0200

+ 

+     RPM with Copy on Write: workaround for corrupt signature header

+     

+     Some packages have errors in the signature header. These errors do not

+     prevent installation of the package but cause issues in rpm2extents

+     conversion. This commit implements the same fix as in

+     unloadImmutableRegion.

+ 

+ Signed-off-by: Richard Phibel <richardphibel@meta.com>

+ 

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

+ index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -139,7 +139,7 @@ exit:

+   * @param package_name	package name

+   * @return 		true if package is in deny list

+   */

+ -static inline int isInDenyList(char * package_name)

+ +static inline int isInDenyList(char *package_name)

+  {

+      int is_in_deny_list = 0;

+      if (package_name) {

+ @@ -153,7 +153,7 @@ static inline int isInDenyList(char * package_name)

+  	    denytlist_item = strtok(NULL, ",");

+  	}

+      }

+ -	return is_in_deny_list;

+ +    return is_in_deny_list;

+  }

+  

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

+ @@ -229,6 +229,22 @@ exit:

+      return rc;

+  }

+  

+ +static void sanitizeSignatureHeader(Header * sigh)

+ +{

+ +    struct rpmtd_s td;

+ +

+ +    /* This is inspired by the code in unloadImmutableRegion. See https://github.com/rpm-software-management/rpm/pull/1330 */

+ +    if (!headerGet(*sigh, RPMTAG_HEADERSIGNATURES, &td, HEADERGET_DEFAULT)) {

+ +	/* Signature header corrupt/missing */

+ +	rpmlog(RPMLOG_WARNING, _("Error verifying signature header\n"));

+ +	rpmtdFreeData(&td);

+ +	Header nh = headerCopy(*sigh);

+ +	headerFree(*sigh);

+ +	*sigh = headerLink(nh);

+ +	headerFree(nh);

+ +    }

+ +}

+ +

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

+  {

+      uint32_t diglen;

+ @@ -261,7 +277,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      uint32_t offset_ix = 0;

+      size_t len;

+      int next = 0;

+ -	struct rpmlead_s l;

+ +    struct rpmlead_s l;

+      rpmfiles files = NULL;

+      rpmfi fi = NULL;

+      char *msg = NULL;

+ @@ -274,43 +290,47 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  

+      /* Skip conversion if package is in deny list */

+      if (isInDenyList(l.name)) {

+ +	rpmlog(RPMLOG_WARNING, _("package %s is in deny list: conversion skipped\n"), l.name);

+  	if (rpmLeadWrite(fdo, l)) {

+ -		fprintf(stderr, _("Unable to write package lead: %s\n"),

+ -		Fstrerror(fdo));

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),

+ +		    Fstrerror(fdo));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+  

+  	ssize_t fdilength = ufdCopy(fdi, fdo);

+  	if (fdilength == -1) {

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

+ +	    rpmlog(RPMLOG_ERR, _("process_package cat failed\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+  

+  	goto exit;

+      } else {

+ -    if (rpmReadPackageRaw(fdi, &sigh, &h)) {

+ -	rpmlog(RPMLOG_ERR, _("Error reading package\n"));

+ -	exit(EXIT_FAILURE);

+ -    }

+ +	if (rpmReadPackageRaw(fdi, &sigh, &h)) {

+ +	    rpmlog(RPMLOG_ERR, _("Error reading package\n"));

+ +	    exit(EXIT_FAILURE);

+ +	}

+  

+ -    if (rpmLeadWriteFromHeader(fdo, h))

+ -    {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),

+ -		Fstrerror(fdo));

+ -	exit(EXIT_FAILURE);

+ -    }

+ +	sanitizeSignatureHeader(&sigh);

+  

+ -    if (rpmWriteSignature(fdo, sigh)) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), Fstrerror(fdo));

+ -	exit(EXIT_FAILURE);

+ -    }

+ +	if (rpmLeadWriteFromHeader(fdo, h)) {

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),

+ +		   Fstrerror(fdo));

+ +	    exit(EXIT_FAILURE);

+ +	}

+  

+ -    if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {

+ -	rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), Fstrerror(fdo));

+ -	exit(EXIT_FAILURE);

+ -    }

+ +	if (rpmWriteSignature(fdo, sigh)) {

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"),

+ +		   Fstrerror(fdo));

+ +	    exit(EXIT_FAILURE);

+ +	}

+ +

+ +	if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"),

+ +		   Fstrerror(fdo));

+ +	    exit(EXIT_FAILURE);

+ +	}

+  

+  	/* Retrieve payload size and compression type. */

+  	{

+ @@ -323,10 +343,11 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */

+  	free(rpmio_flags);

+  

+ -    if (gzdi == NULL) {

+ -	rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));

+ -	exit(EXIT_FAILURE);

+ -    }

+ +	if (gzdi == NULL) {

+ +	    rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"),

+ +		   Fstrerror(gzdi));

+ +	    exit(EXIT_FAILURE);

+ +	}

+  

+  	files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);

+  	fi = rpmfiNewArchiveReader(gzdi, files,

+ @@ -348,124 +369,128 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  

+  	zeros = xcalloc(fundamental_block_size, 1);

+  

+ -    while (next >= 0) {

+ -	next = rpmfiNext(fi);

+ -	if (next == RPMERR_ITER_END) {

+ -	    rc = RPMRC_OK;

+ -	    break;

+ +	while (next >= 0) {

+ +	    next = rpmfiNext(fi);

+ +	    if (next == RPMERR_ITER_END) {

+ +		rc = RPMRC_OK;

+ +		break;

+ +	    }

+ +	    mode = rpmfiFMode(fi);

+ +	    if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {

+ +		/* not a regular file, or the archive doesn't contain any content

+ +		 * for this entry.

+ +		 */

+ +		continue;

+ +	    }

+ +	    digest = rpmfiFDigest(fi, NULL, NULL);

+ +	    if (digestSetGetEntry(ds, digest, NULL)) {

+ +		/* This specific digest has already been included, so skip it. */

+ +		continue;

+ +	    }

+ +	    pad = pad_to(pos, fundamental_block_size);

+ +	    if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {

+ +		rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));

+ +		rc = RPMRC_FAIL;

+ +		goto exit;

+ +	    }

+ +	    /* round up to next fundamental_block_size */

+ +	    pos += pad;

+ +	    digestSetAddEntry(ds, digest);

+ +	    offsets[offset_ix].digest = digest;

+ +	    offsets[offset_ix].pos = pos;

+ +	    offset_ix++;

+ +	    size = rpmfiFSize(fi);

+ +	    rc = rpmfiArchiveReadToFile(fi, fdo, 0);

+ +	    if (rc != RPMRC_OK) {

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

+  	}

+ -	mode = rpmfiFMode(fi);

+ -	if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {

+ -	    /* not a regular file, or the archive doesn't contain any content

+ -	     * for this entry.

+ -	    */

+ -	    continue;

+ +	Fclose(gzdi);		/* XXX gzdi == fdi */

+ +

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

+ +	      digestoffsetCmp);

+ +

+ +	validation_pos = pos;

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

+ +	if (validation_len == -1) {

+ +	    rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));

+ +	    rc = RPMRC_FAIL;

+ +	    goto exit;

+  	}

+ -	digest = rpmfiFDigest(fi, NULL, NULL);

+ -	if (digestSetGetEntry(ds, digest, NULL)) {

+ -	    /* This specific digest has already been included, so skip it. */

+ -	    continue;

+ +

+ +	digest_table_pos = validation_pos + validation_len;

+ +

+ +	len = sizeof(offset_ix);

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

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write length of table\n"));

+ +	    rc = RPMRC_FAIL;

+ +	    goto exit;

+  	}

+ -	pad = pad_to(pos, fundamental_block_size);

+ -	if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {

+ -	    rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));

+ +	len = sizeof(diglen);

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

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ -	/* round up to next fundamental_block_size */

+ -	pos += pad;

+ -	digestSetAddEntry(ds, digest);

+ -	offsets[offset_ix].digest = digest;

+ -	offsets[offset_ix].pos = pos;

+ -	offset_ix++;

+ -	size = rpmfiFSize(fi);

+ -	rc = rpmfiArchiveReadToFile(fi, fdo, 0);

+ -	if (rc != RPMRC_OK) {

+ -	    char *errstr = rpmfileStrerror(rc);

+ -	    rpmlog(RPMLOG_ERR,

+ -		   _("rpmfiArchiveReadToFile failed while extracting "\

+ -		   "\"%s\" with RC %d: %s\n"),

+ -		   rpmfiFN(fi), rc, errstr);

+ -	    free(errstr);

+ +	len = sizeof(rpm_loff_t);

+ +	for (int x = 0; x < offset_ix; x++) {

+ +	    if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {

+ +		rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));

+ +		rc = RPMRC_FAIL;

+ +		goto exit;

+ +	    }

+ +	    if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {

+ +		rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));

+ +		rc = RPMRC_FAIL;

+ +		goto exit;

+ +	    }

+ +	}

+ +	digest_pos =

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

+ +	     offset_ix * (diglen + sizeof(rpm_loff_t))

+ +	    );

+ +

+ +	ssize_t digest_len = ufdCopy(digestori, fdo);

+ +	if (digest_len == -1) {

+ +	    rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n"));

+ +	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ -	pos += size;

+ -    }

+ -    Fclose(gzdi);	/* XXX gzdi == fdi */

+ -

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

+ -	      digestoffsetCmp);

+  

+ -    validation_pos = pos;

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

+ -    if (validation_len == -1) {

+ -	rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -

+ -    digest_table_pos = validation_pos + validation_len;

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

+ +	 */

+  

+ -    len = sizeof(offset_ix);

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

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

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

+ -	    rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));

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

+ +	    rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));

+  	    rc = RPMRC_FAIL;

+  	    goto exit;

+  	}

+ -	if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {

+ -	    rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));

+ +	zeros = _free(zeros);

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

+  	}

+      }

+ -    digest_pos = (

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

+ -	offset_ix * (diglen + sizeof(rpm_loff_t))

+ -    );

+ -

+ -    ssize_t digest_len = ufdCopy(digestori, fdo);

+ -    if (digest_len == -1) {

+ -	rpmlog(RPMLOG_ERR, _("digest table 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.

+ -    */

+  

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

+ -	rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));

+ -	rc = RPMRC_FAIL;

+ -	goto exit;

+ -    }

+ -    zeros = _free(zeros);

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

+ -    }

+ -	}

+ -

+ -exit:

+ +  exit:

+      rpmfilesFree(files);

+      rpmfiFree(fi);

+      headerFree(h);

@@ -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 <errno.h>

+  #include <sys/wait.h>

+  #include <popt.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-imaevm \

+  	--with-crypto=openssl \

+  	--with-fapolicyd \

+ +	--with-fsverity \

+  	--disable-dependency-tracking

+  

+  include $(top_srcdir)/rpm.am

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,80 @@ 

+ From 937f9bc67b905851c78719d8397926eaa97b174a Mon Sep 17 00:00:00 2001

+ From: Richard Phibel <richardphibel@meta.com>

+ Date: Mon, 22 May 2023 05:16:51 +0200

+ Subject: [PATCH] Fix stack overflow

+ 

+ Creation of array struct digestoffset offsets[rpmfiFC(fi)] caused a

+ stack overflow because the total size is greater than 8M which is the

+ stack size limit on Linux. To fix the issue, the array is allocated on

+ the heap.

+ 

+ I used AddressSanitizer to find the root cause of the issue. It found a

+ number of memory leaks so I fixed them as well.

+ ---

+  rpm2extents.c | 15 +++++++++++----

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

+ 

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

+ index c2a373914..0ee8666fa 100644

+ --- a/rpm2extents.c

+ +++ b/rpm2extents.c

+ @@ -226,6 +226,7 @@ exit:

+      if(msg) {

+  	free(msg);

+      }

+ +    rpmtsFree(ts);

+      return rc;

+  }

+  

+ @@ -243,6 +244,7 @@ static void sanitizeSignatureHeader(Header * sigh)

+  	*sigh = headerLink(nh);

+  	headerFree(nh);

+      }

+ +    rpmtdFreeData(&td);

+  }

+  

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

+ @@ -281,6 +283,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      rpmfiles files = NULL;

+      rpmfi fi = NULL;

+      char *msg = NULL;

+ +    struct digestoffset *offsets = NULL;

+ +    digestSet ds = NULL;

+  

+      fdo = fdDup(STDOUT_FILENO);

+  

+ @@ -357,10 +361,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+  	 * now?)

+  	 */

+  	diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi));

+ -	digestSet ds =

+ -	    digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp,

+ -			    NULL);

+ -	struct digestoffset offsets[rpmfiFC(fi)];

+ +	ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, NULL);

+ +	offsets = xcalloc(rpmfiFC(fi), sizeof(*offsets));

+  	pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);

+  

+  	/* main headers are aligned to 8 byte boundry */

+ @@ -494,6 +496,10 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)

+      rpmfilesFree(files);

+      rpmfiFree(fi);

+      headerFree(h);

+ +    headerFree(sigh);

+ +    free(offsets);

+ +    Fclose(fdo);

+ +    digestSetFree(ds);

+      return rc;

+  }

+  

+ @@ -693,6 +699,7 @@ int main(int argc, char *argv[]) {

+  

+      FD_t fdi = fdDup(STDIN_FILENO);

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

+ +    Fclose(fdi);

+      if (rc != RPMRC_OK) {

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

+  	return EXIT_FAILURE;

+ -- 

+ 2.40.1

+ 

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

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

+ From: Richard Phibel <richardphibel@meta.com>

+ Date: Fri, 11 Aug 2023 00:43:21 +0200

+ Subject: [PATCH] Fix issue for transaction with transcoded and non-transcoded

+  packages

+ 

+ The flag saying whether a package is transcoded is not clean-up between

+ each packages. Because of that if a non-transcoded package is treated

+ after a transcoded one, the package is treated as transcoded

+ ---

+  plugins/reflink.c | 1 +

+  1 file changed, 1 insertion(+)

+ 

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

+ index 986cbd172..20d35eefd 100644

+ --- a/plugins/reflink.c

+ +++ b/plugins/reflink.c

+ @@ -234,6 +234,7 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)

+  	inodeIndexHashFree(state->inodeIndexes);

+  	state->inodeIndexes = NULL;

+      }

+ +    state->transcoded = 0;

+      return RPMRC_OK;

+  }

+  

+ -- 

+ 2.40.1

+ 

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

+  }

@@ -0,0 +1,161 @@ 

+ From 07f1d3132f0c7b7ecb69a47a9930edb534a9250e Mon Sep 17 00:00:00 2001

+ From: Panu Matilainen <pmatilai@redhat.com>

+ Date: Mon, 7 Feb 2022 13:38:48 +0200

+ Subject: [PATCH] Fix IMA signature fubar, take III (#1833, RhBug:2018937)

+ 

+ At least ECDSA and RSA signatures can vary in length, but the IMA code

+ assumes constant lengths and thus may either place invalid signatures on

+ disk from either truncating or overshooting, and segfault if the stars are

+ just so.

+ 

+ As we can't assume static lengths and attempts to use maximum length

+ have proven problematic for other reasons, use a data structure that

+ can actually handle variable length data properly: store offsets into

+ the decoded binary blob and use them to calculate lengths when needed,

+ empty data is simply consequtive identical offsets. This avoids a whole

+ class of silly overflow issues with multiplying, makes zero-length data

+ actually presentable in the data structure and saves memory too.

+ 

+ Add tests to show behavior with variable length signatures and missing

+ signatures.

+ 

+ Additionally update the signing code to store the largest IMA signature

+ length rather than what happened to be last to be on the safe side.

+ We can't rely on this value due to invalid packages being out there,

+ but then we need to calculate the lengths on rpmfiles populate so there's

+ not a lot to gain anyhow.

+ 

+ Fixes: #1833

+ ---

+  lib/rpmfi.c         | 61 +++++++++++++++++++++++++++++++++++++++------

+  sign/rpmsignfiles.c |  5 +++-

+  2 files changed, 58 insertions(+), 8 deletions(-)

+ 

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

+ index 439179689..4673fbb85 100644

+ --- a/lib/rpmfi.c

+ +++ b/lib/rpmfi.c

+ @@ -116,7 +116,7 @@ struct rpmfiles_s {

+      struct fingerPrint_s * fps;	/*!< File fingerprint(s). */

+  

+      int digestalgo;		/*!< File digest algorithm */

+ -    int signaturelength;	/*!< File signature length */

+ +    uint32_t *signatureoffs;	/*!< File signature offsets */

+      int veritysiglength;	/*!< Verity signature length */

+      uint16_t verityalgo;	/*!< Verity algorithm */

+      unsigned char * digests;	/*!< File digests in binary. */

+ @@ -566,10 +566,15 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)

+      const unsigned char *signature = NULL;

+  

+      if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {

+ -	if (fi->signatures != NULL)

+ -	    signature = fi->signatures + (fi->signaturelength * ix);

+ +	size_t slen = 0;

+ +	if (fi->signatures != NULL && fi->signatureoffs != NULL) {

+ +	    uint32_t off = fi->signatureoffs[ix];

+ +	    slen = fi->signatureoffs[ix+1] - off;

+ +	    if (slen > 0)

+ +		signature = fi->signatures + off;

+ +	}

+  	if (len)

+ -	    *len = fi->signaturelength;

+ +	    *len = slen;

+      }

+      return signature;

+  }

+ @@ -1242,6 +1247,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)

+  	fi->flangs = _free(fi->flangs);

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

+  

+ @@ -1471,6 +1477,48 @@ err:

+      return;

+  }

+  

+ +/*

+ + * Convert a tag of variable len hex strings to binary presentation,

+ + * accessed via offsets to a contiguous binary blob. Empty values

+ + * are represented by identical consequtive offsets. The offsets array

+ + * always has one extra element to allow calculating the size of the

+ + * last element.

+ + */

+ +static uint8_t *hex2binv(Header h, rpmTagVal tag, rpm_count_t num,

+ +			uint32_t **offsetp)

+ +{

+ +    struct rpmtd_s td;

+ +    uint8_t *bin = NULL;

+ +    uint32_t *offs = NULL;

+ +

+ +    if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {

+ +	const char *s;

+ +	int i = 0;

+ +	uint8_t *t = bin = xmalloc(((rpmtdSize(&td) / 2) + 1));

+ +	offs = xmalloc((num + 1) * sizeof(*offs));

+ +

+ +	while ((s = rpmtdNextString(&td))) {

+ +	    uint32_t slen = strlen(s);

+ +	    uint32_t len = slen / 2;

+ +	    if (slen % 2) {

+ +		bin = rfree(bin);

+ +		offs = rfree(offs);

+ +		goto exit;

+ +	    }

+ +	    offs[i] = t - bin;

+ +	    for (int j = 0; j < len; j++, t++, s += 2)

+ +		*t = (rnibble(s[0]) << 4) | rnibble(s[1]);

+ +	    i++;

+ +	}

+ +	offs[i] = t - bin;

+ +	*offsetp = offs;

+ +    }

+ +

+ +exit:

+ +    rpmtdFreeData(&td);

+ +    return bin;

+ +}

+ +

+  /* Convert a tag of hex strings to binary presentation */

+  static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)

+  {

+ @@ -1623,9 +1671,8 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)

+      fi->signatures = NULL;

+      /* grab hex signatures from header and store in binary format */

+      if (!(flags & RPMFI_NOFILESIGNATURES)) {

+ -	fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);

+ -	fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,

+ -				 totalfc, fi->signaturelength);

+ +	fi->signatures = hex2binv(h, RPMTAG_FILESIGNATURES,

+ +				 totalfc, &fi->signatureoffs);

+      }

+  

+      fi->veritysigs = NULL;

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

+ index b143c5b9b..372ba634c 100644

+ --- a/sign/rpmsignfiles.c

+ +++ b/sign/rpmsignfiles.c

+ @@ -98,8 +98,9 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+      td.count = 1;

+  

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

+ +	uint32_t slen = 0;

+  	digest = rpmfiFDigest(fi, NULL, NULL);

+ -	signature = signFile(algoname, digest, diglen, key, keypass, &siglen);

+ +	signature = signFile(algoname, digest, diglen, key, keypass, &slen);

+  	if (!signature) {

+  	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));

+  	    goto exit;

+ @@ -110,6 +111,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)

+  	    goto exit;

+  	}

+  	signature = _free(signature);

+ +	if (slen > siglen)

+ +	    siglen = slen;

+      }

+  

+      if (siglen > 0) {

+ -- 

+ 2.40.1

+ 

file added
+23
@@ -0,0 +1,23 @@ 

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

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

+ Date: Mon, 28 Sep 2020 12:41:22 -0700

+ Subject: [PATCH] Make fdSeek return 0 on success, -1 on error

+ 

+ This code eliminates a false positive failure when the destination position is > 2GiB. This is done by changing the contract for `Fseek`. Now it returns `0` on success instead of an `int` offset. Care should be used to interpret the result as there is a difference in semantics between the POSIX `fseek(2)`. Existing code is correct: negative results are still failures.

+ ---

+  rpmio/rpmio.c | 2 +-

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

+ 

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

+ index 10a28a923..9f4a60aa1 100644

+ --- a/rpmio/rpmio.c

+ +++ b/rpmio/rpmio.c

+ @@ -382,7 +382,7 @@ static ssize_t fdWrite(FDSTACK_t fps, const void * buf, size_t count)

+  

+  static int fdSeek(FDSTACK_t fps, off_t pos, int whence)

+  {

+ -    return lseek(fps->fdno, pos, whence);

+ +    return (lseek(fps->fdno, pos, whence) == -1) ? -1 : 0;

+  }

+  

+  static int fdClose(FDSTACK_t fps)

file added
+1359
The added file is too large to be shown here, see it at: 1534.patch
@@ -0,0 +1,46 @@ 

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

+ From: Lumir Balhar <lbalhar@redhat.com>

+ Date: Tue, 26 Sep 2023 13:14:44 +0200

+ Subject: [PATCH] brp-python-bytecompile compatibility with newer pythons

+ 

+ ---

+  scripts/brp-python-bytecompile | 8 ++++----

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

+ 

+ diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile

+ index 4a9b49e..472bf10 100644

+ --- a/scripts/brp-python-bytecompile

+ +++ b/scripts/brp-python-bytecompile

+ @@ -58,7 +58,7 @@ EOF

+  # and below /usr/lib/python3.1/, we're targeting /usr/bin/python3.1

+  

+  shopt -s nullglob

+ -for python_libdir in `find "$RPM_BUILD_ROOT" -type d|grep -E "/usr/lib(64)?/python[0-9]\.[0-9]$"`;

+ +for python_libdir in `find "$RPM_BUILD_ROOT" -type d|grep -E "/usr/lib(64)?/python[0-9]\.[0-9]+$"`;

+  do

+  	python_binary=/usr/bin/$(basename $python_libdir)

+  	if [ "$python_binary" = "/usr/bin/python3.6" ]; then

+ @@ -97,17 +97,17 @@ fi

+  

+  # Figure out if there are files to be bytecompiled with the default_python at all

+  # this prevents unnecessary default_python invocation

+ -find "$RPM_BUILD_ROOT" -type f -name "*.py" | grep -Ev "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" || exit 0

+ +find "$RPM_BUILD_ROOT" -type f -name "*.py" | grep -Ev "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" || exit 0

+  

+  # Generate normal (.pyc) byte-compiled files.

+ -python_bytecompile "" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"

+ +python_bytecompile "" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"

+  if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then

+  	# One or more of the files had a syntax error

+  	exit 1

+  fi

+  

+  # Generate optimized (.pyo) byte-compiled files.

+ -python_bytecompile "-O" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"

+ +python_bytecompile "-O" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"

+  if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then

+  	# One or more of the files had a syntax error

+  	exit 1

+ -- 

+ 2.41.0

+ 

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

+ From 93e482be29ee683011c71f23b3b0096889e50331 Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Mon, 3 Feb 2020 11:37:30 +0100

+ Subject: [PATCH] Permit ndb database queries on read-only media

+ 

+ See also commit a429c99e13fbe9926243f29b78df8d64222c4469 for db3.

+ ---

+  lib/backend/ndb/glue.c | 2 +-

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

+ 

+ diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c

+ index 90c10f8894..d19da7c5cd 100644

+ --- a/lib/backend/ndb/glue.c

+ +++ b/lib/backend/ndb/glue.c

+ @@ -161,7 +161,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)

+  	    /* Open indexes readwrite if possible */

+  	    ioflags = O_RDWR;

+  	    rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666);

+ -	    if (rc && errno == EACCES) {

+ +	    if (rc && (errno == EACCES || errno == EROFS)) {

+  		/* If it is not asked for rw explicitly, try to open ro */

+  		if (!(oflags & O_RDWR)) {

+  		    ioflags = O_RDONLY;

@@ -0,0 +1,178 @@ 

+ From a5803faa083690526b96484c7e6a4cc915ca3921 Mon Nov 28 16:35:09 2022

+ From: Aleksandr Kazakov <alexkazakov@meta.com>

+ Date: Mon, 28 Nov 2022 16:35:09 +0000

+ Subject: [PATCH] Backport multi-threaded zstd to 4.14.x to support

+  multi-threaded zstd compression on centos 8

+ 

+ Signed-off-by: Aleksandr Kazakov <alexkazakov@meta.com>

+ ---

+  configure.ac  |  2 +-

+  macros.in     |  1 +

+  rpmio/rpmio.c | 82 +++++++++++++++++++++++++++++++++++----------------

+  3 files changed, 58 insertions(+), 27 deletions(-)

+ 

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

+ index 47327bd..b1213ae 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -214,7 +214,7 @@ AC_ARG_ENABLE([zstd],

+                [enable_zstd=auto])

+  

+  AS_IF([test "x$enable_zstd" != "xno"], [

+ -  PKG_CHECK_MODULES([ZSTD], [libzstd], [have_zstd=yes], [have_zstd=no])

+ +  PKG_CHECK_MODULES([ZSTD], [libzstd >= 1.3.8], [have_zstd=yes], [have_zstd=no])

+    AS_IF([test "$enable_zstd" = "yes"], [

+      if test "$have_zstd" = "no"; then

+        AC_MSG_ERROR([--enable-zstd specified, but not available])

+ diff --git a/macros.in b/macros.in

+ index 9b9fe23..832b60a 100644

+ --- a/macros.in

+ +++ b/macros.in

+ @@ -394,6 +394,7 @@ package or when debugging this package.\

+  #		"w9.bzdio"	bzip2 level 9.

+  #		"w6.xzdio"	xz level 6, xz's default.

+  #		"w7T16.xzdio"	xz level 7 using 16 thread (xz only)

+ +#		"w19T8.zstdio"	zstd level 19 using 8 threads

+  #		"w6.lzdio"	lzma-alone level 6, lzma's default

+  #

+  #%_source_payload	w9.gzdio

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

+ index 09b5d02..d030a9c 100644

+ --- a/rpmio/rpmio.c

+ +++ b/rpmio/rpmio.c

+ @@ -1070,6 +1070,7 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode)

+      char *t = stdio;

+      char *te = t + sizeof(stdio) - 2;

+      int c;

+ +    int threads = 0;

+  

+      switch ((c = *s++)) {

+      case 'a':

+ @@ -1098,7 +1099,14 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode)

+  	    flags &= ~O_ACCMODE;

+  	    flags |= O_RDWR;

+  	    continue;

+ -	    break;

+ +	case 'T':

+ +	    if (*s >= '0' && *s <= '9') {

+ +		threads = strtol(s, (char **)&s, 10);

+ +		/* T0 means automatic detection */

+ +		if (threads == 0)

+ +		    threads = sysconf(_SC_NPROCESSORS_ONLN);

+ +	    }

+ +	    continue;

+  	default:

+  	    if (c >= (int)'0' && c <= (int)'9') {

+  		level = strtol(s-1, (char **)&s, 10);

+ @@ -1132,10 +1140,16 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode)

+  	}

+  	nb = ZSTD_DStreamInSize();

+      } else {					/* compressing */

+ -	if ((_stream = (void *) ZSTD_createCStream()) == NULL

+ -	 || ZSTD_isError(ZSTD_initCStream(_stream, level))) {

+ +	if ((_stream = (void *) ZSTD_createCCtx()) == NULL

+ +	 || ZSTD_isError(ZSTD_CCtx_setParameter(_stream, ZSTD_c_compressionLevel, level))) {

+  	    goto err;

+  	}

+ +

+ +	rpmlog(RPMLOG_DEBUG, "using %i threads in zstd compression\n", threads);

+ +	if (threads > 0) {

+ +	    if (ZSTD_isError (ZSTD_CCtx_setParameter(_stream, ZSTD_c_nbWorkers, threads)))

+ +		rpmlog(RPMLOG_WARNING, "zstd library does not support multi-threading\n");

+ +	}

+  	nb = ZSTD_CStreamOutSize();

+      }

+  

+ @@ -1155,7 +1169,7 @@ err:

+      if ((flags & O_ACCMODE) == O_RDONLY)

+  	ZSTD_freeDStream(_stream);

+      else

+ -	ZSTD_freeCStream(_stream);

+ +	ZSTD_freeCCtx(_stream);

+      return NULL;

+  }

+  

+ @@ -1181,16 +1195,24 @@ assert(zstd);

+  	rc = 0;

+      } else {					/* compressing */

+  	/* close frame */

+ -	zstd->zob.dst  = zstd->b;

+ -	zstd->zob.size = zstd->nb;

+ -	zstd->zob.pos  = 0;

+ -	int xx = ZSTD_flushStream(zstd->_stream, &zstd->zob);

+ -	if (ZSTD_isError(xx))

+ -	    fps->errcookie = ZSTD_getErrorName(xx);

+ -	else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))

+ -	    fps->errcookie = "zstdFlush fwrite failed.";

+ -	else

+ -	    rc = 0;

+ +	int xx;

+ +	do {

+ +	  ZSTD_inBuffer zib = { NULL, 0, 0 };

+ +	  zstd->zob.dst  = zstd->b;

+ +	  zstd->zob.size = zstd->nb;

+ +	  zstd->zob.pos  = 0;

+ +	  xx = ZSTD_compressStream2(zstd->_stream, &zstd->zob, &zib, ZSTD_e_flush);

+ +	  if (ZSTD_isError(xx)) {

+ +	      fps->errcookie = ZSTD_getErrorName(xx);

+ +	      break;

+ +	  }

+ +	  else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp)) {

+ +	      fps->errcookie = "zstdClose fwrite failed.";

+ +	      break;

+ +	  }

+ +	  else

+ +	      rc = 0;

+ +	} while (xx != 0);

+      }

+      return rc;

+  }

+ @@ -1235,7 +1257,7 @@ assert(zstd);

+  	zstd->zob.pos  = 0;

+  

+  	/* Compress next chunk. */

+ -        int xx = ZSTD_compressStream(zstd->_stream, &zstd->zob, &zib);

+ +        int xx = ZSTD_compressStream2(zstd->_stream, &zstd->zob, &zib, ZSTD_e_continue);

+          if (ZSTD_isError(xx)) {

+  	    fps->errcookie = ZSTD_getErrorName(xx);

+  	    return -1;

+ @@ -1264,17 +1286,25 @@ assert(zstd);

+  	ZSTD_freeDStream(zstd->_stream);

+      } else {					/* compressing */

+  	/* close frame */

+ -	zstd->zob.dst  = zstd->b;

+ -	zstd->zob.size = zstd->nb;

+ -	zstd->zob.pos  = 0;

+ -	int xx = ZSTD_endStream(zstd->_stream, &zstd->zob);

+ -	if (ZSTD_isError(xx))

+ -	    fps->errcookie = ZSTD_getErrorName(xx);

+ -	else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))

+ -	    fps->errcookie = "zstdClose fwrite failed.";

+ -	else

+ -	    rc = 0;

+ -	ZSTD_freeCStream(zstd->_stream);

+ +	int xx;

+ +	do {

+ +	  ZSTD_inBuffer zib = { NULL, 0, 0 };

+ +	  zstd->zob.dst  = zstd->b;

+ +	  zstd->zob.size = zstd->nb;

+ +	  zstd->zob.pos  = 0;

+ +	  xx = ZSTD_compressStream2(zstd->_stream, &zstd->zob, &zib, ZSTD_e_end);

+ +	  if (ZSTD_isError(xx)) {

+ +	      fps->errcookie = ZSTD_getErrorName(xx);

+ +	      break;

+ +	  }

+ +	  else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp)) {

+ +	      fps->errcookie = "zstdClose fwrite failed.";

+ +	      break;

+ +	  }

+ +	  else

+ +	      rc = 0;

+ +	} while (xx != 0);

+ +	ZSTD_freeCCtx(zstd->_stream);

+      }

+  

+      if (zstd->fp && fileno(zstd->fp) > 2)

+ -- 

+ 2.38.1

+ 

file modified
+255 -4
@@ -12,8 +12,18 @@ 

  %bcond_without libarchive

  # build with libimaevm.so

  %bcond_without libimaevm

+ %ifarch aarch64 ppc64le

+ # no fsverity on RHEL based aarch64 or 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 new db format

- %bcond_with ndb

+ %bcond_without ndb

  # build with zstd support?

  %bcond_without zstd

  # build with lmdb support?
@@ -32,7 +42,7 @@ 

  

  %global rpmver 4.14.3

  #global snapver rc2

- %global rel 26

+ %global rel 31.1

  

  %global srcver %{version}%{?snapver:-%{snapver}}

  %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x}
@@ -119,6 +129,16 @@ 

  Patch166: rpm-4.14.3-rpm2archive-nocompression.patch

  Patch167: rpm-4.14.3-rpm2archive-parse-popt-options.patch

  Patch168: rpm-4.14.3-rpm2archive-Don-t-print-usage.patch

+ # Backport fsm to fix CVEs

+ Patch169: 0001-Eliminate-code-duplication-from-rpmfiNext.patch

+ Patch170: 0001-Add-optional-callback-on-directory-changes-during-rp.patch

+ Patch171: 0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch

+ Patch172: 0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch

+ Patch173: 0001-Use-file-state-machine-from-rpm-4.19.patch

+ Patch174: 0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch

+ Patch175: 0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch

+ Patch176: 0001-Print-full-path-if-file-removal-fails.patch

+ Patch177: 0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch

  

  # Python 3 string API sanity

  Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch
@@ -151,6 +171,102 @@ 

  # make unversioned %%__python an error unless explicitly overridden

  Patch1002: rpm-4.14.2-unversioned-python.patch

  

+ # Make brp-python-bytecompile compatible with Python 3.10+

+ Patch1003: brp-python-bytecompile-compatibility-with-newer-pyth.patch

+ 

+ %if %{with zstd}

+ # multithreaded zstd compression

+ Patch1004: rpm-4.14.3-backport-multithreaded-zstd.patch

+ %endif

+ 

+ # fsverity support

+ %if %{with libfsverity}

+ Patch1950: 0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch

+ Patch1951: 0002-Add-RPMTAG_IDENTITY-reservation.patch

+ Patch1952: 0003-Use-lower-level-headerPut-for-file-signing.patch

+ Patch1953: 0004-Place-file-signatures-into-the-signature-header-wher.patch

+ Patch1954: 0005-Unbreak-file-signing-from-previous-commit.patch

+ Patch1955: 0006-Assume-failure-in-rpmSignFiles.patch

+ Patch1956: 0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch

+ Patch1957: 0008-Eliminate-redundant-signature-length-calculation-fun.patch

+ Patch1958: 0009-Drop-redundant-check-on-hash-algo-name.patch

+ Patch1959: 0010-Drop-redundant-check-on-hash-algo-name.patch

+ Patch1960: 0011-Generalize-file-signing-to-use-a-generic-flags-field.patch

+ Patch1961: 0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch

+ Patch1962: 0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch

+ Patch1963: 0014-Drop-support-for-dmalloc.patch

+ 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

+ Patch1984: 0035-fix-IMA-signature-lengths-assumed-constant.patch

+ %endif

+ 

+ %if %{with ndb}

+ # GH#1040

+ Patch9001: ndb_query_ro_media.patch

+ %endif

+ 

+ Patch9989: 1534.patch

+ Patch9990: https://github.com/rpm-software-management/rpm/pull/1381.patch

+ Provides: rpm(pr1381)

+ 

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

+ Patch9931: 0031-rpmcow-denylist.patch

+ Patch9932: 0032-rpmcow-workaround.patch

+ Patch9933: 0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch

+ Patch9934: 0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.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 

  License: GPLv2+
@@ -232,6 +348,10 @@ 

  BuildRequires: %{imadevname} >= 1.0

  %endif

  

+ %if %{with libfsverity}

+ BuildRequires: fsverity-utils-devel >= 1.4

+ %endif

+ 

  %description

  The RPM Package Manager (RPM) is a powerful command line driven

  package management system capable of installing, uninstalling,
@@ -290,7 +410,7 @@ 

  Requires: findutils sed grep gawk diffutils file patch >= 2.5

  Requires: tar unzip gzip bzip2 cpio xz

  %if %{with zstd}

- Requires: zstd

+ Requires: zstd >= 1.3.8

  %endif

  Requires: pkgconfig >= 1:0.24

  Requires: /usr/bin/gdb-add-index
@@ -407,6 +527,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-prioreset

  Summary: Rpm plugin for resetting scriptlet priorities for SysV init

  Group: System Environment/Base
@@ -427,6 +558,21 @@ 

  %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-measure

+ Summary: Rpm plugin for measure

+ Group: System Environment/Base

+ Requires: rpm-libs%{_isa} = %{version}-%{release}

+ 

+ %description plugin-measure

+ Adds measure support

+ 

  %endif # with plugins

  

  %prep
@@ -473,6 +619,7 @@ 

      %{?with_ndb: --enable-ndb} \

      %{!?with_libarchive: --without-archive} \

      %{?with_libimaevm: --with-imaevm} \

+     %{?with_libfsverity: --with-fsverity} \

      %{?with_zstd: --enable-zstd} \

      %{?with_lmdb: --enable-lmdb} \

      %{?with_sqlite: --enable-sqlite} \
@@ -618,6 +765,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

  
@@ -637,6 +789,14 @@ 

  %files plugin-fapolicyd

  %{_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-measure

+ %{_libdir}/rpm-plugins/measure.so

  %endif # with plugins

  

  %files build-libs
@@ -699,19 +859,85 @@ 

  %doc doc/librpm/html/*

  

  %changelog

- * Mon Dec 19 2022 Florian Festi <ffesti@redhat.com> - 4.14.4-26

+ * Wed Feb 21 2024 Davide Cavalca <dcavalca@centosproject.org> - 4.14.3-31.1

+ - Merge upstream changes for Hyperscale

+ 

+ * Wed Feb 21 2024 Davide Cavalca <dcavalca@centosproject.org> - 4.14.3-26.4

+ - Convert to dist-git layout

+ 

+ * Tue Dec 12 2023 Florian Festi <ffesti@redhat.com> - 4.14.3-31

+ - Backport file handling code from rpm-4.19 to fix CVE-2021-35937,

+   CVE-2021-35938 and CVE-2021-35939

+ 

+ * Tue Sep 26 2023 LumĆ­r Balhar <lbalhar@redhat.com> - 4.14.3-27

+ - Make brp-python-bytecompile script compatible with Python 3.10+

+ Resolves: RHEL-6423

+ 

+ * Wed Sep 13 2023 Richard Phibel <richardphibel@meta.com> - 4.14.3-26.3

+ - Fix IMA signature lengths assumed constant

+ 

+ * Thu Aug 17 2023 Richard Phibel <richardphibel@meta.com> - 4.14.3-26.2

+ - Fix issue for transaction with transcoded and non-transcoded packages

+ - Fix stack overflow in rpm2extents and various memory leaks

+ 

+ * Wed Dec 21 2022 Davide Cavalca <dcavalca@centosproject.org> - 4.14.3-26.1

+ - Merge upstream changes for Hyperscale

+ 

+ * Mon Dec 19 2022 Florian Festi <ffesti@redhat.com> - 4.14.3-26

  - Add --nocompression to rpm2archive (#2129345)

  

+ * Fri Dec 16 2022 Davide Cavalca <dcavalca@centosproject.org> - 4.14.3-25.1

+ - Merge upstream changes for Hyperscale

+ 

+ * Wed Nov 30 2022 Richard Phibel <richardphibel@meta.com> - 4.14.3-24.3

+ - Add deny list support and workaround for RPM CoW

+ 

+ * Tue Nov 29 2022 Aleksandr Kazakov <alexkazakov@meta.com> - 4.14.3-24.2

+ - Backport support for multi-threaded zstd compression

+ 

+ * Sat Oct 29 2022 Richard Phibel <richardphibel@fb.com> - 4.14.3-24.1

+ - Merge upstream changes for Hyperscale

+ 

  * Tue Sep 13 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-24

  - Make write() nonblocking in fapolicyd plugin (#2110787)

  

+ * Tue Jun 21 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-23.2

+ - Revert ndb by default (e62c0500274012ca77817a24814de38944c8abd4)

+ 

+ * Mon May 16 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-23.1

+ -  Rebuild for Hyperscale

+ 

  * Tue Apr 05 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-23

  - Fix minor ABI regression in rpmcli.h (#1940895)

  

+ * Fri Mar 25 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.6

+ - Make `rpm -i` work without `--nodigest`

+ - Remove need of executable stack for reflink plugin

+ - Split RPM CoW diffs in individual patches

+ 

+ * Fri Mar 04 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.5

+ - Backport GH#1040 to allow ndb DB query on read-only FS

+ 

  * Tue Feb 15 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-22

  - Fix spurious %transfiletriggerpostun execution (#2023693)

  - Skip recorded symlinks in --setperms (#1900662)

  

+ * Mon Feb 14 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.4

+ - Use ndb by default

+ - Fix support for hardlinks

+ 

+ * Tue Feb 08 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.3

+ - Sync with latest CoW patch

+ - Fix issue where files were created before their parent directory

+ 

+ * Tue Feb 01 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.2

+ - Include PR1534

+ - Rebase PR1470 on top of PR1534

+ - Include support to validate signature while transcoding file

+ 

+ * Tue Feb 01 2022 Manu Bretelle <chantra@fb.com> - 4.14.3-21.1

+ - Rebuild for Hyperscale

+ 

  * Mon Jan 10 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-21

  - Address covscan issues in binding sigs validation patch (#1958480)

  
@@ -721,9 +947,15 @@ 

  - Validate and require subkey binding sigs on PGP pubkeys (#1958480)

  - Fixes CVE-2021-3521

  

+ * Thu Nov 04 2021 Matthew Almond <malmond@fb.com> - 4.14.3-18.2

+ - Include PR1779

+ 

  * Wed Oct 06 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-19

  - Unbreak in-tree kmod strip by reverting brp-strip fix (#1967291)

  

+ * Thu Sep 16 2021 Matthew Almond <malmond@fb.com> - 4.14.3-18.1

+ - Rebase c8s-sig-hyperscale-experimental branch onto c8s changes

+ 

  * Thu Aug 26 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-18

  - Address important covscan issues (#1996665), vol. 2

  
@@ -734,15 +966,34 @@ 

  - Add support for read-only sqlite rpmdb (#1938928)

  - Drop compat .decode() method from returned Py3 strings (#1840142)

  

+ * Tue Aug 03 2021 Matthew Almond <malmond@fb.com> - 4.14.3-15.4

+ - Add measure plugin

+ 

+ * Tue Aug 03 2021 Matthew Almond <malmond@fb.com> - 4.14.3-15.3

+ - Move rpm2extents to plugin package

+ 

+ * Tue Aug 03 2021 Matthew Almond <malmond@fb.com> - 4.14.3-15.2

+ - Added fsverity backport

+ 

+ * Sat Jul 24 2021 Neal Gompa <ngompa@centosproject.org> - 4.14.3-15.1

+ - Rebuild for Hyperscale

+ 

  * Thu Jul 15 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-15

  - Add out-of-bounds checks to hdrblobInit() (#1929445)

  - Fixes CVE-2021-20266

  - Fix regression in brp-strip causing kmods to lose SecureBoot sig (#1967291)

  

+ * Wed Jul 07 2021 Davide Cavalca <dcavalca@centosproject.org> - 4.14.3-14.1

+ - Rebuild for Hyperscale

+ 

  * Thu May 27 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-14

  - Be more careful about copying data from signature header (#1958477)

  - Fixes CVE-2021-20271

  

+ * Thu Mar 18 2021 Matthew Almond <malmond@fb.com> - 4.14.3-13.1

+ - PR1381 (Fix Fseek for offset > 2GiB)

+ - PR1470 (CoW)

+ 

  * Fri Feb 12 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-13

  - Fix minor issues found by COVSCAN in fapolicyd plugin

  - Actually honor libarchive bcond at configure time (#1902887)

This converts the repo layout to dist-git and attempts to merge the latest changes.

Note that this doesn't build as is: Patch9989 (1534.patch) and the CoW stack don't apply cleanly and need to be updated.

Metadata
Changes Summary 86
+1
file added
.rpm.metadata
+32
file added
0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch
+107
file added
0001-Add-optional-callback-on-directory-changes-during-rp.patch
+30
file added
0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch
+35
file added
0001-Eliminate-code-duplication-from-rpmfiNext.patch
+66
file added
0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch
+46
file added
0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch
+153
file added
0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch
+32
file added
0001-Print-full-path-if-file-removal-fails.patch
+1344
file added
0001-RPM-with-Copy-on-Write.patch
+90
file added
0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch
+1654
file added
0001-Use-file-state-machine-from-rpm-4.19.patch
+34
file added
0002-Add-RPMTAG_IDENTITY-reservation.patch
+53
file added
0002-Remove-use-of-bool-type-for-consistency.patch
+1249
file added
0003-Match-formatting-style-of-existing-code.patch
+58
file added
0003-Use-lower-level-headerPut-for-file-signing.patch
+27
file added
0004-Fix-printf-formatting-in-reflink.c.patch
+329
file added
0004-Place-file-signatures-into-the-signature-header-wher.patch
+30
file added
0005-Unbreak-file-signing-from-previous-commit.patch
+73
file added
0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
+71
file added
0006-Assume-failure-in-rpmSignFiles.patch
+431
file added
0006-rpm2extents-verify-package-signature-during-transcod.patch
+108
file added
0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch
+282
file added
0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch
+105
file added
0008-Eliminate-redundant-signature-length-calculation-fun.patch
+116
file added
0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch
+29
file added
0009-Drop-redundant-check-on-hash-algo-name.patch
+70
file added
0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
+40
file added
0010-Drop-redundant-check-on-hash-algo-name.patch
+204
file added
0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch
+129
file added
0011-Generalize-file-signing-to-use-a-generic-flags-field.patch
+389
file added
0011-rpm2extents-Perform-digest-computation-within-the-va.patch
+201
file added
0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch
+299
file added
0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
+27
file added
0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch
+109
file added
0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
+48
file added
0014-Drop-support-for-dmalloc.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
+32
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
+210
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
+281
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
+91
file added
0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch
+72
file added
0031-Update-man-page-for-rpmsign.patch
+386
file added
0031-rpmcow-denylist.patch
+385
file added
0032-rpmcow-workaround.patch
+168
file added
0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
+27
file added
0033-Enable-fsverity-in-CI.patch
+80
file added
0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch
+28
file added
0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch
+257
file added
0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch
+161
file added
0035-fix-IMA-signature-lengths-assumed-constant.patch
+23
file added
1381.patch
+1359
file added
1534.patch
+46
file added
brp-python-bytecompile-compatibility-with-newer-pyth.patch
+279
file added
measure.patch
+23
file added
ndb_query_ro_media.patch
+178
file added
rpm-4.14.3-backport-multithreaded-zstd.patch
+255 -4
file changed
rpm.spec