From 527b56f58eaa45ca035d426c8b13deabbc9c7ab1 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Sep 26 2023 11:19:49 +0000 Subject: [PATCH 1/8] Make brp-python-bytecompile script compatible with Python 3.10+ Resolves: RHEL-6423 --- diff --git a/brp-python-bytecompile-compatibility-with-newer-pyth.patch b/brp-python-bytecompile-compatibility-with-newer-pyth.patch new file mode 100644 index 0000000..ebe7230 --- /dev/null +++ b/brp-python-bytecompile-compatibility-with-newer-pyth.patch @@ -0,0 +1,46 @@ +From acbf558c486ee3518aca74045504f05872da4a58 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 + diff --git a/rpm.spec b/rpm.spec index f235765..b550fb4 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 26 +%global rel 27 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -150,6 +150,8 @@ Patch1000: disable-python-extra.patch Patch1001: compile-with-Platform-Python-binary-where-relevant.patch # 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 # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -699,6 +701,10 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog +* Tue Sep 26 2023 Lumír Balhar - 4.14.4-27 +- Make brp-python-bytecompile script compatible with Python 3.10+ +Resolves: RHEL-6423 + * Mon Dec 19 2022 Florian Festi - 4.14.4-26 - Add --nocompression to rpm2archive (#2129345) From 563383c859c6777358b79b482cabe307fa352aef Mon Sep 17 00:00:00 2001 From: Miro Hrončok Date: Oct 26 2023 11:08:52 +0000 Subject: [PATCH 2/8] Fix version in the two latest %changelog entries --- diff --git a/rpm.spec b/rpm.spec index b550fb4..c105920 100644 --- a/rpm.spec +++ b/rpm.spec @@ -701,11 +701,11 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog -* Tue Sep 26 2023 Lumír Balhar - 4.14.4-27 +* Tue Sep 26 2023 Lumír Balhar - 4.14.3-27 - Make brp-python-bytecompile script compatible with Python 3.10+ Resolves: RHEL-6423 -* Mon Dec 19 2022 Florian Festi - 4.14.4-26 +* Mon Dec 19 2022 Florian Festi - 4.14.3-26 - Add --nocompression to rpm2archive (#2129345) * Tue Sep 13 2022 Michal Domonkos - 4.14.3-24 From 0408f935ff5f3ea410d85c2949e339721d5b11c1 Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Nov 02 2023 11:33:09 +0000 Subject: [PATCH 3/8] Backport file handling code from rpm-4.19 Fixes CVE-2021-35937, CVE-2021-35938 and CVE-2021-35939 Resolves: RHEL-9561 RHEL-9563 RHEL-9565 --- diff --git a/0001-Add-optional-callback-on-directory-changes-during-rp.patch b/0001-Add-optional-callback-on-directory-changes-during-rp.patch new file mode 100644 index 0000000..bda7110 --- /dev/null +++ b/0001-Add-optional-callback-on-directory-changes-during-rp.patch @@ -0,0 +1,107 @@ +From 186e0ab025b9ad92d900697f611633a6f6162f3b Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Eliminate-code-duplication-from-rpmfiNext.patch b/0001-Eliminate-code-duplication-from-rpmfiNext.patch new file mode 100644 index 0000000..a5e0463 --- /dev/null +++ b/0001-Eliminate-code-duplication-from-rpmfiNext.patch @@ -0,0 +1,35 @@ +From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch new file mode 100644 index 0000000..0cdde83 --- /dev/null +++ b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch @@ -0,0 +1,157 @@ +From ac7b0dbd5a18d2c57a942ca14ac856b8047425ff Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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/ima.c b/plugins/ima.c +index fe6d3ad7f..9c28a41a3 100644 +--- a/plugins/ima.c ++++ b/plugins/ima.c +@@ -39,7 +39,7 @@ static int check_zero_hdr(const unsigned char *fsig, size_t siglen) + 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,7 +63,12 @@ static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + + fsig = rpmfiFSignature(fi, &len); + if (fsig && (check_zero_hdr(fsig, len) == 0)) { +- if (lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0) < 0) { ++ 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) { + rpmlog(RPMLOG_ERR, + "ima: could not apply signature on '%s': %s\n", + path, strerror(errno)); +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 */ +diff --git a/plugins/selinux.c b/plugins/selinux.c +index 32c3b7529..a7f20aeca 100644 +--- a/plugins/selinux.c ++++ b/plugins/selinux.c +@@ -149,7 +149,7 @@ static rpmRC selinux_scriptlet_fork_post(rpmPlugin plugin, + 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 @@ static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + 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 { +-- +2.41.0 + diff --git a/0001-Use-file-state-machine-from-rpm-4.19.patch b/0001-Use-file-state-machine-from-rpm-4.19.patch new file mode 100644 index 0000000..19c2bdd --- /dev/null +++ b/0001-Use-file-state-machine-from-rpm-4.19.patch @@ -0,0 +1,1653 @@ +From 36ee14a07630668629a0d461fba8b5b2248d7d71 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 10 Oct 2023 16:46:17 +0200 +Subject: [PATCH] Use file state machine from rpm-4.19 + +This new implementation fixes several race conditions when placing down +files on disc +--- + lib/fsm.c | 1164 +++++++++++++++++++++++++--------------------- + lib/rpmarchive.h | 3 + + lib/rpmfiles.h | 3 + + +diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h +index c864e5b56..e5cda4f97 100644 +--- a/lib/rpmarchive.h ++++ b/lib/rpmarchive.h +@@ -26,6 +26,8 @@ enum rpmfilesErrorCodes { + RPMERR_FILE_SIZE = -12, + RPMERR_ITER_SKIP = -13, + RPMERR_EXIST_AS_DIR = -14, ++ RPMERR_INVALID_SYMLINK = -15, ++ RPMERR_ENOTDIR = -16, + + RPMERR_OPEN_FAILED = -32768, + RPMERR_CHMOD_FAILED = -32769, +@@ -47,6 +49,7 @@ enum rpmfilesErrorCodes { + RPMERR_COPY_FAILED = -32785, + RPMERR_LSETFCON_FAILED = -32786, + RPMERR_SETCAP_FAILED = -32787, ++ RPMERR_CLOSE_FAILED = -32788, + }; + + #ifdef __cplusplus +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index daf572cf4..e74bb2201 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e { + #define XFA_SKIPPING(_a) \ + ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) + ++#define XFA_CREATING(_a) \ ++ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) ++ + /** + * We pass these around as an array with a sentinel. + */ +--- rpm-4.14.3/lib/fsm.c.orig 2023-10-11 16:00:49.610090807 +0200 ++++ rpm-4.14.3/lib/fsm.c 2023-10-11 16:01:16.976451270 +0200 +@@ -5,9 +5,11 @@ + + #include "system.h" + ++#include + #include + #include +-#if WITH_CAP ++#include ++#ifdef WITH_CAP + #include + #endif + +@@ -17,10 +19,11 @@ + #include + + #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ +-#include "lib/fsm.h" +-#include "lib/rpmte_internal.h" /* XXX rpmfs */ +-#include "lib/rpmplugins.h" /* rpm plugins hooks */ +-#include "lib/rpmug.h" ++#include "fsm.h" ++#include "rpmte_internal.h" /* XXX rpmfs */ ++#include "rpmfi_internal.h" /* rpmfiSetOnChdir */ ++#include "rpmplugins.h" /* rpm plugins hooks */ ++#include "rpmug.h" + + #include "debug.h" + +@@ -38,172 +41,92 @@ + #define _dirPerms 0755 + #define _filePerms 0644 + ++enum filestage_e { ++ FILE_COMMIT = -1, ++ FILE_NONE = 0, ++ FILE_PRE = 1, ++ FILE_UNPACK = 2, ++ FILE_PREP = 3, ++ FILE_POST = 4, ++}; ++ ++struct filedata_s { ++ int stage; ++ int setmeta; ++ int skip; ++ rpmFileAction action; ++ const char *suffix; ++ char *fpath; ++ struct stat sb; ++}; ++ + /* + * XXX Forward declarations for previously exported functions to avoid moving + * things around needlessly + */ + static const char * fileActionString(rpmFileAction a); ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir); ++static int fsmClose(int *wfdp); + + /** \ingroup payload + * Build path to file from file info, optionally ornamented with suffix. ++ * "/" needs special handling to avoid appearing as empty path. + * @param fi file info iterator + * @param suffix suffix to use (NULL disables) +- * @retval path to file (malloced) ++ * @param[out] path to file (malloced) + */ + static char * fsmFsPath(rpmfi fi, const char * suffix) + { +- return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL); +-} +- +-/** \ingroup payload +- * Directory name iterator. +- */ +-typedef struct dnli_s { +- rpmfiles fi; +- char * active; +- int reverse; +- int isave; +- int i; +-} * DNLI_t; +- +-/** \ingroup payload +- * Destroy directory name iterator. +- * @param dnli directory name iterator +- * @retval NULL always +- */ +-static DNLI_t dnlFreeIterator(DNLI_t dnli) +-{ +- if (dnli) { +- if (dnli->active) free(dnli->active); +- free(dnli); +- } +- return NULL; ++ const char *bn = rpmfiBN(fi); ++ return rstrscat(NULL, *bn ? bn : "/", suffix ? suffix : "", NULL); + } + +-/** \ingroup payload +- * Create directory name iterator. +- * @param fi file info set +- * @param fs file state set +- * @param reverse traverse directory names in reverse order? +- * @return directory name iterator +- */ +-static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse) ++static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path) + { +- DNLI_t dnli; +- int i, j; +- int dc; +- +- if (fi == NULL) +- return NULL; +- dc = rpmfilesDC(fi); +- dnli = xcalloc(1, sizeof(*dnli)); +- dnli->fi = fi; +- dnli->reverse = reverse; +- dnli->i = (reverse ? dc : 0); +- +- if (dc) { +- dnli->active = xcalloc(dc, sizeof(*dnli->active)); +- int fc = rpmfilesFC(fi); +- +- /* Identify parent directories not skipped. */ +- for (i = 0; i < fc; i++) +- if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) +- dnli->active[rpmfilesDI(fi, i)] = 1; +- +- /* Exclude parent directories that are explicitly included. */ +- for (i = 0; i < fc; i++) { +- int dil; +- size_t dnlen, bnlen; ++ int rc = linkat(odirfd, opath, dirfd, path, 0); + +- if (!S_ISDIR(rpmfilesFMode(fi, i))) +- continue; +- +- dil = rpmfilesDI(fi, i); +- dnlen = strlen(rpmfilesDN(fi, dil)); +- bnlen = strlen(rpmfilesBN(fi, i)); +- +- for (j = 0; j < dc; j++) { +- const char * dnl; +- size_t jlen; +- +- if (!dnli->active[j] || j == dil) +- continue; +- dnl = rpmfilesDN(fi, j); +- jlen = strlen(dnl); +- if (jlen != (dnlen+bnlen+1)) +- continue; +- if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen)) +- continue; +- if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen)) +- continue; +- if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') +- continue; +- /* This directory is included in the package. */ +- dnli->active[j] = 0; +- break; +- } +- } +- +- /* Print only once per package. */ +- if (!reverse) { +- j = 0; +- for (i = 0; i < dc; i++) { +- if (!dnli->active[i]) continue; +- if (j == 0) { +- j = 1; +- rpmlog(RPMLOG_DEBUG, +- "========== Directories not explicitly included in package:\n"); +- } +- rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i)); +- } +- if (j) +- rpmlog(RPMLOG_DEBUG, "==========\n"); +- } ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } +- return dnli; ++ ++ if (rc < 0) ++ rc = RPMERR_LINK_FAILED; ++ return rc; + } + +-/** \ingroup payload +- * Return next directory name (from file info). +- * @param dnli directory name iterator +- * @return next directory name +- */ +-static +-const char * dnlNextIterator(DNLI_t dnli) ++#ifdef WITH_CAP ++static int cap_set_fileat(int dirfd, const char *path, cap_t fcaps) + { +- const char * dn = NULL; +- +- if (dnli) { +- rpmfiles fi = dnli->fi; +- int dc = rpmfilesDC(fi); +- int i = -1; +- +- if (dnli->active) +- do { +- i = (!dnli->reverse ? dnli->i++ : --dnli->i); +- } while (i >= 0 && i < dc && !dnli->active[i]); +- +- if (i >= 0 && i < dc) +- dn = rpmfilesDN(fi, i); +- else +- i = -1; +- dnli->isave = i; ++ int rc = -1; ++ int fd = fsmOpenat(dirfd, path, O_RDONLY|O_NOFOLLOW, 0); ++ if (fd >= 0) { ++ rc = cap_set_fd(fd, fcaps); ++ fsmClose(&fd); + } +- return dn; ++ return rc; + } ++#endif + +-static int fsmSetFCaps(const char *path, const char *captxt) ++static int fsmSetFCaps(int fd, int dirfd, const char *path, const char *captxt) + { + int rc = 0; +-#if WITH_CAP ++ ++#ifdef WITH_CAP + if (captxt && *captxt != '\0') { + cap_t fcaps = cap_from_text(captxt); +- if (fcaps == NULL || cap_set_file(path, fcaps) != 0) { +- rc = RPMERR_SETCAP_FAILED; ++ ++ if (fd >= 0) { ++ if (fcaps == NULL || cap_set_fd(fd, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; ++ } else { ++ if (fcaps == NULL || cap_set_fileat(dirfd, path, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; + } ++ + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- path, captxt, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %s) %s\n", __func__, ++ fd, dirfd, path, captxt, (rc < 0 ? strerror(errno) : "")); + } + cap_free(fcaps); + } +@@ -211,101 +134,104 @@ + return rc; + } + +-static void wfd_close(FD_t *wfdp) ++static int fsmClose(int *wfdp) + { +- if (wfdp && *wfdp) { ++ int rc = 0; ++ if (wfdp && *wfdp >= 0) { + int myerrno = errno; + static int oneshot = 0; + static int flush_io = 0; ++ int fdno = *wfdp; ++ + if (!oneshot) { +- flush_io = rpmExpandNumeric("%{?_flush_io}"); ++ flush_io = (rpmExpandNumeric("%{?_flush_io}") > 0); + oneshot = 1; + } + if (flush_io) { +- int fdno = Fileno(*wfdp); + fsync(fdno); + } +- Fclose(*wfdp); +- *wfdp = NULL; ++ if (close(fdno)) ++ rc = RPMERR_CLOSE_FAILED; ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__, ++ fdno, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = -1; + errno = myerrno; + } ++ return rc; + } + +-static int wfd_open(FD_t *wfdp, const char *dest) ++static int fsmOpen(int *wfdp, int dirfd, const char *dest) + { + int rc = 0; + /* Create the file with 0200 permissions (write by owner). */ +- { +- mode_t old_umask = umask(0577); +- *wfdp = Fopen(dest, "wx.ufdio"); +- umask(old_umask); +- } +- if (Ferror(*wfdp)) { ++ int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200); ++ ++ if (fd < 0) + rc = RPMERR_OPEN_FAILED; +- goto exit; +- } + +- return 0; ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__, ++ dest, fd, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = fd; + +-exit: +- wfd_close(wfdp); + return rc; + } + +-/** \ingroup payload +- * Create file from payload stream. +- * @return 0 on success +- */ +-static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) ++static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest) + { +- FD_t wfd = NULL; +- int rc; +- +- rc = wfd_open(&wfd, dest); +- if (rc != 0) +- goto exit; +- +- rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm); +- wfd_close(&wfd); +-exit: ++ FD_t fd = fdDup(fdno); ++ int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm); ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s %" PRIu64 " bytes [%d]) %s\n", __func__, ++ rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd), ++ (rc < 0 ? strerror(errno) : "")); ++ } ++ Fclose(fd); + return rc; + } + +-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, +- rpmpsm psm, int nodigest, int *setmeta, +- int * firsthardlink, FD_t *firstlinkfile) ++static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files, ++ rpmpsm psm, int nodigest, ++ struct filedata_s ** firstlink, int *firstlinkfile, ++ int *firstdir, int *fdp) + { + int rc = 0; +- int numHardlinks = rpmfiFNlink(fi); ++ int fd = -1; + +- if (numHardlinks > 1) { +- /* Create first hardlinked file empty */ +- if (*firsthardlink < 0) { +- *firsthardlink = rpmfiFX(fi); +- rc = wfd_open(firstlinkfile, dest); +- } else { +- /* Create hard links for others */ +- char *fn = rpmfilesFN(files, *firsthardlink); +- rc = link(fn, dest); +- if (rc < 0) { +- rc = RPMERR_LINK_FAILED; +- } +- free(fn); ++ if (*firstlink == NULL) { ++ /* First encounter, open file for writing */ ++ rc = fsmOpen(&fd, dirfd, fp->fpath); ++ /* If it's a part of a hardlinked set, the content may come later */ ++ if (fp->sb.st_nlink > 1) { ++ *firstlink = fp; ++ *firstlinkfile = fd; ++ *firstdir = dup(dirfd); ++ } ++ } else { ++ /* Create hard links for others and avoid redundant metadata setting */ ++ if (*firstlink != fp) { ++ rc = fsmLink(*firstdir, (*firstlink)->fpath, dirfd, fp->fpath); + } ++ fd = *firstlinkfile; + } +- /* Write normal files or fill the last hardlinked (already +- existing) file with content */ +- if (numHardlinks<=1) { +- if (!rc) +- rc = expandRegular(fi, dest, psm, nodigest); +- } else if (rpmfiArchiveHasContent(fi)) { ++ ++ /* If the file has content, unpack it */ ++ if (rpmfiArchiveHasContent(fi)) { + if (!rc) +- rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); +- wfd_close(firstlinkfile); +- *firsthardlink = -1; +- } else { +- *setmeta = 0; ++ rc = fsmUnpack(fi, fd, psm, nodigest); ++ /* Last file of hardlink set, ensure metadata gets set */ ++ if (*firstlink) { ++ fp->setmeta = 1; ++ *firstlink = NULL; ++ *firstlinkfile = -1; ++ fsmClose(firstdir); ++ } + } ++ *fdp = fd; + + return rc; + } +@@ -330,18 +256,15 @@ + return rc; + } + +-static int fsmStat(const char *path, int dolstat, struct stat *sb) ++static int fsmStat(int dirfd, const char *path, int dolstat, struct stat *sb) + { +- int rc; +- if (dolstat){ +- rc = lstat(path, sb); +- } else { +- rc = stat(path, sb); +- } ++ int flags = dolstat ? AT_SYMLINK_NOFOLLOW : 0; ++ int rc = fstatat(dirfd, path, sb, flags); ++ + if (_fsm_debug && rc && errno != ENOENT) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, ost) %s\n", + __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) { + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED); + /* Ensure consistent struct content on failure */ +@@ -350,12 +273,12 @@ + return rc; + } + +-static int fsmRmdir(const char *path) ++static int fsmRmdir(int dirfd, const char *path) + { +- int rc = rmdir(path); ++ int rc = unlinkat(dirfd, path, AT_REMOVEDIR); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + switch (errno) { + case ENOENT: rc = RPMERR_ENOENT; break; +@@ -365,172 +288,193 @@ + return rc; + } + +-static int fsmMkdir(const char *path, mode_t mode) ++static int fsmMkdir(int dirfd, const char *path, mode_t mode) + { +- int rc = mkdir(path, (mode & 07777)); ++ int rc = mkdirat(dirfd, path, (mode & 07777)); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", __func__, ++ dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_MKDIR_FAILED; + return rc; + } + +-static int fsmMkfifo(const char *path, mode_t mode) ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir) + { +- int rc = mkfifo(path, (mode & 07777)); +- +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", +- __func__, path, (unsigned)(mode & 07777), +- (rc < 0 ? strerror(errno) : "")); ++ struct stat lsb, sb; ++ int sflags = flags | O_NOFOLLOW; ++ int fd = openat(dirfd, path, sflags); ++ ++ /* ++ * Only ever follow symlinks by root or target owner. Since we can't ++ * open the symlink itself, the order matters: we stat the link *after* ++ * opening the target, and if the link ownership changed between the calls ++ * it could've only been the link owner or root. ++ */ ++ if (fd < 0 && errno == ELOOP && flags != sflags) { ++ int ffd = openat(dirfd, path, flags); ++ if (ffd >= 0) { ++ if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) { ++ if (fstat(ffd, &sb) == 0) { ++ if (lsb.st_uid == 0 || lsb.st_uid == sb.st_uid) { ++ fd = ffd; ++ } ++ } ++ } ++ if (ffd != fd) ++ close(ffd); ++ } + } + +- if (rc < 0) +- rc = RPMERR_MKFIFO_FAILED; +- +- return rc; ++ /* O_DIRECTORY equivalent */ ++ if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) { ++ errno = ENOTDIR; ++ fsmClose(&fd); ++ } ++ return fd; + } + +-static int fsmMknod(const char *path, mode_t mode, dev_t dev) ++static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn, ++ const char *apath, ++ int owned, mode_t mode, int *fdp) + { +- /* FIX: check S_IFIFO or dev != 0 */ +- int rc = mknod(path, (mode & ~07777), dev); ++ int rc; ++ rpmFsmOp op = (FA_CREATE); ++ if (!owned) ++ op |= FAF_UNOWNED; + +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", +- __func__, path, (unsigned)(mode & ~07777), +- (unsigned)dev, (rc < 0 ? strerror(errno) : "")); ++ /* Run fsm file pre hook for all plugins */ ++ rc = rpmpluginsCallFsmFilePre(plugins, NULL, apath, mode, op); ++ ++ if (!rc) ++ rc = fsmMkdir(dirfd, dn, mode); ++ ++ if (!rc) { ++ *fdp = fsmOpenat(dirfd, dn, O_RDONLY|O_NOFOLLOW, 1); ++ if (*fdp == -1) ++ rc = RPMERR_ENOTDIR; + } + +- if (rc < 0) +- rc = RPMERR_MKNOD_FAILED; ++ if (!rc) { ++ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, *fdp, apath, apath, mode, op); ++ } ++ ++ /* Run fsm file post hook for all plugins */ ++ rpmpluginsCallFsmFilePost(plugins, NULL, apath, mode, op, rc); ++ ++ if (!rc) { ++ rpmlog(RPMLOG_DEBUG, ++ "%s directory created with perms %04o\n", ++ apath, (unsigned)(mode & 07777)); ++ } + + return rc; + } + +-/** +- * Create (if necessary) directories not explicitly included in package. +- * @param files file data +- * @param fs file states +- * @param plugins rpm plugins handle +- * @return 0 on success +- */ +-static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins) ++static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create, ++ int quiet, int *dirfdp) + { +- DNLI_t dnli = dnlInitIterator(files, fs, 0); +- struct stat sb; +- const char *dpath; +- int dc = rpmfilesDC(files); ++ char *sp = NULL, *bn; ++ char *apath = NULL; ++ int oflags = O_RDONLY; + int rc = 0; +- int i; +- int ldnlen = 0; +- int ldnalloc = 0; +- char * ldn = NULL; +- short * dnlx = NULL; +- +- dnlx = (dc ? xcalloc(dc, sizeof(*dnlx)) : NULL); +- +- if (dnlx != NULL) +- while ((dpath = dnlNextIterator(dnli)) != NULL) { +- size_t dnlen = strlen(dpath); +- char * te, dn[dnlen+1]; +- +- dc = dnli->isave; +- if (dc < 0) continue; +- dnlx[dc] = dnlen; +- if (dnlen <= 1) +- continue; + +- if (dnlen <= ldnlen && rstreq(dpath, ldn)) +- continue; ++ if (*dirfdp >= 0) ++ return rc; + +- /* Copy as we need to modify the string */ +- (void) stpcpy(dn, dpath); ++ int dirfd = fsmOpenat(-1, "/", oflags, 1); ++ int fd = dirfd; /* special case of "/" */ + +- /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ +- for (i = 1, te = dn + 1; *te != '\0'; te++, i++) { +- if (*te != '/') +- continue; ++ char *path = xstrdup(p); ++ char *dp = path; + +- *te = '\0'; ++ while ((bn = strtok_r(dp, "/", &sp)) != NULL) { ++ fd = fsmOpenat(dirfd, bn, oflags, 1); ++ /* assemble absolute path for plugins benefit, sigh */ ++ apath = rstrscat(&apath, "/", bn, NULL); + +- /* Already validated? */ +- if (i < ldnlen && +- (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i)) +- { +- *te = '/'; +- /* Move pre-existing path marker forward. */ +- dnlx[dc] = (te - dn); +- continue; ++ if (fd < 0 && errno == ENOENT && create) { ++ mode_t mode = S_IFDIR | (_dirPerms & 07777); ++ rc = fsmDoMkDir(plugins, dirfd, bn, apath, owned, mode, &fd); ++ } ++ ++ fsmClose(&dirfd); ++ if (fd >= 0) { ++ dirfd = fd; ++ } else { ++ if (!quiet) { ++ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"), ++ bn, p, strerror(errno)); + } ++ rc = RPMERR_OPEN_FAILED; ++ break; ++ } + +- /* Validate next component of path. */ +- rc = fsmStat(dn, 1, &sb); /* lstat */ +- *te = '/'; +- +- /* Directory already exists? */ +- if (rc == 0 && S_ISDIR(sb.st_mode)) { +- /* Move pre-existing path marker forward. */ +- dnlx[dc] = (te - dn); +- } else if (rc == RPMERR_ENOENT) { +- *te = '\0'; +- mode_t mode = S_IFDIR | (_dirPerms & 07777); +- rpmFsmOp op = (FA_CREATE|FAF_UNOWNED); +- +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op); +- +- if (!rc) +- rc = fsmMkdir(dn, mode); +- +- if (!rc) { +- rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, +- mode, op); +- } ++ dp = NULL; ++ } + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc); ++ if (rc) { ++ fsmClose(&fd); ++ fsmClose(&dirfd); ++ } else { ++ rc = 0; ++ } ++ *dirfdp = dirfd; + +- if (!rc) { +- rpmlog(RPMLOG_DEBUG, +- "%s directory created with perms %04o\n", +- dn, (unsigned)(mode & 07777)); +- } +- *te = '/'; +- } +- if (rc) +- break; +- } +- if (rc) break; ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s: %d) %s\n", __func__, ++ p, dirfd, (rc < 0 ? strerror(errno) : "")); ++ } + +- /* Save last validated path. */ +- if (ldnalloc < (dnlen + 1)) { +- ldnalloc = dnlen + 100; +- ldn = xrealloc(ldn, ldnalloc); +- } +- if (ldn != NULL) { /* XXX can't happen */ +- strcpy(ldn, dn); +- ldnlen = dnlen; +- } ++ free(path); ++ free(apath); ++ return rc; ++} ++ ++static int fsmMkfifo(int dirfd, const char *path, mode_t mode) ++{ ++ int rc = mkfifoat(dirfd, path, (mode & 07777)); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & 07777), ++ (rc < 0 ? strerror(errno) : "")); ++ } ++ ++ if (rc < 0) ++ rc = RPMERR_MKFIFO_FAILED; ++ ++ return rc; ++} ++ ++static int fsmMknod(int dirfd, const char *path, mode_t mode, dev_t dev) ++{ ++ /* FIX: check S_IFIFO or dev != 0 */ ++ int rc = mknodat(dirfd, path, (mode & ~07777), dev); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%o, 0x%x) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & ~07777), ++ (unsigned)dev, (rc < 0 ? strerror(errno) : "")); + } +- free(dnlx); +- free(ldn); +- dnlFreeIterator(dnli); ++ ++ if (rc < 0) ++ rc = RPMERR_MKNOD_FAILED; + + return rc; + } + +-static void removeSBITS(const char *path) ++static void removeSBITS(int dirfd, const char *path) + { + struct stat stb; +- if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) { + if ((stb.st_mode & 06000) != 0) { +- (void) chmod(path, stb.st_mode & 0777); ++ (void) fchmodat(dirfd, path, stb.st_mode & 0777, flags); + } +-#if WITH_CAP ++#ifdef WITH_CAP + if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { +- (void) cap_set_file(path, NULL); ++ (void) cap_set_fileat(dirfd, path, NULL); + } + #endif + } +@@ -546,13 +490,13 @@ + (fpath ? fpath : "")); + } + +-static int fsmSymlink(const char *opath, const char *path) ++static int fsmSymlink(const char *opath, int dirfd, const char *path) + { +- int rc = symlink(opath, path); ++ int rc = symlinkat(opath, dirfd, path); + + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%s, %d %s) %s\n", __func__, ++ opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } + + if (rc < 0) +@@ -560,96 +504,125 @@ + return rc; + } + +-static int fsmUnlink(const char *path) ++static int fsmUnlink(int dirfd, const char *path) + { + int rc = 0; +- removeSBITS(path); +- rc = unlink(path); ++ removeSBITS(dirfd, path); ++ rc = unlinkat(dirfd, path, 0); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED); + return rc; + } + +-static int fsmRename(const char *opath, const char *path) ++static int fsmRename(int odirfd, const char *opath, int dirfd, const char *path) + { +- removeSBITS(path); +- int rc = rename(opath, path); ++ removeSBITS(dirfd, path); ++ int rc = renameat(odirfd, opath, dirfd, path); + #if defined(ETXTBSY) && defined(__HPUX__) + /* XXX HP-UX (and other os'es) don't permit rename to busy files. */ + if (rc && errno == ETXTBSY) { + char *rmpath = NULL; + rstrscat(&rmpath, path, "-RPMDELETE", NULL); +- rc = rename(path, rmpath); +- if (!rc) rc = rename(opath, path); ++ /* Rename within the original directory */ ++ rc = renameat(odirfd, path, odirfd, rmpath); ++ if (!rc) rc = renameat(odirfd, opath, dirfd, path); + free(rmpath); + } + #endif + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED); + return rc; + } + +-static int fsmRemove(const char *path, mode_t mode) ++static int fsmRemove(int dirfd, const char *path, mode_t mode) + { +- return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path); ++ return S_ISDIR(mode) ? fsmRmdir(dirfd, path) : fsmUnlink(dirfd, path); + } + +-static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid) ++static int fsmChown(int fd, int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid) + { +- int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid) +- rc = 0; ++ int rc; ++ struct stat st; ++ ++ if (fd >= 0) { ++ rc = fchown(fd, uid, gid); ++ if (rc < 0) { ++ if (fstat(fd, &st) == 0 && (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } ++ } else { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ rc = fchownat(dirfd, path, uid, gid, flags); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, flags) == 0 && ++ (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } + } +- if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__, +- path, (int)uid, (int)gid, ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %d, %d) %s\n", __func__, ++ fd, dirfd, path, (int)uid, (int)gid, + (rc < 0 ? strerror(errno) : "")); ++ } + if (rc < 0) rc = RPMERR_CHOWN_FAILED; + return rc; + } + +-static int fsmChmod(const char *path, mode_t mode) ++static int fsmChmod(int fd, int dirfd, const char *path, mode_t mode) + { +- int rc = chmod(path, (mode & 07777)); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777)) +- rc = 0; ++ mode_t fmode = (mode & 07777); ++ int rc; ++ if (fd >= 0) { ++ rc = fchmod(fd, fmode); ++ if (rc < 0) { ++ struct stat st; ++ if (fstat(fd, &st) == 0 && (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } ++ } else { ++ rc = fchmodat(dirfd, path, fmode, 0); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, AT_SYMLINK_NOFOLLOW) == 0 && ++ (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } + } + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0%04o) %s\n", __func__, ++ fd, dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_CHMOD_FAILED; + return rc; + } + +-static int fsmUtime(const char *path, mode_t mode, time_t mtime) ++static int fsmUtime(int fd, int dirfd, const char *path, mode_t mode, time_t mtime) + { + int rc = 0; +- struct timeval stamps[2] = { +- { .tv_sec = mtime, .tv_usec = 0 }, +- { .tv_sec = mtime, .tv_usec = 0 }, ++ struct timespec stamps[2] = { ++ { .tv_sec = mtime, .tv_nsec = 0 }, ++ { .tv_sec = mtime, .tv_nsec = 0 }, + }; + +-#if HAVE_LUTIMES +- rc = lutimes(path, stamps); +-#else +- if (!S_ISLNK(mode)) +- rc = utimes(path, stamps); +-#endif ++ if (fd >= 0) ++ rc = futimens(fd, stamps); ++ else ++ rc = utimensat(dirfd, path, stamps, AT_SYMLINK_NOFOLLOW); + + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__, +- path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0x%x) %s\n", __func__, ++ fd, dirfd, path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_UTIME_FAILED; + /* ...but utime error is not critical for directories */ + if (rc && S_ISDIR(mode)) +@@ -657,24 +630,24 @@ + return rc; + } + +-static int fsmVerify(const char *path, rpmfi fi) ++static int fsmVerify(int dirfd, const char *path, rpmfi fi) + { + int rc; + int saveerrno = errno; + struct stat dsb; + mode_t mode = rpmfiFMode(fi); + +- rc = fsmStat(path, 1, &dsb); ++ rc = fsmStat(dirfd, path, 1, &dsb); + if (rc) + return rc; + + if (S_ISREG(mode)) { + /* HP-UX (and other os'es) don't permit unlink on busy files. */ + char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL); +- rc = fsmRename(path, rmpath); ++ rc = fsmRename(dirfd, path, dirfd, rmpath); + /* XXX shouldn't we take unlink return code here? */ + if (!rc) +- (void) fsmUnlink(rmpath); ++ (void) fsmUnlink(dirfd, rmpath); + else + rc = RPMERR_UNLINK_FAILED; + free(rmpath); +@@ -683,7 +656,7 @@ + if (S_ISDIR(dsb.st_mode)) return 0; + if (S_ISLNK(dsb.st_mode)) { + uid_t luid = dsb.st_uid; +- rc = fsmStat(path, 0, &dsb); ++ rc = fsmStat(dirfd, path, 0, &dsb); + if (rc == RPMERR_ENOENT) rc = 0; + if (rc) return rc; + errno = saveerrno; +@@ -709,7 +682,7 @@ + if (S_ISSOCK(dsb.st_mode)) return 0; + } + /* XXX shouldn't do this with commit/undo. */ +- rc = fsmUnlink(path); ++ rc = fsmUnlink(dirfd, path); + if (rc == 0) rc = RPMERR_ENOENT; + return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */ + } +@@ -723,7 +696,7 @@ + + + /* Rename pre-existing modified or unmanaged file. */ +-static int fsmBackup(rpmfi fi, rpmFileAction action) ++static int fsmBackup(int dirfd, rpmfi fi, rpmFileAction action) + { + int rc = 0; + const char *suffix = NULL; +@@ -744,9 +717,10 @@ + if (suffix) { + char * opath = fsmFsPath(fi, NULL); + char * path = fsmFsPath(fi, suffix); +- rc = fsmRename(opath, path); ++ rc = fsmRename(dirfd, opath, dirfd, path); + if (!rc) { +- rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path); ++ rpmlog(RPMLOG_WARNING, _("%s%s saved as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), path); + } + free(path); + free(opath); +@@ -754,7 +728,8 @@ + return rc; + } + +-static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins, ++static int fsmSetmeta(int fd, int dirfd, const char *path, ++ rpmfi fi, rpmPlugins plugins, + rpmFileAction action, const struct stat * st, + int nofcaps) + { +@@ -762,27 +737,28 @@ + const char *dest = rpmfiFN(fi); + + if (!rc && !getuid()) { +- rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid); ++ rc = fsmChown(fd, dirfd, path, st->st_mode, st->st_uid, st->st_gid); + } + if (!rc && !S_ISLNK(st->st_mode)) { +- rc = fsmChmod(path, st->st_mode); ++ rc = fsmChmod(fd, dirfd, path, st->st_mode); + } + /* Set file capabilities (if enabled) */ + if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) { +- rc = fsmSetFCaps(path, rpmfiFCaps(fi)); ++ rc = fsmSetFCaps(fd, dirfd, path, rpmfiFCaps(fi)); + } + if (!rc) { +- rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi)); ++ rc = fsmUtime(fd, dirfd, path, st->st_mode, rpmfiFMtime(fi)); + } + if (!rc) { + rc = rpmpluginsCallFsmFilePrepare(plugins, fi, +- path, dest, st->st_mode, action); ++ fd, path, dest, ++ st->st_mode, action); + } + + return rc; + } + +-static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix) ++static int fsmCommit(int dirfd, char **path, rpmfi fi, rpmFileAction action, const char *suffix) + { + int rc = 0; + +@@ -796,15 +772,18 @@ + + /* Rename temporary to final file name if needed. */ + if (dest != *path) { +- rc = fsmRename(*path, dest); +- if (!rc && nsuffix) { +- char * opath = fsmFsPath(fi, NULL); +- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), +- opath, dest); +- free(opath); +- } +- free(*path); +- *path = dest; ++ rc = fsmRename(dirfd, *path, dirfd, dest); ++ if (!rc) { ++ if (nsuffix) { ++ char * opath = fsmFsPath(fi, NULL); ++ rpmlog(RPMLOG_WARNING, _("%s%s created as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), dest); ++ free(opath); ++ } ++ free(*path); ++ *path = dest; ++ } else ++ free(dest); + } + } + +@@ -855,184 +834,277 @@ + } + } + ++struct diriter_s { ++ int dirfd; ++ int firstdir; ++}; ++ ++static int onChdir(rpmfi fi, void *data) ++{ ++ struct diriter_s *di = data; ++ ++ fsmClose(&(di->dirfd)); ++ return 0; ++} ++ ++static rpmfi fsmIter(FD_t payload, rpmfiles files, rpmFileIter iter, void *data) ++{ ++ rpmfi fi; ++ if (payload) ++ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ else ++ fi = rpmfilesIter(files, iter); ++ if (fi && data) ++ rpmfiSetOnChdir(fi, onChdir, data); ++ return fi; ++} ++ ++static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di) ++{ ++ fsmClose(&(di->dirfd)); ++ fsmClose(&(di->firstdir)); ++ return rpmfiFree(fi); ++} ++ + int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { + FD_t payload = rpmtePayload(te); +- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ rpmfi fi = NULL; + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; +- int saveerrno = errno; + int rc = 0; ++ int fx = -1; ++ int fc = rpmfilesFC(files); + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; +- int firsthardlink = -1; +- FD_t firstlinkfile = NULL; +- int skip; +- rpmFileAction action; ++ int firstlinkfile = -1; + char *tid = NULL; +- const char *suffix; +- char *fpath = NULL; +- +- if (fi == NULL) { +- rc = RPMERR_BAD_MAGIC; +- goto exit; +- } ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); ++ struct filedata_s *firstlink = NULL; ++ struct diriter_s di = { -1, -1 }; + + /* transaction id used for temporary path suffix while installing */ + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); + +- /* Detect and create directories not explicitly in package. */ +- rc = fsmMkdirs(files, fs, plugins); +- +- while (!rc) { +- /* Read next payload header. */ +- rc = rpmfiNext(fi); ++ /* Collect state data for the whole operation */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ if (rpmfiFFlags(fi) & RPMFILE_GHOST) ++ fp->action = FA_SKIP; ++ else ++ fp->action = rpmfsGetAction(fs, fx); ++ fp->skip = XFA_SKIPPING(fp->action); ++ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) ++ fp->suffix = tid; ++ fp->fpath = fsmFsPath(fi, fp->suffix); + +- if (rc < 0) { +- if (rc == RPMERR_ITER_END) +- rc = 0; +- break; +- } ++ /* Remap file perms, owner, and group. */ ++ rc = rpmfiStat(fi, 1, &fp->sb); + +- action = rpmfsGetAction(fs, rpmfiFX(fi)); +- skip = XFA_SKIPPING(action); +- if (action != FA_TOUCH) { +- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; +- } else { +- suffix = NULL; +- } +- fpath = fsmFsPath(fi, suffix); ++ /* Hardlinks are tricky and handled elsewhere for install */ ++ fp->setmeta = (fp->skip == 0) && ++ (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH); + +- /* Remap file perms, owner, and group. */ +- rc = rpmfiStat(fi, 1, &sb); ++ setFileState(fs, fx); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fp->stage = FILE_PRE; ++ } ++ fi = rpmfiFree(fi); + +- /* Exit on error. */ +- if (rc) +- break; ++ if (rc) ++ goto exit; + +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); +- if (rc) { +- skip = 1; +- } else { +- setFileState(fs, rpmfiFX(fi)); +- } ++ fi = fsmIter(payload, files, ++ payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + +- if (!skip) { +- int setmeta = 1; ++ if (fi == NULL) { ++ rc = RPMERR_BAD_MAGIC; ++ goto exit; ++ } + +- /* When touching we don't need any of this... */ +- if (action == FA_TOUCH) +- goto touch; ++ /* Process the payload */ ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* ++ * Tricksy case: this file is a being skipped, but it's part of ++ * a hardlinked set and has the actual content linked with it. ++ * Write the content to the first non-skipped file of the set ++ * instead. ++ */ ++ if (fp->skip && firstlink && rpmfiArchiveHasContent(fi)) ++ fp = firstlink; ++ ++ if (!fp->skip) { ++ int mayopen = 0; ++ int fd = -1; ++ rc = ensureDir(plugins, rpmfiDN(fi), 0, ++ (fp->action == FA_CREATE), 0, &di.dirfd); + + /* Directories replacing something need early backup */ +- if (!suffix) { +- rc = fsmBackup(fi, action); ++ if (!rc && !fp->suffix && fp != firstlink) { ++ rc = fsmBackup(di.dirfd, fi, fp->action); + } ++ ++ /* Run fsm file pre hook for all plugins */ ++ if (!rc) ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); ++ if (rc) ++ goto setmeta; /* for error notification */ ++ + /* Assume file does't exist when tmp suffix is in use */ +- if (!suffix) { +- rc = fsmVerify(fpath, fi); ++ if (!fp->suffix) { ++ if (fp->action == FA_TOUCH) { ++ struct stat sb; ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &sb); ++ } else { ++ rc = fsmVerify(di.dirfd, fp->fpath, fi); ++ } + } else { + rc = RPMERR_ENOENT; + } + +- if (S_ISREG(sb.st_mode)) { ++ /* See if the file was removed while our attention was elsewhere */ ++ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { ++ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", ++ fp->fpath); ++ fp->action = FA_CREATE; ++ fsmDebug(fp->fpath, fp->action, &fp->sb); ++ } ++ ++ /* When touching we don't need any of this... */ ++ if (fp->action == FA_TOUCH) ++ goto setmeta; ++ ++ if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fpath, files, psm, nodigest, +- &setmeta, &firsthardlink, &firstlinkfile); ++ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile, &di.firstdir, ++ &fd); + } +- } else if (S_ISDIR(sb.st_mode)) { ++ } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- mode_t mode = sb.st_mode; ++ mode_t mode = fp->sb.st_mode; + mode &= ~07777; + mode |= 00700; +- rc = fsmMkdir(fpath, mode); ++ rc = fsmMkdir(di.dirfd, fp->fpath, mode); + } +- } else if (S_ISLNK(sb.st_mode)) { ++ } else if (S_ISLNK(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmSymlink(rpmfiFLink(fi), fpath); ++ rc = fsmSymlink(rpmfiFLink(fi), di.dirfd, fp->fpath); + } +- } else if (S_ISFIFO(sb.st_mode)) { ++ } else if (S_ISFIFO(fp->sb.st_mode)) { + /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfifo(fpath, 0000); ++ rc = fsmMkfifo(di.dirfd, fp->fpath, 0000); + } +- } else if (S_ISCHR(sb.st_mode) || +- S_ISBLK(sb.st_mode) || +- S_ISSOCK(sb.st_mode)) ++ } else if (S_ISCHR(fp->sb.st_mode) || ++ S_ISBLK(fp->sb.st_mode) || ++ S_ISSOCK(fp->sb.st_mode)) + { + if (rc == RPMERR_ENOENT) { +- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); ++ rc = fsmMknod(di.dirfd, fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); + } + } else { + /* XXX Special case /dev/log, which shouldn't be packaged anyways */ +- if (!IS_DEV_LOG(fpath)) ++ if (!IS_DEV_LOG(fp->fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; + } + +-touch: +- /* Set permissions, timestamps etc for non-hardlink entries */ +- if (!rc && setmeta) { +- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); ++setmeta: ++ /* Special files require path-based ops */ ++ mayopen = S_ISREG(fp->sb.st_mode) || S_ISDIR(fp->sb.st_mode); ++ if (!rc && fd == -1 && mayopen) { ++ int flags = O_RDONLY; ++ /* Only follow safe symlinks, and never on temporary files */ ++ if (fp->suffix) ++ flags |= AT_SYMLINK_NOFOLLOW; ++ fd = fsmOpenat(di.dirfd, fp->fpath, flags, ++ S_ISDIR(fp->sb.st_mode)); ++ if (fd < 0) ++ rc = RPMERR_OPEN_FAILED; + } +- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { +- /* On FA_TOUCH no hardlinks are created thus this is skipped. */ +- /* we skip the hard linked file containing the content */ +- /* write the content to the first used instead */ +- char *fn = rpmfilesFN(files, firsthardlink); +- rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); +- wfd_close(&firstlinkfile); +- firsthardlink = -1; +- free(fn); +- } +- +- if (rc) { +- if (!skip) { +- /* XXX only erase if temp fn w suffix is in use */ +- if (suffix) { +- (void) fsmRemove(fpath, sb.st_mode); +- } +- errno = saveerrno; +- } +- } else { +- /* Notify on success. */ +- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); +- +- if (!skip) { +- /* Backup file if needed. Directories are handled earlier */ +- if (suffix) +- rc = fsmBackup(fi, action); + +- if (!rc) +- rc = fsmCommit(&fpath, fi, action, suffix); ++ if (!rc && fp->setmeta) { ++ rc = fsmSetmeta(fd, di.dirfd, fp->fpath, ++ fi, plugins, fp->action, ++ &fp->sb, nofcaps); + } ++ ++ if (fd != firstlinkfile) ++ fsmClose(&fd); + } + ++ /* Notify on success. */ + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ else ++ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); ++ fp->stage = FILE_UNPACK; ++ } ++ fi = fsmIterFini(fi, &di); + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); +- fpath = _free(fpath); ++ if (!rc && fx < 0 && fx != RPMERR_ITER_END) ++ rc = fx; ++ ++ /* If all went well, commit files to final destination */ ++ fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ if (!fp->skip) { ++ if (!rc) ++ rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd); ++ ++ /* Backup file if needed. Directories are handled earlier */ ++ if (!rc && fp->suffix) ++ rc = fsmBackup(di.dirfd, fi, fp->action); ++ ++ if (!rc) ++ rc = fsmCommit(di.dirfd, &fp->fpath, fi, fp->action, fp->suffix); ++ ++ if (!rc) ++ fp->stage = FILE_COMMIT; ++ else ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ ++ /* Run fsm file post hook for all plugins for all processed files */ ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); ++ } ++ } ++ fi = fsmIterFini(fi, &di); ++ ++ /* On failure, walk backwards and erase non-committed files */ ++ if (rc) { ++ fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); ++ while ((fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ if (fp->stage > FILE_NONE && !fp->skip) { ++ (void) fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); ++ } ++ } + } + + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + + exit: +- +- /* No need to bother with close errors on read */ +- rpmfiArchiveClose(fi); +- rpmfiFree(fi); ++ fi = fsmIterFini(fi, &di); + Fclose(payload); + free(tid); +- free(fpath); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); + + return rc; + } +@@ -1041,32 +1113,42 @@ + int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { +- rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); ++ struct diriter_s di = { -1, -1 }; ++ rpmfi fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; ++ int fc = rpmfilesFC(files); ++ int fx = -1; ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + int rc = 0; +- char *fpath = NULL; + +- while (!rc && rpmfiNext(fi) >= 0) { +- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); +- fpath = fsmFsPath(fi, NULL); +- rc = fsmStat(fpath, 1, &sb); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); ++ ++ if (XFA_SKIPPING(fp->action)) ++ continue; ++ ++ fp->fpath = fsmFsPath(fi, NULL); ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + + /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); + +- if (!XFA_SKIPPING(action)) +- rc = fsmBackup(fi, action); ++ rc = fsmBackup(di.dirfd, fi, fp->action); + + /* Remove erased files. */ +- if (action == FA_ERASE) { ++ if (fp->action == FA_ERASE) { + int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); + +- rc = fsmRemove(fpath, sb.st_mode); ++ rc = fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); + + /* + * Missing %ghost or %missingok entries are not errors. +@@ -1091,20 +1173,20 @@ + if (rc) { + int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING; + rpmlog(lvl, _("%s %s: remove failed: %s\n"), +- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), +- fpath, strerror(errno)); ++ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), ++ fp->fpath, strerror(errno)); + } + } + + /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); + + /* XXX Failure to remove is not (yet) cause for failure. */ + if (!strict_erasures) rc = 0; + + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); + + if (rc == 0) { + /* Notify on success. */ +@@ -1112,11 +1194,12 @@ + rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); + rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + } +- fpath = _free(fpath); + } + +- free(fpath); +- rpmfiFree(fi); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); ++ fsmIterFini(fi, &di); + + return rc; + } diff --git a/rpm.spec b/rpm.spec index c105920..a9629f9 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 27 +%global rel 28 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -119,6 +119,11 @@ Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch 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-Use-file-state-machine-from-rpm-4.19.patch # Python 3 string API sanity Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch @@ -701,6 +706,10 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog +* Fri Oct 13 2023 Florian Festi - 4.14.3-28 +- 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 - 4.14.3-27 - Make brp-python-bytecompile script compatible with Python 3.10+ Resolves: RHEL-6423 From e91f7f791b4b77a1f65a2c17fe1e75e9491d4f0c Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Nov 07 2023 13:02:41 +0000 Subject: [PATCH 4/8] Fix plugin code for the new fsm implementation Resolves: RHEL-9561 RHEL-9563 RHEL-9565 --- diff --git a/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch new file mode 100644 index 0000000..3210c07 --- /dev/null +++ b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch @@ -0,0 +1,90 @@ +From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/rpm.spec b/rpm.spec index a9629f9..79e818a 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 28 +%global rel 29 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -119,11 +119,12 @@ Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch 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 +# 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-Use-file-state-machine-from-rpm-4.19.patch +Patch172: 0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch +Patch173: 0001-Use-file-state-machine-from-rpm-4.19.patch # Python 3 string API sanity Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch @@ -706,7 +707,7 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog -* Fri Oct 13 2023 Florian Festi - 4.14.3-28 +* Tue Nov 07 2023 Florian Festi - 4.14.3-29 - Backport file handling code from rpm-4.19 to fix CVE-2021-35937, CVE-2021-35938 and CVE-2021-35939 From 284b6bc6f8eb245e100790783a5251cc7964381b Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Nov 10 2023 09:39:39 +0000 Subject: [PATCH 5/8] Fix regression in new code CVE-2005-4889-rpm-fails-to-drop-SUID-SGID-bits-on-package fails with the new code as older glibc versions don't support AT_SYMLINK_NOFOLLOW for fchmodat. Fixed upstream as https://github.com/rpm-software-management/rpm/pull/2759 Resolves: RHEL-9561 RHEL-9563 RHEL-9565 --- diff --git a/0001-Use-file-state-machine-from-rpm-4.19.patch b/0001-Use-file-state-machine-from-rpm-4.19.patch index 19c2bdd..5b6653e 100644 --- a/0001-Use-file-state-machine-from-rpm-4.19.patch +++ b/0001-Use-file-state-machine-from-rpm-4.19.patch @@ -513,7 +513,7 @@ index daf572cf4..e74bb2201 100644 if (rc < 0) switch (errno) { case ENOENT: rc = RPMERR_ENOENT; break; -@@ -365,172 +288,193 @@ +@@ -365,172 +288,194 @@ return rc; } @@ -819,9 +819,10 @@ index daf572cf4..e74bb2201 100644 - if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) { + int flags = AT_SYMLINK_NOFOLLOW; + if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) { ++ /* We now know it's not a link so no need to worry about following */ if ((stb.st_mode & 06000) != 0) { - (void) chmod(path, stb.st_mode & 0777); -+ (void) fchmodat(dirfd, path, stb.st_mode & 0777, flags); ++ (void) fchmodat(dirfd, path, stb.st_mode & 0777, 0); } -#if WITH_CAP +#ifdef WITH_CAP diff --git a/rpm.spec b/rpm.spec index 79e818a..aa07aea 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 29 +%global rel 30 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -707,7 +707,7 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog -* Tue Nov 07 2023 Florian Festi - 4.14.3-29 +* Fri Nov 10 2023 Florian Festi - 4.14.3-30 - Backport file handling code from rpm-4.19 to fix CVE-2021-35937, CVE-2021-35938 and CVE-2021-35939 From b86572b8d2e2f78f7e6bb4c05914fd747ae0fbb4 Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Dec 13 2023 13:31:16 +0000 Subject: [PATCH 6/8] Fix issues with backported file handling Resolves: RHEL-9561 RHEL-9563 RHEL-9565 --- diff --git a/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch new file mode 100644 index 0000000..f910f38 --- /dev/null +++ b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch @@ -0,0 +1,30 @@ +From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch new file mode 100644 index 0000000..29fb473 --- /dev/null +++ b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch @@ -0,0 +1,66 @@ +From c140768202e271b60910644c1e4bf848a50218d3 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch new file mode 100644 index 0000000..1d73765 --- /dev/null +++ b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch @@ -0,0 +1,46 @@ +From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch index 0cdde83..51ecf97 100644 --- a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch +++ b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch @@ -76,11 +76,23 @@ index 39762c376..ddf5d7048 100644 mode_t mode, rpmFsmOp op); #ifdef __cplusplus -diff --git a/plugins/ima.c b/plugins/ima.c -index fe6d3ad7f..9c28a41a3 100644 ---- a/plugins/ima.c -+++ b/plugins/ima.c -@@ -39,7 +39,7 @@ static int check_zero_hdr(const unsigned char *fsig, size_t siglen) +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); } @@ -89,39 +101,26 @@ index fe6d3ad7f..9c28a41a3 100644 const char *path, const char *dest, mode_t file_mode, rpmFsmOp op) -@@ -63,7 +63,12 @@ static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, +@@ -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) { - rpmlog(RPMLOG_ERR, ++ int is_err = errno != EOPNOTSUPP; ++ rpmlog(is_err?RPMLOG_ERR:RPMLOG_DEBUG, "ima: could not apply signature on '%s': %s\n", path, strerror(errno)); -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 */ -diff --git a/plugins/selinux.c b/plugins/selinux.c -index 32c3b7529..a7f20aeca 100644 ---- a/plugins/selinux.c -+++ b/plugins/selinux.c -@@ -149,7 +149,7 @@ static rpmRC selinux_scriptlet_fork_post(rpmPlugin plugin, + 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; } @@ -130,7 +129,7 @@ index 32c3b7529..a7f20aeca 100644 const char *path, const char *dest, mode_t file_mode, rpmFsmOp op) { -@@ -159,14 +159,17 @@ static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, +@@ -159,14 +159,17 @@ if (sehandle && !XFA_SKIPPING(action)) { security_context_t scon = NULL; if (selabel_lookup_raw(sehandle, &scon, dest, file_mode) == 0) { @@ -152,6 +151,3 @@ index 32c3b7529..a7f20aeca 100644 freecon(scon); } else { --- -2.41.0 - diff --git a/0001-Print-full-path-if-file-removal-fails.patch b/0001-Print-full-path-if-file-removal-fails.patch new file mode 100644 index 0000000..266bd69 --- /dev/null +++ b/0001-Print-full-path-if-file-removal-fails.patch @@ -0,0 +1,32 @@ +From f1503ab6e898430b80017c0f8347860f3a74d5bb Mon Sep 17 00:00:00 2001 +From: Florian Festi +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 + diff --git a/rpm.spec b/rpm.spec index aa07aea..a52c767 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 30 +%global rel 31 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -125,6 +125,10 @@ 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 @@ -707,7 +711,7 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog -* Fri Nov 10 2023 Florian Festi - 4.14.3-30 +* Tue Dec 12 2023 Florian Festi - 4.14.3-31 - Backport file handling code from rpm-4.19 to fix CVE-2021-35937, CVE-2021-35938 and CVE-2021-35939 From 472f5364fd28f86e34a3f9ae75812c788fccd737 Mon Sep 17 00:00:00 2001 From: Davide Cavalca Date: Feb 21 2024 19:56:56 +0000 Subject: [PATCH 7/8] Convert to dist-git layout --- diff --git a/.gitignore b/.gitignore index 2f8a22a..7c30adb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/rpm-4.14.3.tar.bz2 +/rpm-4.14.3.tar.bz2 diff --git a/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch b/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch new file mode 100644 index 0000000..4ecdab7 --- /dev/null +++ b/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch @@ -0,0 +1,32 @@ +From 5b21f2f2a12adfd9e1adffc2bf1ad7171ee5d03c Mon Sep 17 00:00:00 2001 +From: "Vladimir D. Seleznev" +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 +--- + 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 + diff --git a/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch b/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch new file mode 100644 index 0000000..5601c58 --- /dev/null +++ b/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch @@ -0,0 +1,93 @@ +From 1da9e839bb573b9187403983f5a69853ab364306 Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Sun, 17 Mar 2019 06:47:26 +0100 +Subject: [PATCH] Add flag to use strip -g instead of full strip on DSOs + (RhBug:1663264) + +The find-debuginfo.sh flag -g had exactly this meaning. But from +version rpm-4.13.0-alpha flag -g changes its behavior. It affects +both libraries and executables. + +For some packages the original behavior was preferred. That is why +the new find-debuginfo.sh flag --g-libs is created. + +Options -g and --g-libs are mutually exclusive. + + +Adjusted for rpm-4.14.2 in RHEL + +--- rpm-4.14.2/scripts/find-debuginfo.sh.orig 2019-04-24 15:14:29.351010878 +0200 ++++ rpm-4.14.2/scripts/find-debuginfo.sh 2019-04-24 15:19:42.296240705 +0200 +@@ -4,6 +4,7 @@ + # + # Usage: find-debuginfo.sh [--strict-build-id] [-g] [-r] [-m] [-i] [-n] + # [--keep-section SECTION] [--remove-section SECTION] ++# [--g-libs] + # [-j N] [--jobs N] + # [-o debugfiles.list] + # [-S debugsourcefiles.list] +@@ -16,6 +17,8 @@ + # [builddir] + # + # The -g flag says to use strip -g instead of full strip on DSOs or EXEs. ++# The --g-libs flag says to use strip -g instead of full strip ONLY on DSOs. ++# Options -g and --g-libs are mutually exclusive. + # The -r flag says to use eu-strip --reloc-debug-sections. + # Use --keep-section SECTION or --remove-section SECTION to explicitly + # keep a (non-allocated) section in the main executable or explicitly +@@ -68,6 +71,9 @@ + # With -g arg, pass it to strip on libraries or executables. + strip_g=false + ++# With --g-libs arg, pass it to strip on libraries. ++strip_glibs=false ++ + # with -r arg, pass --reloc-debug-sections to eu-strip. + strip_r=false + +@@ -135,6 +141,9 @@ + unique_debug_src_base=$2 + shift + ;; ++ --g-libs) ++ strip_glibs=true ++ ;; + -g) + strip_g=true + ;; +@@ -204,6 +213,11 @@ + exit 2 + fi + ++if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then ++ echo >&2 "*** ERROR: -g and --g-libs cannot be used together" ++ exit 2 ++fi ++ + i=0 + while ((i < nout)); do + outs[$i]="$BUILDDIR/${outs[$i]}" +@@ -237,6 +251,9 @@ + application/x-executable*) g=-g ;; + application/x-pie-executable*) g=-g ;; + esac ++ $strip_glibs && case "$(file -bi "$2")" in ++ application/x-sharedlib*) g=-g ;; ++ esac + eu-strip --remove-comment $r $g ${keep_remove_args} -f "$1" "$2" || exit + chmod 444 "$1" || exit + } +@@ -430,8 +430,12 @@ + # libraries. Other executable ELF files (like kernel modules) don't need it. + if [ "$include_minidebug" = "true" -a "$strip_g" = "false" ]; then + skip_mini=true ++ if [ "$strip_glibs" = "false" ]; then ++ case "$(file -bi "$f")" in ++ application/x-sharedlib*) skip_mini=false ;; ++ esac ++ fi + case "$(file -bi "$f")" in +- application/x-sharedlib*) skip_mini=false ;; + application/x-executable*) skip_mini=false ;; + application/x-pie-executable*) skip_mini=false ;; + esac diff --git a/0001-Add-limits-to-autopatch-macro.patch b/0001-Add-limits-to-autopatch-macro.patch new file mode 100644 index 0000000..3235922 --- /dev/null +++ b/0001-Add-limits-to-autopatch-macro.patch @@ -0,0 +1,44 @@ +From f00bb5be9caa62220c6aeaf3f7264840d5c089e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Tue, 5 Feb 2019 18:15:47 +0100 +Subject: [PATCH] Add limits to autopatch macro + +Limits allow to apply only range of patches with given parameters. +Useful if something needs to be done between patch sets. Allows applying +of patches with different -pX parameter in one spec file. + +Resolves: #626 +Co-authored-by: Florian Festi +--- + macros.in | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/macros.in b/macros.in +index 7b5b63020..912ad5997 100644 +--- a/macros.in ++++ b/macros.in +@@ -1265,11 +1265,19 @@ else\ + end} + + # Automatically apply all patches +-%autopatch(vp:)\ ++# -m Apply patches with number >= min only ++# -M Apply patches with number <= max only ++%autopatch(vp:m:M:)\ + %{lua:\ + local options = rpm.expand("%{!-v:-q} %{-p:-p%{-p*}} ")\ ++local low_limit = tonumber(rpm.expand("%{-m:%{-m*}}"))\ ++local high_limit = tonumber(rpm.expand("%{-M:%{-M*}}"))\ + for i, p in ipairs(patches) do\ +- print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n"))\ ++ local inum = patch_nums[i]\ ++ if ((not low_limit or inum>=low_limit) and (not high_limit or inum<=high_limit)) \ ++ then\ ++ print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n")) \ ++ end\ + end} + + # One macro to (optionally) do it all. +-- +2.26.2 + diff --git a/0001-Always-close-libelf-handle-1313.patch b/0001-Always-close-libelf-handle-1313.patch new file mode 100644 index 0000000..81a1296 --- /dev/null +++ b/0001-Always-close-libelf-handle-1313.patch @@ -0,0 +1,32 @@ +From 38c03ddb18e86c84d89af695f72442d8365eb64e Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 21 Jul 2020 10:45:20 +0200 +Subject: [PATCH] Always close libelf handle (#1313) + +Otherwise executables that are not proper elf files are leaking libelf +handles. This results in file being left open (mmap'ed) and fails the +build on NFS as those files can't be deleted properly there. + +Resolves: rhbz#1840728 +See also: https://bugzilla.redhat.com/show_bug.cgi?id=1840728 +--- + build/files.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/build/files.c b/build/files.c +index f675306f7..62489c07c 100644 +--- a/build/files.c ++++ b/build/files.c +@@ -1935,8 +1935,8 @@ static int generateBuildIDs(FileList fl, ARGV_t *files) + if (terminate) + rc = 1; + } +- elf_end (elf); + } ++ elf_end (elf); + close (fd); + } + } +-- +2.26.2 + diff --git a/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch b/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch new file mode 100644 index 0000000..df0aaab --- /dev/null +++ b/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch @@ -0,0 +1,37 @@ +From c4f285cff8f830447857e52848ecf909cedb192a Mon Sep 17 00:00:00 2001 +Message-Id: +From: Panu Matilainen +Date: Tue, 6 Nov 2018 12:22:55 +0200 +Subject: [PATCH] Document --noverify in the man page (RhBug:1646458) + +Should've been in commit 765e2c72ae8be369ada41d4747b8999519a0e327 +--- + doc/rpm.8 | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/doc/rpm.8 b/doc/rpm.8 +index 5ab61b2ac..31c51d821 100644 +--- a/doc/rpm.8 ++++ b/doc/rpm.8 +@@ -104,7 +104,7 @@ Scripts and triggers: + [\fB--ignoresize\fR] [\fB--ignorearch\fR] [\fB--ignoreos\fR] + [\fB--includedocs\fR] [\fB--justdb\fR] + [\fB--nodeps\fR] [\fB--nodigest\fR] [\fB--noplugins\fR] +- [\fB--nocaps\fR] [\fB--noorder\fR] ++ [\fB--nocaps\fR] [\fB--noorder\fR] [\fB--noverify\fR] + [\fB--nosignature\fR] [\fB--noscripts\fR] [\fB--notriggers\fR] + [\fB--oldpackage\fR] [\fB--percent\fR] [\fB--prefix \fINEWPATH\fB\fR] + [\fB--relocate \fIOLDPATH\fB=\fINEWPATH\fB\fR] +@@ -315,6 +315,9 @@ Don't set file capabilities. + Don't reorder the packages for an install. The list of + packages would normally be reordered to satisfy dependencies. + .TP ++\fB--noverify\fR ++Don't perform verify package files prior to installation. ++.TP + \fB--noplugins\fR + Do not load and execute plugins. + .TP +-- +2.19.2 + diff --git a/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch b/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch new file mode 100644 index 0000000..df98eaa --- /dev/null +++ b/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch @@ -0,0 +1,152 @@ +From 13f70e3710b2df49a923cc6450ff4a8f86e65666 Mon Sep 17 00:00:00 2001 +Message-Id: <13f70e3710b2df49a923cc6450ff4a8f86e65666.1555050140.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 20 Mar 2019 12:38:00 +0200 +Subject: [PATCH] Fix FA_TOUCH on files with suid/sgid bits and/or capabilities + +FA_TOUCH used to set suffix to "" instead of NULL which causes fsmCommit() +to rename the file onto itself, which is a bit dumb but mostly harmless +with regular permission. On suid/sgid/capabilities we strip any extra +privileges on rename to make sure hardlinks are neutered, and because +rename occurs after other permissions etc setting, on FA_TOUCH those +extra privileges are stripped and much brokenness will follow. + +A more minimal fix would be a strategically placed strcmp(), but NULL +is what the rest of the fsm expects for no suffix and differentiating +between empty and NULL suffix is too subtle for its own good as +witnessed here. So now, NULL suffix is no suffix again and the rest +of the code will do the right thing except where related to creation, +and creation is what FA_TOUCH wont do so lets just explicitly skip it +and restore the original code otherwise. The goto is ugly but reindenting +gets even uglier, shrug. Add a test-case to go with it. + +This has been broken since its introduction in commit +79ca74e15e15c1d91a9a31a9ee90abc91736f390 so all current 4.14.x versions +are affected. +--- + lib/fsm.c | 17 ++++++++++---- + tests/data/SPECS/replacetest.spec | 2 +- + tests/rpmverify.at | 38 ++++++++++++++++++++++++++++++- + 3 files changed, 50 insertions(+), 7 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 8eb2c185c..432bcbd90 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -898,12 +898,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + + action = rpmfsGetAction(fs, rpmfiFX(fi)); + skip = XFA_SKIPPING(action); +- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; + if (action != FA_TOUCH) { +- fpath = fsmFsPath(fi, suffix); ++ suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; + } else { +- fpath = fsmFsPath(fi, ""); ++ suffix = NULL; + } ++ fpath = fsmFsPath(fi, suffix); + + /* Remap file perms, owner, and group. */ + rc = rpmfiStat(fi, 1, &sb); +@@ -926,6 +926,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!skip) { + int setmeta = 1; + ++ /* When touching we don't need any of this... */ ++ if (action == FA_TOUCH) ++ goto touch; ++ + /* Directories replacing something need early backup */ + if (!suffix) { + rc = fsmBackup(fi, action); +@@ -934,7 +938,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!suffix) { + rc = fsmVerify(fpath, fi); + } else { +- rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT; ++ rc = RPMERR_ENOENT; + } + + if (S_ISREG(sb.st_mode)) { +@@ -970,11 +974,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!IS_DEV_LOG(fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; + } ++ ++touch: + /* Set permissions, timestamps etc for non-hardlink entries */ + if (!rc && setmeta) { + rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); + } + } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { ++ /* On FA_TOUCH no hardlinks are created thus this is skipped. */ + /* we skip the hard linked file containing the content */ + /* write the content to the first used instead */ + char *fn = rpmfilesFN(files, firsthardlink); +@@ -987,7 +994,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (rc) { + if (!skip) { + /* XXX only erase if temp fn w suffix is in use */ +- if (suffix && (action != FA_TOUCH)) { ++ if (suffix) { + (void) fsmRemove(fpath, sb.st_mode); + } + errno = saveerrno; +diff --git a/tests/data/SPECS/replacetest.spec b/tests/data/SPECS/replacetest.spec +index 54974567b..d5a1729d3 100644 +--- a/tests/data/SPECS/replacetest.spec ++++ b/tests/data/SPECS/replacetest.spec +@@ -46,4 +46,4 @@ rm -rf $RPM_BUILD_ROOT + + %files + %defattr(-,%{user},%{grp},-) +-/opt/* ++%{?fileattr} /opt/* +diff --git a/tests/rpmverify.at b/tests/rpmverify.at +index 52ee2abfb..f7dd57531 100644 +--- a/tests/rpmverify.at ++++ b/tests/rpmverify.at +@@ -575,3 +575,39 @@ + ], + []) + AT_CLEANUP ++ ++AT_SETUP([Upgraded verification with min_writes 5 (suid files)]) ++AT_KEYWORDS([upgrade verify min_writes]) ++AT_CHECK([ ++RPMDB_CLEAR ++RPMDB_INIT ++tf="${RPMTEST}"/opt/foo ++rm -rf "${tf}" "${tf}".rpm* ++rm -rf "${TOPDIR}" ++ ++for v in "1.0" "2.0"; do ++ runroot rpmbuild --quiet -bb \ ++ --define "ver $v" \ ++ --define "filetype file" \ ++ --define "filedata foo" \ ++ --define "fileattr %attr(2755,-,-)" \ ++ /data/SPECS/replacetest.spec ++done ++ ++runroot rpm -U /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm ++runroot rpm -Va --nouser --nogroup replacetest ++runroot rpm -U \ ++ --define "_minimize_writes 1" \ ++ /build/RPMS/noarch/replacetest-2.0-1.noarch.rpm ++runroot rpm -Va --nouser --nogroup replacetest ++chmod 777 "${tf}" ++runroot rpm -U \ ++ --oldpackage \ ++ --define "_minimize_writes 1" \ ++ /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm ++runroot rpm -Va --nouser --nogroup replacetest ++], ++[0], ++[], ++[]) ++AT_CLEANUP +-- +2.20.1 + diff --git a/0001-Fix-brp-strip-static-archive-parallelism.patch b/0001-Fix-brp-strip-static-archive-parallelism.patch new file mode 100644 index 0000000..a1583f9 --- /dev/null +++ b/0001-Fix-brp-strip-static-archive-parallelism.patch @@ -0,0 +1,41 @@ +From 1fd84fa0cfa6e493d1c15edfb7d9f0bb05e4f920 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Thu, 2 May 2019 17:17:56 +0200 +Subject: [PATCH] Fix brp-strip-static-archive parallelism + +The change made in fc2c986 can break for large values of %_smp_build_ncpus as +this many processes are able to overflow the following pipe. + +Thanks to Denys Vlasenko for testing this. + +This change solves this problem by running a whole processing pileline for each +parallel (file) process. This has also the benefit of running at least some +stip commands in parallel. + +The -n param fro xargs was increased to 32 to further reduce the over head of +spawing the helpers as they are now needed for each run of the file command. +--- + scripts/brp-strip-static-archive | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive +index 4dc449061..13d9a098b 100755 +--- a/scripts/brp-strip-static-archive ++++ b/scripts/brp-strip-static-archive +@@ -13,10 +13,6 @@ Darwin*) exit 0 ;; + esac + + # Strip static libraries. +-for f in `find "$RPM_BUILD_ROOT" -type f | \ +- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ +- xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \ +- grep 'current ar archive' | \ +- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do +- $STRIP -g "$f" +-done ++find "$RPM_BUILD_ROOT" -type f | \ ++ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ ++ xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0 +-- +2.21.0 + diff --git a/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch b/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch new file mode 100644 index 0000000..809f065 --- /dev/null +++ b/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch @@ -0,0 +1,102 @@ +From 60066aba510b3ff4a7db092021aae71948e3f8be Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Thu, 4 Jun 2020 11:18:01 +0300 +Subject: [PATCH] Fix python ts.addErase() not raising exception on not-found + packages + +The code would only raise an exception if TransactionSetCore.addErase() +returned an error, but the catch is that with many kinds of argument +types we'd silently skip the whole addition because no headers were found. +This looks to be a regression introduced some eleven years ago in +commit 9b20c706a4f93266450fae2f94007343b2e8fd9e. + +As a special case, a match iterator argument will not raise an exception +if it doesn't actually match anything. + +Fixes: #1214 +--- + python/rpm/transaction.py | 26 +++++++++++++++----------- + tests/rpmpython.at | 22 ++++++++++++++++++++++ + 2 files changed, 37 insertions(+), 11 deletions(-) + +diff --git a/python/rpm/transaction.py b/python/rpm/transaction.py +index 7c4a551d3..3c9ddb207 100644 +--- a/python/rpm/transaction.py ++++ b/python/rpm/transaction.py +@@ -91,14 +91,22 @@ class TransactionSet(TransactionSetCore): + + def addErase(self, item): + hdrs = [] +- if isinstance(item, rpm.hdr): +- hdrs = [item] +- elif isinstance(item, rpm.mi): ++ # match iterators are passed on as-is ++ if isinstance(item, rpm.mi): + hdrs = item +- elif isinstance(item, int): +- hdrs = self.dbMatch(rpm.RPMDBI_PACKAGES, item) +- elif isinstance(item, _string_types): +- hdrs = self.dbMatch(rpm.RPMDBI_LABEL, item) ++ elif isinstance(item, rpm.hdr): ++ hdrs.append(item) ++ elif isinstance(item, (int, _string_types)): ++ if isinstance(item, int): ++ dbi = rpm.RPMDBI_PACKAGES ++ else: ++ dbi = rpm.RPMDBI_LABEL ++ ++ for h in self.dbMatch(dbi, item): ++ hdrs.append(h) ++ ++ if not hdrs: ++ raise rpm.error("package not installed") + else: + raise TypeError("invalid type %s" % type(item)) + +@@ -106,10 +114,6 @@ class TransactionSet(TransactionSetCore): + if not TransactionSetCore.addErase(self, h): + raise rpm.error("package not installed") + +- # garbage collection should take care but just in case... +- if isinstance(hdrs, rpm.mi): +- del hdrs +- + def run(self, callback, data): + rc = TransactionSetCore.run(self, callback, data, self._probFilter) + +diff --git a/tests/rpmpython.at b/tests/rpmpython.at +index 3a7c251f1..de39c8417 100644 +--- a/tests/rpmpython.at ++++ b/tests/rpmpython.at +@@ -201,6 +201,28 @@ for e in ts: + [foo-1.0-1.noarch] + ) + ++RPMPY_TEST([add erasure to transaction],[ ++ts = rpm.ts() ++for i in ['foo', 1234]: ++ myprint('addErase %s' % i) ++ try: ++ ts.addErase(i) ++ except rpm.error as err: ++ myprint(err) ++myprint('addErase mi') ++mi = ts.dbMatch('name', 'foo') ++try: ++ ts.addErase(mi) ++except rpm.error as err: ++ myprint(err) ++], ++[addErase foo ++package not installed ++addErase 1234 ++package not installed ++addErase mi] ++) ++ + RPMPY_TEST([add bogus package to transaction 1],[ + ts = rpm.ts() + h = rpm.hdr() +-- +2.26.2 + diff --git a/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch b/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch new file mode 100644 index 0000000..b3c2f4b --- /dev/null +++ b/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch @@ -0,0 +1,50 @@ +From ed6c5573c09611ff9522ed290ef9d1ba717d8019 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Panu Matilainen +Date: Thu, 21 Nov 2019 12:22:45 +0200 +Subject: [PATCH] Fix resource leaks on zstd open error paths + +If zstd stream initialization fails, the opened fd and the stream +itself are leaked. Handle error exit in a central label. +--- + rpmio/rpmio.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c +index 243942411..10ba20cd6 100644 +--- a/rpmio/rpmio.c ++++ b/rpmio/rpmio.c +@@ -1128,13 +1128,13 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode) + if ((flags & O_ACCMODE) == O_RDONLY) { /* decompressing */ + if ((_stream = (void *) ZSTD_createDStream()) == NULL + || ZSTD_isError(ZSTD_initDStream(_stream))) { +- return NULL; ++ goto err; + } + nb = ZSTD_DStreamInSize(); + } else { /* compressing */ + if ((_stream = (void *) ZSTD_createCStream()) == NULL + || ZSTD_isError(ZSTD_initCStream(_stream, level))) { +- return NULL; ++ goto err; + } + nb = ZSTD_CStreamOutSize(); + } +@@ -1149,6 +1149,14 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode) + zstd->b = xmalloc(nb); + + return zstd; ++ ++err: ++ fclose(fp); ++ if ((flags & O_ACCMODE) == O_RDONLY) ++ ZSTD_freeDStream(_stream); ++ else ++ ZSTD_freeCStream(_stream); ++ return NULL; + } + + static FD_t zstdFdopen(FD_t fd, int fdno, const char * fmode) +-- +2.23.0 + diff --git a/0001-Honor-PYTHON-from-configure-when-running-tests.patch b/0001-Honor-PYTHON-from-configure-when-running-tests.patch new file mode 100644 index 0000000..b39c52b --- /dev/null +++ b/0001-Honor-PYTHON-from-configure-when-running-tests.patch @@ -0,0 +1,53 @@ +From 6b6c4d881dc6fc99f949dac4aaf9a513542f9956 Mon Sep 17 00:00:00 2001 +Message-Id: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 3 Oct 2018 15:22:55 +0300 +Subject: [PATCH 1/5] Honor PYTHON from configure when running tests + +Pass PYTHON from configure down through all the nutty layers of make +to allow running test-suite with Python 3. In theory that is. + +(cherry picked from commit dcd5ab67c40b543f22b07df8c1028c34b94a7929) +--- + tests/Makefile.am | 1 + + tests/atlocal.in | 3 ++- + tests/local.at | 2 +- + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index eaf817cc2..21ca216a8 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -117,6 +117,7 @@ atlocal: atlocal.in Makefile + -e "s,[@]usrlibdir[@],$(libdir)," \ + -e "s,[@]execprefix[@],$(exec_prefix)," \ + -e "s,[@]RPMCONFIGDIR[@],$(rpmconfigdir)," \ ++ -e "s,[@]PYTHON[@],$(PYTHON)," \ + < $(srcdir)/atlocal.in > atlocal + DISTCLEANFILES = atlocal + EXTRA_DIST += atlocal.in +diff --git a/tests/atlocal.in b/tests/atlocal.in +index d7d837f45..3b1474b56 100644 +--- rpm-4.14.3/tests/atlocal.in.orig 2020-04-28 14:19:26.866602968 +0200 ++++ rpm-4.14.3/tests/atlocal.in 2020-04-28 14:21:07.977910054 +0200 +@@ -3,7 +3,8 @@ + PATH="${abs_builddir}/testing@rpmbindir@:${abs_builddir}/testing@usrbindir@:$PATH" + export PATH + +-PYLIBDIR=`python2 -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))"` ++PYTHON=@PYTHON@ ++PYLIBDIR=$(${PYTHON} -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))") + PYTHONPATH="${abs_builddir}/testing${PYLIBDIR}" + export PYTHONPATH + +--- rpm-4.14.3/tests/local.at.orig 2020-04-28 14:28:33.106664317 +0200 ++++ rpm-4.14.3/tests/local.at 2020-04-28 14:29:02.064038653 +0200 +@@ -18,7 +18,7 @@ + sys.stdout.write('%s\n' % msg) + $1 + EOF +-python2 test.py ++${PYTHON} test.py test.py + ]]) + + m4_define([RPMPY_CHECK],[ diff --git a/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch b/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch new file mode 100644 index 0000000..35f12c2 --- /dev/null +++ b/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch @@ -0,0 +1,656 @@ +From 84920f898315d09a57a3f1067433eaeb7de5e830 Mon Sep 17 00:00:00 2001 +Message-Id: <84920f898315d09a57a3f1067433eaeb7de5e830.1554884444.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Fri, 22 Feb 2019 19:44:16 +0200 +Subject: [PATCH] In Python 3, return all our string data as surrogate-escaped + utf-8 strings + +In the almost ten years of rpm sort of supporting Python 3 bindings, quite +obviously nobody has actually tried to use them. There's a major mismatch +between what the header API outputs (bytes) and what all the other APIs +accept (strings), resulting in hysterical TypeErrors all over the place, +including but not limited to labelCompare() (RhBug:1631292). Also a huge +number of other places have been returning strings and silently assuming +utf-8 through use of Py_BuildValue("s", ...), which will just irrevocably +fail when non-utf8 data is encountered. + +The politically Python 3-correct solution would be declaring all our data +as bytes with unspecified encoding - that's exactly what it historically is. +However doing so would by definition break every single rpm script people +have developed on Python 2. And when 99% of the rpm content in the world +actually is utf-8 encoded even if it doesn't say so (and in recent times +packages even advertise themselves as utf-8 encoded), the bytes-only route +seems a wee bit too draconian, even to this grumpy old fella. + +Instead, route all our string returns through a single helper macro +which on Python 2 just does what we always did, but in Python 3 converts +the data to surrogate-escaped utf-8 strings. This makes stuff "just work" +out of the box pretty much everywhere even with Python 3 (including +our own test-suite!), while still allowing to handle the non-utf8 case. +Handling the non-utf8 case is a bit more uglier but still possible, +which is exactly how you want corner-cases to be. There might be some +uses for retrieving raw byte data from the header, but worrying about +such an API is a case for some other rainy day, for now we mostly only +care that stuff works again. + +Also add test-cases for mixed data source labelCompare() and +non-utf8 insert to + retrieve from header. +--- + python/header-py.c | 2 +- + python/rpmds-py.c | 8 ++++---- + python/rpmfd-py.c | 6 +++--- + python/rpmfi-py.c | 24 ++++++++++++------------ + python/rpmfiles-py.c | 26 +++++++++++++------------- + python/rpmkeyring-py.c | 2 +- + python/rpmmacro-py.c | 2 +- + python/rpmmodule.c | 2 +- + python/rpmps-py.c | 8 ++++---- + python/rpmstrpool-py.c | 2 +- + python/rpmsystem-py.h | 7 +++++++ + python/rpmtd-py.c | 2 +- + python/rpmte-py.c | 16 ++++++++-------- + python/rpmts-py.c | 11 ++++++----- + python/spec-py.c | 8 ++++---- + tests/local.at | 1 + + tests/rpmpython.at | 34 ++++++++++++++++++++++++++++++++++ + 17 files changed, 102 insertions(+), 59 deletions(-) + +diff --git a/python/header-py.c b/python/header-py.c +index c9d54e869..93c241cb7 100644 +--- a/python/header-py.c ++++ b/python/header-py.c +@@ -231,7 +231,7 @@ static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds) + return NULL; + } + +- result = Py_BuildValue("s", r); ++ result = utf8FromString(r); + free(r); + + return result; +diff --git a/python/rpmds-py.c b/python/rpmds-py.c +index 39b26628e..ecc9af9d5 100644 +--- a/python/rpmds-py.c ++++ b/python/rpmds-py.c +@@ -31,19 +31,19 @@ rpmds_Ix(rpmdsObject * s) + static PyObject * + rpmds_DNEVR(rpmdsObject * s) + { +- return Py_BuildValue("s", rpmdsDNEVR(s->ds)); ++ return utf8FromString(rpmdsDNEVR(s->ds)); + } + + static PyObject * + rpmds_N(rpmdsObject * s) + { +- return Py_BuildValue("s", rpmdsN(s->ds)); ++ return utf8FromString(rpmdsN(s->ds)); + } + + static PyObject * + rpmds_EVR(rpmdsObject * s) + { +- return Py_BuildValue("s", rpmdsEVR(s->ds)); ++ return utf8FromString(rpmdsEVR(s->ds)); + } + + static PyObject * +@@ -261,7 +261,7 @@ rpmds_subscript(rpmdsObject * s, PyObject * key) + + ix = (int) PyInt_AsLong(key); + rpmdsSetIx(s->ds, ix); +- return Py_BuildValue("s", rpmdsDNEVR(s->ds)); ++ return utf8FromString(rpmdsDNEVR(s->ds)); + } + + static PyMappingMethods rpmds_as_mapping = { +diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c +index 85fb0cd24..4b05cce5f 100644 +--- a/python/rpmfd-py.c ++++ b/python/rpmfd-py.c +@@ -327,17 +327,17 @@ static PyObject *rpmfd_get_closed(rpmfdObject *s) + static PyObject *rpmfd_get_name(rpmfdObject *s) + { + /* XXX: rpm returns non-paths with [mumble], python files use */ +- return Py_BuildValue("s", Fdescr(s->fd)); ++ return utf8FromString(Fdescr(s->fd)); + } + + static PyObject *rpmfd_get_mode(rpmfdObject *s) + { +- return Py_BuildValue("s", s->mode); ++ return utf8FromString(s->mode); + } + + static PyObject *rpmfd_get_flags(rpmfdObject *s) + { +- return Py_BuildValue("s", s->flags); ++ return utf8FromString(s->flags); + } + + static PyGetSetDef rpmfd_getseters[] = { +diff --git a/python/rpmfi-py.c b/python/rpmfi-py.c +index 8d2f926d0..db405c231 100644 +--- a/python/rpmfi-py.c ++++ b/python/rpmfi-py.c +@@ -41,19 +41,19 @@ rpmfi_DX(rpmfiObject * s, PyObject * unused) + static PyObject * + rpmfi_BN(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiBN(s->fi)); ++ return utf8FromString(rpmfiBN(s->fi)); + } + + static PyObject * + rpmfi_DN(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiDN(s->fi)); ++ return utf8FromString(rpmfiDN(s->fi)); + } + + static PyObject * + rpmfi_FN(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiFN(s->fi)); ++ return utf8FromString(rpmfiFN(s->fi)); + } + + static PyObject * +@@ -98,7 +98,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused) + { + char *digest = rpmfiFDigestHex(s->fi, NULL); + if (digest) { +- PyObject *dig = Py_BuildValue("s", digest); ++ PyObject *dig = utf8FromString(digest); + free(digest); + return dig; + } else { +@@ -109,7 +109,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused) + static PyObject * + rpmfi_FLink(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiFLink(s->fi)); ++ return utf8FromString(rpmfiFLink(s->fi)); + } + + static PyObject * +@@ -133,13 +133,13 @@ rpmfi_FMtime(rpmfiObject * s, PyObject * unused) + static PyObject * + rpmfi_FUser(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiFUser(s->fi)); ++ return utf8FromString(rpmfiFUser(s->fi)); + } + + static PyObject * + rpmfi_FGroup(rpmfiObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmfiFGroup(s->fi)); ++ return utf8FromString(rpmfiFGroup(s->fi)); + } + + static PyObject * +@@ -155,7 +155,7 @@ rpmfi_FClass(rpmfiObject * s, PyObject * unused) + + if ((FClass = rpmfiFClass(s->fi)) == NULL) + FClass = ""; +- return Py_BuildValue("s", FClass); ++ return utf8FromString(FClass); + } + + static PyObject * +@@ -208,7 +208,7 @@ rpmfi_iternext(rpmfiObject * s) + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, 0, Py_None); + } else +- PyTuple_SET_ITEM(result, 0, Py_BuildValue("s", FN)); ++ PyTuple_SET_ITEM(result, 0, utf8FromString(FN)); + PyTuple_SET_ITEM(result, 1, PyLong_FromLongLong(FSize)); + PyTuple_SET_ITEM(result, 2, PyInt_FromLong(FMode)); + PyTuple_SET_ITEM(result, 3, PyInt_FromLong(FMtime)); +@@ -222,12 +222,12 @@ rpmfi_iternext(rpmfiObject * s) + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, 10, Py_None); + } else +- PyTuple_SET_ITEM(result, 10, Py_BuildValue("s", FUser)); ++ PyTuple_SET_ITEM(result, 10, utf8FromString(FUser)); + if (FGroup == NULL) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, 11, Py_None); + } else +- PyTuple_SET_ITEM(result, 11, Py_BuildValue("s", FGroup)); ++ PyTuple_SET_ITEM(result, 11, utf8FromString(FGroup)); + PyTuple_SET_ITEM(result, 12, rpmfi_Digest(s, NULL)); + + } else +@@ -313,7 +313,7 @@ rpmfi_subscript(rpmfiObject * s, PyObject * key) + + ix = (int) PyInt_AsLong(key); + rpmfiSetFX(s->fi, ix); +- return Py_BuildValue("s", rpmfiFN(s->fi)); ++ return utf8FromString(rpmfiFN(s->fi)); + } + + static PyMappingMethods rpmfi_as_mapping = { +diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c +index bc07dbeaf..557246cae 100644 +--- a/python/rpmfiles-py.c ++++ b/python/rpmfiles-py.c +@@ -41,37 +41,37 @@ static PyObject *rpmfile_dx(rpmfileObject *s) + static PyObject *rpmfile_name(rpmfileObject *s) + { + char * fn = rpmfilesFN(s->files, s->ix); +- PyObject *o = Py_BuildValue("s", fn); ++ PyObject *o = utf8FromString(fn); + free(fn); + return o; + } + + static PyObject *rpmfile_basename(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesBN(s->files, s->ix)); ++ return utf8FromString(rpmfilesBN(s->files, s->ix)); + } + + static PyObject *rpmfile_dirname(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); ++ return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); + } + + static PyObject *rpmfile_orig_name(rpmfileObject *s) + { + char * fn = rpmfilesOFN(s->files, s->ix); +- PyObject *o = Py_BuildValue("s", fn); ++ PyObject *o = utf8FromString(fn); + free(fn); + return o; + } + + static PyObject *rpmfile_orig_basename(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesOBN(s->files, s->ix)); ++ return utf8FromString(rpmfilesOBN(s->files, s->ix)); + } + + static PyObject *rpmfile_orig_dirname(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); ++ return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); + } + static PyObject *rpmfile_mode(rpmfileObject *s) + { +@@ -105,17 +105,17 @@ static PyObject *rpmfile_nlink(rpmfileObject *s) + + static PyObject *rpmfile_linkto(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFLink(s->files, s->ix)); ++ return utf8FromString(rpmfilesFLink(s->files, s->ix)); + } + + static PyObject *rpmfile_user(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFUser(s->files, s->ix)); ++ return utf8FromString(rpmfilesFUser(s->files, s->ix)); + } + + static PyObject *rpmfile_group(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFGroup(s->files, s->ix)); ++ return utf8FromString(rpmfilesFGroup(s->files, s->ix)); + } + + static PyObject *rpmfile_fflags(rpmfileObject *s) +@@ -145,7 +145,7 @@ static PyObject *rpmfile_digest(rpmfileObject *s) + NULL, &diglen); + if (digest) { + char * hex = pgpHexStr(digest, diglen); +- PyObject *o = Py_BuildValue("s", hex); ++ PyObject *o = utf8FromString(hex); + free(hex); + return o; + } +@@ -154,17 +154,17 @@ static PyObject *rpmfile_digest(rpmfileObject *s) + + static PyObject *rpmfile_class(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFClass(s->files, s->ix)); ++ return utf8FromString(rpmfilesFClass(s->files, s->ix)); + } + + static PyObject *rpmfile_caps(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFCaps(s->files, s->ix)); ++ return utf8FromString(rpmfilesFCaps(s->files, s->ix)); + } + + static PyObject *rpmfile_langs(rpmfileObject *s) + { +- return Py_BuildValue("s", rpmfilesFLangs(s->files, s->ix)); ++ return utf8FromString(rpmfilesFLangs(s->files, s->ix)); + } + + static PyObject *rpmfile_links(rpmfileObject *s) +diff --git a/python/rpmkeyring-py.c b/python/rpmkeyring-py.c +index d5f131e42..8968e0513 100644 +--- a/python/rpmkeyring-py.c ++++ b/python/rpmkeyring-py.c +@@ -38,7 +38,7 @@ static PyObject *rpmPubkey_new(PyTypeObject *subtype, + static PyObject * rpmPubkey_Base64(rpmPubkeyObject *s) + { + char *b64 = rpmPubkeyBase64(s->pubkey); +- PyObject *res = Py_BuildValue("s", b64); ++ PyObject *res = utf8FromString(b64); + free(b64); + return res; + } +diff --git a/python/rpmmacro-py.c b/python/rpmmacro-py.c +index 3cb1a51f5..d8a365547 100644 +--- a/python/rpmmacro-py.c ++++ b/python/rpmmacro-py.c +@@ -52,7 +52,7 @@ rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds) + if (rpmExpandMacros(NULL, macro, &str, 0) < 0) + PyErr_SetString(pyrpmError, "error expanding macro"); + else +- res = Py_BuildValue("s", str); ++ res = utf8FromString(str); + free(str); + } + return res; +diff --git a/python/rpmmodule.c b/python/rpmmodule.c +index 3faad23c7..05032edc7 100644 +--- a/python/rpmmodule.c ++++ b/python/rpmmodule.c +@@ -237,7 +237,7 @@ static void addRpmTags(PyObject *module) + + PyModule_AddIntConstant(module, tagname, tagval); + pyval = PyInt_FromLong(tagval); +- pyname = Py_BuildValue("s", shortname); ++ pyname = utf8FromString(shortname); + PyDict_SetItem(dict, pyval, pyname); + Py_DECREF(pyval); + Py_DECREF(pyname); +diff --git a/python/rpmps-py.c b/python/rpmps-py.c +index bdc899a60..902b2ae63 100644 +--- a/python/rpmps-py.c ++++ b/python/rpmps-py.c +@@ -18,12 +18,12 @@ static PyObject *rpmprob_get_type(rpmProblemObject *s, void *closure) + + static PyObject *rpmprob_get_pkgnevr(rpmProblemObject *s, void *closure) + { +- return Py_BuildValue("s", rpmProblemGetPkgNEVR(s->prob)); ++ return utf8FromString(rpmProblemGetPkgNEVR(s->prob)); + } + + static PyObject *rpmprob_get_altnevr(rpmProblemObject *s, void *closure) + { +- return Py_BuildValue("s", rpmProblemGetAltNEVR(s->prob)); ++ return utf8FromString(rpmProblemGetAltNEVR(s->prob)); + } + + static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure) +@@ -38,7 +38,7 @@ static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure) + + static PyObject *rpmprob_get_str(rpmProblemObject *s, void *closure) + { +- return Py_BuildValue("s", rpmProblemGetStr(s->prob)); ++ return utf8FromString(rpmProblemGetStr(s->prob)); + } + + static PyObject *rpmprob_get_num(rpmProblemObject *s, void *closure) +@@ -59,7 +59,7 @@ static PyGetSetDef rpmprob_getseters[] = { + static PyObject *rpmprob_str(rpmProblemObject *s) + { + char *str = rpmProblemString(s->prob); +- PyObject *res = Py_BuildValue("s", str); ++ PyObject *res = utf8FromString(str); + free(str); + return res; + } +diff --git a/python/rpmstrpool-py.c b/python/rpmstrpool-py.c +index 356bd1de5..a56e2b540 100644 +--- a/python/rpmstrpool-py.c ++++ b/python/rpmstrpool-py.c +@@ -44,7 +44,7 @@ static PyObject *strpool_id2str(rpmstrPoolObject *s, PyObject *item) + const char *str = rpmstrPoolStr(s->pool, id); + + if (str) +- ret = PyBytes_FromString(str); ++ ret = utf8FromString(str); + else + PyErr_SetObject(PyExc_KeyError, item); + } +diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h +index 955d60cd3..87c750571 100644 +--- a/python/rpmsystem-py.h ++++ b/python/rpmsystem-py.h +@@ -19,4 +19,11 @@ + #define PyInt_AsSsize_t PyLong_AsSsize_t + #endif + ++/* In Python 3, we return all strings as surrogate-escaped utf-8 */ ++#if PY_MAJOR_VERSION >= 3 ++#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape") ++#else ++#define utf8FromString(_s) PyBytes_FromString(_s) ++#endif ++ + #endif /* H_SYSTEM_PYTHON */ +diff --git a/python/rpmtd-py.c b/python/rpmtd-py.c +index 247c7502a..23ca10517 100644 +--- a/python/rpmtd-py.c ++++ b/python/rpmtd-py.c +@@ -17,7 +17,7 @@ PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass) + + switch (tclass) { + case RPM_STRING_CLASS: +- res = PyBytes_FromString(rpmtdGetString(td)); ++ res = utf8FromString(rpmtdGetString(td)); + break; + case RPM_NUMERIC_CLASS: + res = PyLong_FromLongLong(rpmtdGetNumber(td)); +diff --git a/python/rpmte-py.c b/python/rpmte-py.c +index 99ff2f496..2b3745754 100644 +--- a/python/rpmte-py.c ++++ b/python/rpmte-py.c +@@ -54,49 +54,49 @@ rpmte_TEType(rpmteObject * s, PyObject * unused) + static PyObject * + rpmte_N(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteN(s->te)); ++ return utf8FromString(rpmteN(s->te)); + } + + static PyObject * + rpmte_E(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteE(s->te)); ++ return utf8FromString(rpmteE(s->te)); + } + + static PyObject * + rpmte_V(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteV(s->te)); ++ return utf8FromString(rpmteV(s->te)); + } + + static PyObject * + rpmte_R(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteR(s->te)); ++ return utf8FromString(rpmteR(s->te)); + } + + static PyObject * + rpmte_A(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteA(s->te)); ++ return utf8FromString(rpmteA(s->te)); + } + + static PyObject * + rpmte_O(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteO(s->te)); ++ return utf8FromString(rpmteO(s->te)); + } + + static PyObject * + rpmte_NEVR(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteNEVR(s->te)); ++ return utf8FromString(rpmteNEVR(s->te)); + } + + static PyObject * + rpmte_NEVRA(rpmteObject * s, PyObject * unused) + { +- return Py_BuildValue("s", rpmteNEVRA(s->te)); ++ return utf8FromString(rpmteNEVRA(s->te)); + } + + static PyObject * +diff --git a/python/rpmts-py.c b/python/rpmts-py.c +index 1ddfc9a1e..96e3bb28e 100644 +--- a/python/rpmts-py.c ++++ b/python/rpmts-py.c +@@ -230,8 +230,9 @@ rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data) + + PyEval_RestoreThread(cbInfo->_save); + +- args = Py_BuildValue("(Oissi)", cbInfo->tso, +- rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds)); ++ args = Py_BuildValue("(OiNNi)", cbInfo->tso, ++ rpmdsTagN(ds), utf8FromString(rpmdsN(ds)), ++ utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds)); + result = PyEval_CallObject(cbInfo->cb, args); + Py_DECREF(args); + +@@ -409,7 +410,7 @@ rpmts_HdrCheck(rpmtsObject * s, PyObject *obj) + rpmrc = headerCheck(s->ts, uh, uc, &msg); + Py_END_ALLOW_THREADS; + +- return Py_BuildValue("(is)", rpmrc, msg); ++ return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg)); + } + + static PyObject * +@@ -500,7 +501,7 @@ rpmtsCallback(const void * hd, const rpmCallbackType what, + /* Synthesize a python object for callback (if necessary). */ + if (pkgObj == NULL) { + if (h) { +- pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME)); ++ pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME)); + } else { + pkgObj = Py_None; + Py_INCREF(pkgObj); +@@ -845,7 +846,7 @@ static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure) + + static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure) + { +- return Py_BuildValue("s", rpmtsRootDir(s->ts)); ++ return utf8FromString(rpmtsRootDir(s->ts)); + } + + static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure) +diff --git a/python/spec-py.c b/python/spec-py.c +index 4efdbf4bf..70b796531 100644 +--- a/python/spec-py.c ++++ b/python/spec-py.c +@@ -57,7 +57,7 @@ static PyObject *pkgGetSection(rpmSpecPkg pkg, int section) + { + char *sect = rpmSpecPkgGetSection(pkg, section); + if (sect != NULL) { +- PyObject *ps = PyBytes_FromString(sect); ++ PyObject *ps = utf8FromString(sect); + free(sect); + if (ps != NULL) + return ps; +@@ -158,7 +158,7 @@ static PyObject * getSection(rpmSpec spec, int section) + { + const char *sect = rpmSpecGetSection(spec, section); + if (sect) { +- return Py_BuildValue("s", sect); ++ return utf8FromString(sect); + } + Py_RETURN_NONE; + } +@@ -208,8 +208,8 @@ static PyObject * spec_get_sources(specObject *s, void *closure) + + rpmSpecSrcIter iter = rpmSpecSrcIterInit(s->spec); + while ((source = rpmSpecSrcIterNext(iter)) != NULL) { +- PyObject *srcUrl = Py_BuildValue("(sii)", +- rpmSpecSrcFilename(source, 1), ++ PyObject *srcUrl = Py_BuildValue("(Nii)", ++ utf8FromString(rpmSpecSrcFilename(source, 1)), + rpmSpecSrcNum(source), + rpmSpecSrcFlags(source)); + if (!srcUrl) { +diff --git a/tests/local.at b/tests/local.at +index 02ead66c9..42eef1c75 100644 +--- a/tests/local.at ++++ b/tests/local.at +@@ -10,6 +10,7 @@ rm -rf "${abs_builddir}"/testing`rpm --eval '%_dbpath'`/* + + m4_define([RPMPY_RUN],[[ + cat << EOF > test.py ++# coding=utf-8 + import rpm, sys + dbpath=rpm.expandMacro('%_dbpath') + rpm.addMacro('_dbpath', '${abs_builddir}/testing%s' % dbpath) +diff --git a/tests/rpmpython.at b/tests/rpmpython.at +index ff77f868c..58f3e84a6 100644 +--- a/tests/rpmpython.at ++++ b/tests/rpmpython.at +@@ -106,6 +106,25 @@ None + 'rpm.hdr' object has no attribute '__foo__'] + ) + ++RPMPY_TEST([non-utf8 data in header],[ ++str = u'älämölö' ++enc = 'iso-8859-1' ++b = str.encode(enc) ++h = rpm.hdr() ++h['group'] = b ++d = h['group'] ++try: ++ # python 3 ++ t = bytes(d, 'utf-8', 'surrogateescape') ++except TypeError: ++ # python 2 ++ t = bytes(d) ++res = t.decode(enc) ++myprint(str == res) ++], ++[True] ++) ++ + RPMPY_TEST([invalid header data],[ + h1 = rpm.hdr() + h1['basenames'] = ['bing', 'bang', 'bong'] +@@ -125,6 +144,21 @@ for h in [h1, h2]: + /opt/bing,/opt/bang,/flopt/bong] + ) + ++RPMPY_TEST([labelCompare],[ ++v = '1.0' ++r = '1' ++e = 3 ++h = rpm.hdr() ++h['name'] = 'testpkg' ++h['version'] = v ++h['release'] = r ++h['epoch'] = e ++myprint(rpm.labelCompare((str(h['epoch']), h['version'], h['release']), ++ (str(e), v, r))) ++], ++[0] ++) ++ + RPMPY_TEST([vfyflags API],[ + ts = rpm.ts() + dlv = ts.getVfyFlags() +-- +2.20.1 + diff --git a/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch b/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch new file mode 100644 index 0000000..ccf39e3 --- /dev/null +++ b/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch @@ -0,0 +1,63 @@ +From 9ad4b813483f8cf6c641f56387248b33b6dfc570 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 20 Feb 2019 15:28:30 +0200 +Subject: [PATCH] Introduce patch_nums and source_nums Lua variables in spec + context + +The pre-existing patches and sources variables only contains patch and +source filenames, but for some purposes we need access to the associated +patch/source number too. We could use the number as the table key, but +that would make the table unsorted. That we could handle in our own +macros, but would break compatibility for anybody doing custom stuff +with these. So it seems best to just add parallel arrays sharing the +same array indexes so that both values are as easily accessible, +depending on the need. + +Inspired by Pascal "Pixel" Rigaux's similar patch in Mageia, which differs +in that the number-arrays are indexed by the filename and is unordered. +Compared to patches/sources this seemed against principle of least +surprise, and is slightly more cumbersome int the case we want the number +directly, such as in PR #626. The variable names differ so there +is no incompatibility to that downstream patch introduced. +--- + build/parsePreamble.c | 9 +++++++++ + build/spec.c | 3 ++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/build/parsePreamble.c b/build/parsePreamble.c +index 812c41f9f..9520bac4b 100644 +--- a/build/parsePreamble.c ++++ b/build/parsePreamble.c +@@ -322,6 +322,15 @@ static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag + rpmluaSetVar(lua, var); + rpmluavFree(var); + rpmluaPop(lua); ++ ++ what = (flag & RPMBUILD_ISPATCH) ? "patch_nums" : "source_nums"; ++ rpmluaPushTable(lua, what); ++ var = rpmluavNew(); ++ rpmluavSetListMode(var, 1); ++ rpmluavSetValueNum(var, p->num); ++ rpmluaSetVar(lua, var); ++ rpmluavFree(var); ++ rpmluaPop(lua); + } + #endif + free(body); +diff --git a/build/spec.c b/build/spec.c +index 80eaca611..55095c6ce 100644 +--- a/build/spec.c ++++ b/build/spec.c +@@ -305,7 +305,8 @@ rpmSpec newSpec(void) + #ifdef WITH_LUA + /* make sure patches and sources tables always exist */ + rpmlua lua = NULL; /* global state */ +- const char * luavars[] = { "patches", "sources", NULL, }; ++ const char * luavars[] = { "patches", "sources", ++ "patch_nums", "source_nums", NULL, }; + for (const char **vp = luavars; vp && *vp; vp++) { + rpmluaDelVar(lua, *vp); + rpmluaPushTable(lua, *vp); +-- +2.26.2 + diff --git a/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch b/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch new file mode 100644 index 0000000..a95ea7c --- /dev/null +++ b/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch @@ -0,0 +1,41 @@ +From e811c7ec0b4d2685b63b61803e3952466b1a4ac6 Mon Sep 17 00:00:00 2001 +Message-Id: +From: marxin +Date: Wed, 28 Nov 2018 10:52:01 +0100 +Subject: [PATCH] Isolate %_smp_build_ncpus and use it for %_smp_mflags. + +Refactor _smp_build_ncpus and use it in %_smp_mflags. Note that now +having a single CPU, %_smp_mflags is expanded to '-j1'. + +XXX: hand-edited to remove double quotes as per upstream commit + 9b6fdc65ef0507fff04a69c88e085a7a26711839 which isn't applicable + directly due to other changes + +--- + platform.in | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/platform.in b/platform.in +index 3eb67b55b..2dd951f87 100644 +--- a/platform.in ++++ b/platform.in +@@ -50,11 +50,14 @@ + + # Maximum number of CPU's to use when building, 0 for unlimited. + #%_smp_ncpus_max 0 +-%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\ ++ ++%_smp_build_ncpus %([ -z "$RPM_BUILD_NCPUS" ] \\\ + && RPM_BUILD_NCPUS="`/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\ + ncpus_max=%{?_smp_ncpus_max}; \\\ + if [ -n "$ncpus_max" ] && [ "$ncpus_max" -gt 0 ] && [ "$RPM_BUILD_NCPUS" -gt "$ncpus_max" ]; then RPM_BUILD_NCPUS="$ncpus_max"; fi; \\\ +- if [ "$RPM_BUILD_NCPUS" -gt 1 ]; then echo "-j$RPM_BUILD_NCPUS"; fi) ++ echo "$RPM_BUILD_NCPUS";) ++ ++%_smp_mflags -j%{_smp_build_ncpus} + + #============================================================================== + # ---- Build policy macros. +-- +2.23.0 + diff --git a/0001-Make-check-buildroot-check-the-build-files-in-parall.patch b/0001-Make-check-buildroot-check-the-build-files-in-parall.patch new file mode 100644 index 0000000..bba479b --- /dev/null +++ b/0001-Make-check-buildroot-check-the-build-files-in-parall.patch @@ -0,0 +1,31 @@ +From f23af97c4135013d3134a17c881014fb6e9589c8 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 30 Apr 2019 17:12:35 +0200 +Subject: [PATCH] Make check-buildroot check the build files in parallel + +Thanks to Denys Vlasenko for pointing this out in rhbz#1704353 +--- + scripts/check-buildroot | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/scripts/check-buildroot b/scripts/check-buildroot +index 0cfb34f39..f91dc767b 100755 +--- a/scripts/check-buildroot ++++ b/scripts/check-buildroot +@@ -24,11 +24,12 @@ fi + + tmp=$(mktemp ${TMPDIR:-/tmp}/cbr.XXXXXX) + trap "rm -f $tmp" EXIT ++NCPUS=${RPM_BUILD_NCPUS:-1} + + find "$RPM_BUILD_ROOT" \! \( \ + -name '*.pyo' -o -name '*.pyc' -o -name '*.elc' -o -name '.packlist' \ + \) -type f -print0 | \ +- LANG=C xargs -0r grep -F "$RPM_BUILD_ROOT" >$tmp ++ LANG=C xargs -0r -P$NCPUS -n16 grep -F "$RPM_BUILD_ROOT" >>$tmp + + test -s "$tmp" && { + cat "$tmp" +-- +2.21.0 + diff --git a/0001-Mark-elements-with-associated-problems-as-failed.patch b/0001-Mark-elements-with-associated-problems-as-failed.patch new file mode 100644 index 0000000..320385d --- /dev/null +++ b/0001-Mark-elements-with-associated-problems-as-failed.patch @@ -0,0 +1,28 @@ +From 57b4f21634429ccd29d47cf93ec0841f70b68404 Mon Sep 17 00:00:00 2001 +Message-Id: <57b4f21634429ccd29d47cf93ec0841f70b68404.1545311826.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Tue, 18 Sep 2018 11:02:36 +0300 +Subject: [PATCH] Mark elements with associated problems as failed + +An element with a problem can not possibly succeed so mark these failures +early. Doesn't make much of a difference as problems will prevent the +transaction from starting in the first place but it makes sense anyway. +--- + lib/rpmte.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rpmte.c b/lib/rpmte.c +index 4bdeeaf68..c5d614f67 100644 +--- a/lib/rpmte.c ++++ b/lib/rpmte.c +@@ -703,6 +703,7 @@ static void appendProblem(rpmte te, rpmProblemType type, + if (te->probs == NULL) + te->probs = rpmpsCreate(); + rpmpsAppendProblem(te->probs, p); ++ rpmteMarkFailed(te); + } + rpmProblemFree(p); + } +-- +2.19.2 + diff --git a/0001-Only-read-through-payload-on-verify-if-actually-need.patch b/0001-Only-read-through-payload-on-verify-if-actually-need.patch new file mode 100644 index 0000000..f77c039 --- /dev/null +++ b/0001-Only-read-through-payload-on-verify-if-actually-need.patch @@ -0,0 +1,76 @@ +From 362c4401979f896de1e69a3e18d33954953912cc Mon Sep 17 00:00:00 2001 +Message-Id: <362c4401979f896de1e69a3e18d33954953912cc.1554983588.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Tue, 11 Dec 2018 13:21:47 +0200 +Subject: [PATCH] Only read through payload on verify if actually needed + +If none of our verify items ranges over the payload, then why bother? + +To do this, add an internal rpmvs API to get it's range, and use +that to decide whether trip over the payload is needed or not. +In addition, the payload digest tag needs to be grabbed outside of the +condition to avoid depending on other values. The details including +RPMVSF_NEEDPAYLOAD will be handled internally to rpmvs which makes it +actually nicer code-wise too. +--- + lib/rpmchecksig.c | 8 ++++---- + lib/rpmvs.c | 12 ++++++++++++ + lib/rpmvs.h | 3 +++ + 3 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c +index 1ba72a45e..810f7153d 100644 +--- a/lib/rpmchecksig.c ++++ b/lib/rpmchecksig.c +@@ -187,11 +187,11 @@ rpmRC rpmpkgRead(struct rpmvs_s *vs, FD_t fd, + /* Finalize header range */ + rpmvsFiniRange(vs, RPMSIG_HEADER); + +- /* Unless disabled, read the payload, generating digest(s) on the fly. */ +- if (!(rpmvsFlags(vs) & RPMVSF_NEEDPAYLOAD)) { +- /* Fish interesting tags from the main header. This is a bit hacky... */ +- rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST); ++ /* Fish interesting tags from the main header. This is a bit hacky... */ ++ rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST); + ++ /* If needed and not explicitly disabled, read the payload as well. */ ++ if (rpmvsRange(vs) & RPMSIG_PAYLOAD) { + /* Initialize digests ranging over the payload only */ + rpmvsInitRange(vs, RPMSIG_PAYLOAD); + +diff --git a/lib/rpmvs.c b/lib/rpmvs.c +index 622e48011..0d475af86 100644 +--- a/lib/rpmvs.c ++++ b/lib/rpmvs.c +@@ -396,6 +396,18 @@ void rpmvsFiniRange(struct rpmvs_s *sis, int range) + } + } + ++int rpmvsRange(struct rpmvs_s *vs) ++{ ++ int range = 0; ++ for (int i = 0; i < vs->nsigs; i++) { ++ if (rpmsinfoDisabled(&vs->sigs[i], vs->vsflags)) ++ continue; ++ range |= vs->sigs[i].range; ++ } ++ ++ return range; ++} ++ + static int sinfoCmp(const void *a, const void *b) + { + const struct rpmsinfo_s *sa = a; +--- rpm-4.14.3/lib/rpmvs.h.orig 2020-04-28 10:57:19.727347211 +0200 ++++ rpm-4.14.3/lib/rpmvs.h 2020-04-28 10:57:43.622612015 +0200 +@@ -66,6 +66,8 @@ + + void rpmvsFiniRange(struct rpmvs_s *sis, int range); + ++int rpmvsRange(struct rpmvs_s *vs); ++ + int rpmvsVerify(struct rpmvs_s *sis, int type, + rpmsinfoCb cb, void *cbdata); + +-- +2.20.1 diff --git a/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch b/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch new file mode 100644 index 0000000..0e28f75 --- /dev/null +++ b/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch @@ -0,0 +1,27 @@ +From d97d7b71de158660eb96b4f11d40b6626b85521a Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 16 Apr 2019 09:50:57 +0200 +Subject: [PATCH] Pass RPM_BUILD_NCPUS to build scripts + +Use %_smp_build_ncpus instead of the initial value +--- + macros.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/macros.in b/macros.in +index fc587997d..a15e46f26 100644 +--- a/macros.in ++++ b/macros.in +@@ -807,7 +807,8 @@ package or when debugging this package.\ + RPM_OPT_FLAGS=\"%{optflags}\"\ + RPM_ARCH=\"%{_arch}\"\ + RPM_OS=\"%{_os}\"\ +- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\ ++ RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\ ++ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ + RPM_DOC_DIR=\"%{_docdir}\"\ + export RPM_DOC_DIR\ + RPM_PACKAGE_NAME=\"%{NAME}\"\ +-- +2.21.0 + diff --git a/0001-RPM-with-Copy-on-Write.patch b/0001-RPM-with-Copy-on-Write.patch new file mode 100644 index 0000000..4f4e8ba --- /dev/null +++ b/0001-RPM-with-Copy-on-Write.patch @@ -0,0 +1,1344 @@ +From 7bd31ce85b2ed377f495c31fcea2422a07739e24 Mon Sep 17 00:00:00 2001 +From: Matthew Almond +Date: Fri, 8 Nov 2019 09:29:43 -0800 +Subject: [PATCH 01/30] RPM with Copy on Write + +This is part of https://fedoraproject.org/wiki/Changes/RPMCoW + +The majority of changes are in two new programs: + += rpm2extents + +Modeled as a 'stream processor'. It reads a regular .rpm file on stdin, +and produces a modified .rpm file on stdout. The lead, signature and +headers are preserved 1:1 to allow all the normal metadata inspection, +signature verification to work as expected. Only the 'payload' is +modified. + +The primary motivation for this tool is to re-organize the payload as a +sequence of raw file extents (hence the name). The files are organized +by their digest identity instead of path/filename. If any digest is +repeated, then the file is skipped/de-duped. Only regular files are +represented. All other entries like directories, symlinks, devices are +fully described in the headers and are omitted. + +The files are padded so they start on `sysconf(_SC_PAGESIZE)` boundries +to permit 'reflink' syscalls to work in the `reflink` plugin. + +At the end of the file is a footer with 3 sections: + +1. List of calculated digests of the input stream. This is used in + `librepo` because the file *written* is a derivative, and not the + same as the repo metadata describes. `rpm2extents` takes one or more + positional arguments that described which digest algorithms are + desired. This is often just `SHA256`. This program is only measuring + and recording the digest - it does not express an opinion on whether + the file is correct. Due to the API on most compression libraries + directly reading the source file, the whole file digest is measured + using a subprocess and pipes. I don't love it, but it works. +2. Sorted List of file content digests + offset pairs. This is used in + the plugin with a trivial binary search to locate the start of file + content. The size is not needed because it's part of normal headers. +3. (offset of 1., offset of 2., 8 byte MAGIC value) triple + += reflink plugin + +Looks for the 8 byte magic value at the end of the rpm file. If present +it alters the `RPMTAG_PAYLOADFORMAT` in memory to `clon`, and reads in +the digest-> offset table. + +`rpmPackageFilesInstall()` in `fsm.c` is +modified to alter the enumeration strategy from +`rpmfiNewArchiveReader()` to `rpmfilesIter()` if not `cpio`. This is +needed because there is no cpio to enumerate. In the same function, if +`rpmpluginsCallFsmFilePre()` returns `RPMRC_PLUGIN_CONTENTS` then +`fsmMkfile()` is skipped as it is assumed the plugin did the work. + +The majority of the work is in `reflink_fsm_file_pre()` - the per file +hook for RPM plugins. If the file enumerated in +`rpmPackageFilesInstall()` is a regular file, this function will look up +the offset in the digest->offset table and will try to reflink it, then +fall back to a regular copy. If reflinking does work: we will have +reflinked a whole number of pages, so we truncate the file to the +expected size. Therefore installing most files does involve two writes: +the reflink of the full size, then a fork/copy on write for the last +page worth. + +If the file passed to `reflink_fsm_file_pre()` is anything other than a +regular file, it return `RPMRC_OK` so the normal mechanics of +`rpmPackageFilesInstall()` are used. That handles directories, symlinks +and other non file types. + += New API for internal use + +1. `rpmReadPackageRaw()` is used within `rpm2extents` to read all the + headers without trying to validate signatures. This eliminates the + runtime dependency on rpmdb. +2. `rpmteFd()` exposes the Fd behind the rpmte, so plugins can interact + with the rpm itself. +3. `RPMRC_PLUGIN_CONTENTS` in `rpmRC_e` for use in + `rpmpluginsCallFsmFilePre()` specifically. +4. `pgpStringVal()` is used to help parse the command line in + `rpm2extents` - the positional arguments are strings, and this + converts the values back to the values in the table. + +Nothing has been removed, and none of the changes are intended to be +used externally, so I don't think a soname bump is warranted here. +--- + Makefile.am | 6 +- + lib/depends.c | 2 + + lib/fsm.c | 45 +++- + lib/package.c | 40 ++++ + lib/rpmlib.h | 9 + + lib/rpmplugins.c | 21 +- + lib/rpmte.c | 5 + + lib/rpmte.h | 2 + + lib/rpmtypes.h | 3 +- + macros.in | 1 + + plugins/Makefile.am | 4 + + plugins/reflink.c | 340 +++++++++++++++++++++++++++++ + rpm2extents.c | 519 ++++++++++++++++++++++++++++++++++++++++++++ + rpmio/rpmpgp.c | 10 + + rpmio/rpmpgp.h | 9 + + 15 files changed, 1004 insertions(+), 12 deletions(-) + create mode 100644 plugins/reflink.c + create mode 100644 rpm2extents.c + +diff --git a/Makefile.am b/Makefile.am +index e5c75d7b4..288668819 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -99,7 +99,7 @@ pkginclude_HEADERS += build/rpmfc.h + pkginclude_HEADERS += build/rpmspec.h + + +-bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec ++bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec rpm2extents + if WITH_ARCHIVE + bin_PROGRAMS += rpm2archive + endif +@@ -154,6 +154,10 @@ rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h + rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la + rpm2cpio_LDADD += @WITH_POPT_LIB@ + ++rpm2extents_SOURCES = rpm2extents.c debug.h system.h ++rpm2extents_LDADD = lib/librpm.la rpmio/librpmio.la ++rpm2extents_LDADD += @WITH_POPT_LIB@ ++ + rpm2archive_SOURCES = rpm2archive.c debug.h system.h + rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la + rpm2archive_LDADD += @WITH_POPT_LIB@ @WITH_ARCHIVE_LIB@ +diff --git a/lib/depends.c b/lib/depends.c +index 30234df3d..8998afcd3 100644 +--- a/lib/depends.c ++++ b/lib/depends.c +@@ -81,6 +81,8 @@ 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 935a0a5c6..90193c749 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #if WITH_CAP + #include + #endif +@@ -19,6 +20,7 @@ + + #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" +@@ -52,6 +54,7 @@ struct filedata_s { + int stage; + int setmeta; + int skip; ++ int plugin_contents; + rpmFileAction action; + const char *suffix; + char *fpath; +@@ -891,6 +894,14 @@ 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); ++ bool cpio = true; ++ ++ if (payloadfmt && rstreq(payloadfmt, "clon")) { ++ cpio = false; ++ } ++ + /* transaction id used for temporary path suffix while installing */ + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); + +@@ -911,12 +922,23 @@ 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 = false; ++ switch (rc) { ++ case RPMRC_OK: ++ setFileState(fs, fx); ++ break; ++ case RPMRC_PLUGIN_CONTENTS: ++ fp->plugin_contents = true; ++ // 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); +@@ -924,10 +946,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (rc) + goto exit; + +- fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); +- if (fi == NULL) { +- rc = RPMERR_BAD_MAGIC; +- 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); + } + + /* Detect and create directories not explicitly in package. */ +@@ -969,8 +995,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + + if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fp, files, psm, nodigest, +- &firstlink, &firstlinkfile); ++ if(fp->plugin_contents) { ++ rc = RPMRC_OK; ++ }else { ++ rc = fsmMkfile(fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile); ++ } + } + } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +@@ -1078,6 +1108,7 @@ 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/lib/package.c b/lib/package.c +index 281275029..90bd0d8a7 100644 +--- a/lib/package.c ++++ b/lib/package.c +@@ -404,5 +404,45 @@ exit: + return rc; + } + ++rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp) ++{ ++ char *msg = NULL; ++ hdrblob sigblob = hdrblobCreate(); ++ hdrblob blob = hdrblobCreate(); ++ 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); ++ if (rc != RPMRC_OK) ++ goto exit; ++ ++ rc = hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, blob, &msg); ++ if (rc != RPMRC_OK) ++ goto exit; ++ ++ rc = hdrblobImport(sigblob, 0, &sigh, &msg); ++ if (rc) ++ goto exit; + ++ rc = hdrblobImport(blob, 0, &h, &msg); ++ if (rc) ++ goto exit; + ++ *sigp = headerLink(sigh); ++ *hdrp = headerLink(h); ++ ++exit: ++ if (rc != RPMRC_OK && msg) ++ rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg); ++ hdrblobFree(sigblob); ++ hdrblobFree(blob); ++ headerFree(sigh); ++ headerFree(h); ++ free(msg); ++ ++ return rc; ++} +diff --git a/lib/rpmlib.h b/lib/rpmlib.h +index 0879d04e5..a09ba0daf 100644 +--- a/lib/rpmlib.h ++++ b/lib/rpmlib.h +@@ -155,6 +155,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg); + rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, + const char * fn, Header * hdrp); + ++/** \ingroup header ++ * Return package signature, header from file handle, no verification. ++ * @param fd file handle ++ * @param[out] sigp address of header (or NULL) ++ * @param[out] hdrp address of header (or NULL) ++ * @return RPMRC_OK on success ++ */ ++rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp); ++ + /** \ingroup rpmtrans + * Install source package. + * @param ts transaction set +diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c +index 62d75c4cf..c5084d398 100644 +--- a/lib/rpmplugins.c ++++ b/lib/rpmplugins.c +@@ -356,13 +356,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, + plugin_fsm_file_pre_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_pre); +- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) { +- rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name); +- rc = RPMRC_FAIL; ++ if (hookFunc) { ++ hook_rc = hookFunc(plugin, fi, path, file_mode, op); ++ if (hook_rc == RPMRC_FAIL) { ++ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre 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; ++ } ++ } + } + } + +diff --git a/lib/rpmte.c b/lib/rpmte.c +index 3663604e7..d43dc41ad 100644 +--- a/lib/rpmte.c ++++ b/lib/rpmte.c +@@ -423,6 +423,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd) + return NULL; + } + ++FD_t rpmteFd(rpmte te) ++{ ++ return (te != NULL ? te->fd : NULL); ++} ++ + fnpyKey rpmteKey(rpmte te) + { + return (te != NULL ? te->key : NULL); +diff --git a/lib/rpmte.h b/lib/rpmte.h +index 81acf7a19..6fc0a9f91 100644 +--- a/lib/rpmte.h ++++ b/lib/rpmte.h +@@ -209,6 +209,8 @@ const char * rpmteNEVR(rpmte te); + */ + const char * rpmteNEVRA(rpmte te); + ++FD_t rpmteFd(rpmte te); ++ + /** \ingroup rpmte + * Retrieve key from transaction element. + * @param te transaction element +diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h +index e8e69b506..af2611e9e 100644 +--- a/lib/rpmtypes.h ++++ b/lib/rpmtypes.h +@@ -106,7 +106,8 @@ typedef enum rpmRC_e { + RPMRC_NOTFOUND = 1, /*!< Generic not found code. */ + RPMRC_FAIL = 2, /*!< Generic failure code. */ + RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */ +- RPMRC_NOKEY = 4 /*!< Public key is unavailable. */ ++ RPMRC_NOKEY = 4, /*!< Public key is unavailable. */ ++ RPMRC_PLUGIN_CONTENTS = 5 /*!< fsm_file_pre plugin is handling content */ + } rpmRC; + + #ifdef __cplusplus +diff --git a/macros.in b/macros.in +index e90cefa9a..363252b0f 100644 +--- a/macros.in ++++ b/macros.in +@@ -1143,6 +1143,7 @@ package or when debugging this package.\ + + # Transaction plugin macros + %__plugindir %{_libdir}/rpm-plugins ++%__transaction_reflink %{__plugindir}/reflink.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 3a929d0ce..ad0d3bce7 100644 +--- a/plugins/Makefile.am ++++ b/plugins/Makefile.am +@@ -42,6 +42,10 @@ prioreset_la_SOURCES = prioreset.c + prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la + plugins_LTLIBRARIES += prioreset.la + ++reflink_la_SOURCES = reflink.c ++reflink_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la ++plugins_LTLIBRARIES += reflink.la ++ + syslog_la_SOURCES = syslog.c + syslog_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la + plugins_LTLIBRARIES += syslog.la +diff --git a/plugins/reflink.c b/plugins/reflink.c +new file mode 100644 +index 000000000..d7f19acd9 +--- /dev/null ++++ b/plugins/reflink.c +@@ -0,0 +1,340 @@ ++#include "system.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(__linux__) ++#include /* For FICLONE */ ++#endif ++ ++#include ++#include "lib/rpmlib.h" ++#include "lib/rpmplugin.h" ++#include "lib/rpmte_internal.h" ++#include ++#include "rpmio/rpmio_internal.h" ++ ++ ++#include "debug.h" ++ ++#include ++ ++/* use hash table to remember inode -> ix (for rpmfilesFN(ix)) lookups */ ++#undef HASHTYPE ++#undef HTKEYTYPE ++#undef HTDATATYPE ++#define HASHTYPE inodeIndexHash ++#define HTKEYTYPE rpm_ino_t ++#define HTDATATYPE int ++#include "lib/rpmhash.H" ++#include "lib/rpmhash.C" ++ ++/* ++We use this in find to indicate a key wasn't found. This is an unrecoverable ++error, but we can at least show a decent error. 0 is never a valid offset ++because it's the offset of the start of the file. ++*/ ++#define NOT_FOUND 0 ++ ++#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; ++ char *buffer; ++ ++ /* stuff that's used/updated per psm */ ++ uint32_t keys, keysize; ++ ++ // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) ++ unsigned char *table; ++ FD_t fd; ++ rpmfiles files; ++ inodeIndexHash inodeIndexes; ++}; ++ ++typedef struct reflink_state_s * reflink_state; ++ ++static int inodeCmp(rpm_ino_t a, rpm_ino_t b) ++{ ++ return (a != b); ++} ++ ++static unsigned int inodeId(rpm_ino_t a) ++{ ++ /* rpm_ino_t is uint32_t so maps safely to unsigned int */ ++ return (unsigned int)a; ++} ++ ++static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { ++ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); ++ ++ /* ++ IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and ++ length arguments to be aligned to the fundamental block size. ++ ++ The value of "fundamental block size" is directly related to the system's ++ page size, so we should use that. ++ */ ++ state->fundamental_block_size = sysconf(_SC_PAGESIZE); ++ state->buffer = rcalloc(1, BUFFER_SIZE); ++ rpmPluginSetData(plugin, state); ++ ++ return RPMRC_OK; ++} ++ ++static void reflink_cleanup(rpmPlugin plugin) { ++ reflink_state state = rpmPluginGetData(plugin); ++ free(state->buffer); ++ free(state); ++} ++ ++static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { ++ 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")); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; ++ } ++ rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); ++ Header h = rpmteHeader(te); ++ ++ /* 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(magic)), SEEK_END) < 0) { ++ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); ++ return RPMRC_FAIL; ++ } ++ rpm_loff_t table_start; ++ len = sizeof(table_start); ++ if (Fread(&table_start, len, 1, state->fd) != len) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); ++ return RPMRC_FAIL; ++ } ++ if (Fseek(state->fd, table_start, SEEK_SET) < 0) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); ++ return RPMRC_FAIL; ++ } ++ len = sizeof(state->keys); ++ if (Fread(&state->keys, len, 1, state->fd) != len) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); ++ return RPMRC_FAIL; ++ } ++ len = sizeof(state->keysize); ++ if (Fread(&state->keysize, len, 1, state->fd) != len) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); ++ return RPMRC_FAIL; ++ } ++ rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); ++ // now get digest table if there is a reason to have one. ++ if (state->keys == 0 || state->keysize == 0) { ++ // no files (or no digests(!)) ++ state->table = NULL; ++ } else { ++ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); ++ state->table = rcalloc(1, table_size); ++ if (Fread(state->table, table_size, 1, state->fd) != table_size) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); ++ return RPMRC_FAIL; ++ } ++ state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); ++ } ++ ++ // seek back to original location ++ // might not be needed if we seek to offset immediately ++ if (Fseek(state->fd, current, SEEK_SET) < 0) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; ++} ++ ++static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) ++{ ++ reflink_state state = rpmPluginGetData(plugin); ++ state->files = rpmfilesFree(state->files); ++ if (state->table) { ++ free(state->table); ++ state->table = NULL; ++ } ++ if (state->inodeIndexes) { ++ inodeIndexHashFree(state->inodeIndexes); ++ state->inodeIndexes = NULL; ++ } ++ return RPMRC_OK; ++} ++ ++ ++// have a prototype, warnings system ++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"), 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); ++ if (entry == NULL) { ++ return NOT_FOUND; ++ } ++ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); ++ return offset; ++} ++ ++static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) ++{ ++ struct file_clone_range fcr; ++ rpm_loff_t size; ++ int dst, rc; ++ int *hlix; ++ ++ reflink_state state = rpmPluginGetData(plugin); ++ if (state->table == NULL) { ++ // no table means rpm is not in reflink format, so leave. Now. ++ return RPMRC_OK; ++ } ++ if (op == FA_TOUCH) { ++ // we're not overwriting an existing file ++ return RPMRC_OK; ++ } ++ fcr.dest_offset = 0; ++ if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { ++ rpm_ino_t inode = rpmfiFInode(fi); ++ /* 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)) { ++ // entry is in table, use hard link ++ char *fn = rpmfilesFN(state->files, hlix[0]); ++ if (link(fn, path) != 0) { ++ rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); ++ free(fn); ++ return RPMRC_FAIL; ++ } ++ free(fn); ++ return RPMRC_PLUGIN_CONTENTS; ++ } ++ /* if we didn't hard link, then we'll track this inode as being created soon */ ++ if (rpmfiFNlink(fi) > 1) { ++ /* minor optimization: only store files with more than one link */ ++ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); ++ } ++ /* derived from wfd_open in fsm.c */ ++ mode_t old_umask = umask(0577); ++ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); ++ umask(old_umask); ++ if (dst == -1) { ++ rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); ++ return RPMRC_FAIL; ++ } ++ size = rpmfiFSize(fi); ++ if (size > 0) { ++ /* round src_length down to fundamental_block_size multiple */ ++ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; ++ if ((size % state->fundamental_block_size) > 0) { ++ /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ ++ fcr.src_length += state->fundamental_block_size; ++ } ++ fcr.src_fd = Fileno(state->fd); ++ if (fcr.src_fd == -1) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); ++ return RPMRC_FAIL; ++ } ++ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); ++ if (fcr.src_offset == NOT_FOUND) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); ++ return RPMRC_FAIL; ++ } ++ rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); ++ rc = ioctl(dst, FICLONERANGE, &fcr); ++ if (rc) { ++ rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); ++ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ rpm_loff_t left = size; ++ size_t len, read, written; ++ while (left) { ++ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); ++ read = Fread(state->buffer, len, 1, state->fd); ++ if (read != len) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ written = write(dst, state->buffer, len); ++ if (read != written) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ left -= len; ++ } ++ } else { ++ /* reflink worked, so truncate */ ++ rc = ftruncate(dst, size); ++ if (rc) { ++ rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); ++ return RPMRC_FAIL; ++ } ++ } ++ } ++ close(dst); ++ 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_pre = reflink_fsm_file_pre, ++}; +diff --git a/rpm2extents.c b/rpm2extents.c +new file mode 100644 +index 000000000..5662b86a6 +--- /dev/null ++++ b/rpm2extents.c +@@ -0,0 +1,519 @@ ++/* rpm2extents: convert payload to inline extents */ ++ ++#include "system.h" ++ ++#include /* rpmReadPackageFile .. */ ++#include ++#include ++#include ++#include ++ ++#include ++#include "lib/rpmlead.h" ++#include "lib/signature.h" ++#include "lib/header_internal.h" ++#include "rpmio/rpmio_internal.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "debug.h" ++ ++/* hash of void * (pointers) to file digests to offsets within output. ++ The length of the key depends on what the FILEDIGESTALGO is. ++ */ ++#undef HASHTYPE ++#undef HTKEYTYPE ++#undef HTDATATYPE ++#define HASHTYPE digestSet ++#define HTKEYTYPE const unsigned char * ++#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; ++}; ++ ++rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit); ++ ++rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit) ++{ ++ return (unit - (pos % unit)) % unit; ++} ++ ++static int digestor( ++ FD_t fdi, ++ FD_t fdo, ++ FD_t validationo, ++ uint8_t algos[], ++ 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; ++ } ++ ++ len = sizeof(fdilength); ++ if (Fwrite(&fdilength, len, 1, validationo) != 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")); ++ goto exit; ++ } ++ for (algo = 0; algo < algos_len; algo++) ++ { ++ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); ++ ++ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); ++ algo_name_len = (uint32_t)strlen(algo_name); ++ algo_digest_len = (uint32_t)filedigest_len; ++ ++ len = sizeof(algo_name_len); ++ if (Fwrite(&algo_name_len, len, 1, validationo) != len) ++ { ++ fprintf( ++ stderr, ++ _("Unable to write validation algo name length\n") ++ ); ++ goto exit; ++ } ++ len = sizeof(algo_digest_len); ++ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) ++ { ++ fprintf( ++ stderr, ++ _("Unable to write number of bytes for validation 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")); ++ goto exit; ++ } ++ if ( ++ Fwrite( ++ filedigest, ++ algo_digest_len, ++ 1, ++ validationo ++ ) != algo_digest_len ++ ) ++ { ++ fprintf( ++ stderr, ++ _("Unable to write validation digest value %u, %zu\n"), ++ algo_digest_len, ++ filedigest_len ++ ); ++ goto exit; ++ } ++ } ++ rc = RPMRC_OK; ++exit: ++ return rc; ++} ++ ++static rpmRC process_package(FD_t fdi, FD_t validationi) ++{ ++ uint32_t diglen; ++ /* GNU C extension: can use diglen from outer context */ ++ int digestSetCmp(const unsigned char * a, const unsigned char * b) ++ { ++ return memcmp(a, b, diglen); ++ } ++ ++ unsigned int digestSetHash(const unsigned char * digest) ++ { ++ /* assumes sizeof(unsigned int) < diglen */ ++ return *(unsigned int *)digest; ++ } ++ ++ int digestoffsetCmp(const void * a, const void * b) ++ { ++ return digestSetCmp( ++ ((struct digestoffset *)a)->digest, ++ ((struct digestoffset *)b)->digest ++ ); ++ } ++ ++ FD_t fdo; ++ FD_t gzdi; ++ Header h, sigh; ++ long fundamental_block_size = sysconf(_SC_PAGESIZE); ++ rpmRC rc = RPMRC_OK; ++ rpm_mode_t mode; ++ char *rpmio_flags = NULL, *zeros; ++ const unsigned char *digest; ++ rpm_loff_t pos, size, pad, validation_pos; ++ uint32_t offset_ix = 0; ++ size_t len; ++ int next = 0; ++ ++ fdo = fdDup(STDOUT_FILENO); ++ ++ if (rpmReadPackageRaw(fdi, &sigh, &h)) ++ { ++ fprintf(stderr, _("Error reading package\n")); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (rpmLeadWrite(fdo, h)) ++ { ++ fprintf( ++ stderr, ++ _("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)); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) ++ { ++ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); ++ 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); ++ } ++ ++ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ ++ free(rpmio_flags); ++ ++ if (gzdi == NULL) ++ { ++ fprintf(stderr, _("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 ++ ); ++ ++ /* 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); ++ ++ zeros = xcalloc(fundamental_block_size, 1); ++ ++ 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) ++ { ++ fprintf(stderr, _("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) ++ { ++ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); ++ goto exit; ++ } ++ pos += size; ++ } ++ Fclose(gzdi); /* XXX gzdi == fdi */ ++ ++ qsort( ++ offsets, ++ (size_t)offset_ix, ++ sizeof(struct digestoffset), ++ digestoffsetCmp ++ ); ++ ++ len = sizeof(offset_ix); ++ if (Fwrite(&offset_ix, len, 1, fdo) != len) ++ { ++ fprintf(stderr, _("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")); ++ 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")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) ++ { ++ fprintf(stderr, _("Unable to write offset\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ } ++ validation_pos = ( ++ pos + sizeof(offset_ix) + sizeof(diglen) + ++ offset_ix * (diglen + sizeof(rpm_loff_t)) ++ ); ++ ++ ssize_t validation_len = ufdCopy(validationi, fdo); ++ if (validation_len == -1) ++ { ++ fprintf(stderr, _("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) ++ { ++ fprintf(stderr, _("Unable to write final padding\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ zeros = _free(zeros); ++ if (Fwrite(&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 table\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ uint64_t magic = MAGIC; ++ len = sizeof(magic); ++ if (Fwrite(&magic, len, 1, fdo) != len) ++ { ++ fprintf(stderr, _("Unable to write magic\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ ++exit: ++ rpmfilesFree(files); ++ rpmfiFree(fi); ++ headerFree(h); ++ return rc; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ rpmRC rc; ++ int cprc = 0; ++ uint8_t algos[argc - 1]; ++ int mainpipefd[2]; ++ int metapipefd[2]; ++ pid_t cpid, w; ++ int wstatus; ++ ++ xsetprogname(argv[0]); /* Portability call -- see system.h */ ++ rpmReadConfigFiles(NULL, NULL); ++ ++ 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) ++ { ++ fprintf( ++ stderr, ++ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") ++ ); ++ exit(EXIT_FAILURE); ++ } ++ ++ for (int x = 0; x < (argc - 1); x++) ++ { ++ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) ++ { ++ fprintf( ++ stderr, ++ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), ++ argv[x + 1] ++ ); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ ++ 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, argc - 1); ++ Fclose(validationo); ++ Fclose(fdo); ++ Fclose(fdi); ++ } else { ++ /* parent: main program */ ++ 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. */ ++ 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 failed\n")); ++ 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; ++ } ++ } ++ if (rc != RPMRC_OK) ++ { ++ /* translate rpmRC into generic failure return code. */ ++ return EXIT_FAILURE; ++ } ++ return EXIT_SUCCESS; ++} +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index 015c15a5c..7b972b4a6 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -283,6 +283,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se) + return vs->val; + } + ++int pgpStringVal(pgpValType type, const char *str, uint8_t *val) ++{ ++ pgpValTbl tbl = pgpValTable(type); ++ if (tbl == NULL) return -1; ++ int v = pgpValTok(tbl, str, str + strlen(str)); ++ if (v == -1) return -1; ++ *val = (uint8_t)v; ++ return 0; ++} ++ + /** \ingroup rpmpgp + * Decode length from 1, 2, or 5 octet body length encoding, used in + * new format packet headers and V4 signature subpackets. +diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h +index c53e29b01..2b57318ba 100644 +--- a/rpmio/rpmpgp.h ++++ b/rpmio/rpmpgp.h +@@ -973,6 +973,15 @@ typedef rpmFlags rpmDigestFlags; + */ + const char * pgpValString(pgpValType type, uint8_t val); + ++/** \ingroup rpmpgp ++ * Return OpenPGP value for a string. ++ * @param type type of value ++ * @param str string to lookup ++ * @param[out] val byte value associated with string ++ * @return 0 on success else -1 ++ */ ++int pgpStringVal(pgpValType type, const char *str, uint8_t *val); ++ + /** \ingroup rpmpgp + * Return (native-endian) integer from big-endian representation. + * @param s pointer to big-endian integer +-- +2.35.1 + diff --git a/0001-Return-NULL-string-as-None-from-utf8FromString.patch b/0001-Return-NULL-string-as-None-from-utf8FromString.patch new file mode 100644 index 0000000..e91db6f --- /dev/null +++ b/0001-Return-NULL-string-as-None-from-utf8FromString.patch @@ -0,0 +1,41 @@ +From aea53a4aead8bd71f519df35fcffd9eec76fbc01 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Panu Matilainen +Date: Tue, 26 Feb 2019 11:27:51 +0200 +Subject: [PATCH] Return NULL string as None from utf8FromString() + +Commit 84920f898315d09a57a3f1067433eaeb7de5e830 regressed dnf install +to segfault at the end due to some NULL string passed to strlen(). +Check for NULL and return it as None, make it an inline function +to make this saner. +--- + python/rpmsystem-py.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h +index 87c750571..25938464a 100644 +--- a/python/rpmsystem-py.h ++++ b/python/rpmsystem-py.h +@@ -19,11 +19,17 @@ + #define PyInt_AsSsize_t PyLong_AsSsize_t + #endif + ++static inline PyObject * utf8FromString(const char *s) ++{ + /* In Python 3, we return all strings as surrogate-escaped utf-8 */ + #if PY_MAJOR_VERSION >= 3 +-#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape") ++ if (s != NULL) ++ return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape"); + #else +-#define utf8FromString(_s) PyBytes_FromString(_s) ++ if (s != NULL) ++ return PyBytes_FromString(s); + #endif ++ Py_RETURN_NONE; ++} + + #endif /* H_SYSTEM_PYTHON */ +-- +2.20.1 + diff --git a/0001-Unblock-signals-in-forked-scriptlets.patch b/0001-Unblock-signals-in-forked-scriptlets.patch new file mode 100644 index 0000000..fb1e8d4 --- /dev/null +++ b/0001-Unblock-signals-in-forked-scriptlets.patch @@ -0,0 +1,37 @@ +From cb6aa82dbc10d554f8d234e934ae7c77e39a3ce2 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Tue, 12 Jan 2021 13:35:23 +0200 +Subject: [PATCH] Unblock signals in forked scriptlets + +Since commit c5f82d3f6223ebd0c5cc0a07ea60393ae7284929 we've blocked +most signals during transactions, which makes sense to rpm itself but +the signal mask is inherited to childs and carried even across exec(), +so all scriptlets are executing with those signals blocked as well. +Which in turn does not make sense, the scriptlets could run stuff that +actually depends on signal delivery (such as SIGALARM in RhBug:1913765). + +Unblock all signals for forked scriptlet execution (Lua scriptlets are +totally different as they execute in-process for now) +--- + lib/rpmscript.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib/rpmscript.c b/lib/rpmscript.c +index 2ae3378f7..c69d29554 100644 +--- a/lib/rpmscript.c ++++ b/lib/rpmscript.c +@@ -152,6 +152,11 @@ static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes, + FD_t scriptFd, FD_t out) + { + int xx; ++ sigset_t set; ++ ++ /* Unmask all signals, the scripts may need them */ ++ sigfillset(&set); ++ sigprocmask(SIG_UNBLOCK, &set, NULL); + + /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */ + (void) signal(SIGPIPE, SIG_DFL); +-- +2.29.2 + diff --git a/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch b/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch new file mode 100644 index 0000000..2863a98 --- /dev/null +++ b/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch @@ -0,0 +1,58 @@ +From fc2c986d8f5e4174885ae377750185339636f062 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Mon, 15 Apr 2019 15:46:09 +0200 +Subject: [PATCH] Use RPM_BUILD_NCPUS in brp-strip-static-archive + +to speed the script up for large number of files to be looked at. +Use xargs -P instead of find -exec. + +Add xargs to the test environment + +Resolves rhbz1691822 +--- + scripts/brp-strip-static-archive | 8 +++++--- + tests/Makefile.am | 2 +- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive +index ddd3b2422..4dc449061 100755 +--- a/scripts/brp-strip-static-archive ++++ b/scripts/brp-strip-static-archive +@@ -5,6 +5,7 @@ if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then + fi + + STRIP=${1:-strip} ++NCPUS=${RPM_BUILD_NCPUS:-1} + + case `uname -a` in + Darwin*) exit 0 ;; +@@ -12,9 +13,10 @@ Darwin*) exit 0 ;; + esac + + # Strip static libraries. +-for f in `find "$RPM_BUILD_ROOT" -type f -a -exec file {} \; | \ +- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ ++for f in `find "$RPM_BUILD_ROOT" -type f | \ ++ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ ++ xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \ + grep 'current ar archive' | \ +- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do ++ sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do + $STRIP -g "$f" + done +diff --git a/tests/Makefile.am b/tests/Makefile.am +index e2d759d82..ad9549a68 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -144,7 +144,7 @@ populate_testing: + for d in dev etc magic tmp var; do if [ ! -d testing/$${d} ]; then mkdir testing/$${d}; fi; done + for node in urandom stdin stderr stdout null full; do ln -s /dev/$${node} testing/dev/$${node}; done + for cf in hosts resolv.conf passwd shadow group gshadow mtab ; do [ -f /etc/$${cf} ] && ln -s /etc/$${cf} testing/etc/$${cf}; done +- for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done ++ for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils xargs; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done + for d in /proc /sys /selinux /etc/selinux; do if [ -d $${d} ]; then ln -s $${d} testing/$${d}; fi; done + (cd testing/magic && file -C) + HOME=$(abs_builddir)/testing gpg2 --import ${abs_srcdir}/data/keys/*.secret +-- +2.21.0 + diff --git a/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch b/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch new file mode 100644 index 0000000..6053ca2 --- /dev/null +++ b/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch @@ -0,0 +1,29 @@ +From 9aae21d7610a7e8067ae932f36d1c8bb8583fe59 Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Wed, 5 Jun 2019 06:07:00 +0200 +Subject: [PATCH] Use [ ] in condition to avoid sub processes in + find-debuginfo.sh (#735) + +Introduced in commit 1da9e83, spotted by covscan. + +Modified to fix another covscan warning +--- + scripts/find-debuginfo.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/find-debuginfo.sh b/scripts/find-debuginfo.sh +index 23286139e..d75da1108 100755 +--- a/scripts/find-debuginfo.sh ++++ b/scripts/find-debuginfo.sh +@@ -213,7 +213,7 @@ if test -n "$build_id_seed" -a "$no_recompute_build_id" = "true"; then + exit 2 + fi + +-if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then ++if [ "$strip_g" = "true" ] && [ "$strip_glibs" = "true" ]; then + echo >&2 "*** ERROR: -g and --g-libs cannot be used together" + exit 2 + fi +-- +2.21.0 + diff --git a/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch b/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch new file mode 100644 index 0000000..14cf5d2 --- /dev/null +++ b/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch @@ -0,0 +1,26 @@ +From 09d181d78c16e1751779586c606e85c11f360407 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 25 Jun 2019 18:04:20 +0200 +Subject: [PATCH] Use newline as a delimiter to avoid xargs messing up file + names with quotes + +which is the default behaviour otherwise. + +Fixes rhbz#1721348 +--- + scripts/brp-strip-static-archive | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive +index 13d9a098b..f7fb26b87 100755 +--- a/scripts/brp-strip-static-archive ++++ b/scripts/brp-strip-static-archive +@@ -15,4 +15,4 @@ esac + # Strip static libraries. + find "$RPM_BUILD_ROOT" -type f | \ + grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ +- xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0 ++ xargs -d '\n' -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -d '\n' -I\{\} $STRIP -g \{\}" ARG0 +-- +2.21.0 + diff --git a/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch b/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch new file mode 100644 index 0000000..9e9ee45 --- /dev/null +++ b/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch @@ -0,0 +1,38 @@ +From 9cbc1fe444b048c3f7cf5ea09ab650d1c146d54a Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 20 Feb 2019 14:49:19 +0200 +Subject: [PATCH] When doing the same thing more than once, use a loop... + +No functional changes but this'll simplify the next commit quite a bit. +--- + build/spec.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/build/spec.c b/build/spec.c +index e414e4102..80eaca611 100644 +--- a/build/spec.c ++++ b/build/spec.c +@@ -303,15 +303,13 @@ rpmSpec newSpec(void) + spec->pool = rpmstrPoolCreate(); + + #ifdef WITH_LUA +- { + /* make sure patches and sources tables always exist */ + rpmlua lua = NULL; /* global state */ +- rpmluaDelVar(lua, "patches"); +- rpmluaDelVar(lua, "sources"); +- rpmluaPushTable(lua, "patches"); +- rpmluaPushTable(lua, "sources"); +- rpmluaPop(lua); +- rpmluaPop(lua); ++ const char * luavars[] = { "patches", "sources", NULL, }; ++ for (const char **vp = luavars; vp && *vp; vp++) { ++ rpmluaDelVar(lua, *vp); ++ rpmluaPushTable(lua, *vp); ++ rpmluaPop(lua); + } + #endif + return spec; +-- +2.26.2 + diff --git a/0001-Work-around-buggy-signature-region-preventing-resign.patch b/0001-Work-around-buggy-signature-region-preventing-resign.patch new file mode 100644 index 0000000..54dd45f --- /dev/null +++ b/0001-Work-around-buggy-signature-region-preventing-resign.patch @@ -0,0 +1,44 @@ +From 8fefd2bd21b30996ad0748eab6baadf915610642 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Thu, 13 Aug 2020 13:29:10 +0300 +Subject: [PATCH] Work around buggy signature region preventing resigning + (RhBug:1851508) + +Various proprietary packages in the wild have subtly malformed data +in the signature header, in particular wrt the immutable region size, +presumably from using some in-house/3rd party signing tools which do +not understand the immutable region business at all. This can prevent +resigning and signature deletion on such packages due to the more +thorough checking that rpmsign does. + +As the old wisdom goes, be liberal in what you accept... we can easily +work around the crud by just taking a fresh copy of the contents that +are legit as such (otherwise the package would be uninstallable). + + +Adjusted for 4.14.3 + +--- rpm-4.14.3/sign/rpmgensig.c.orig 2020-10-29 16:00:38.785229048 +0100 ++++ rpm-4.14.3/sign/rpmgensig.c 2020-10-29 16:08:55.997791345 +0100 +@@ -401,12 +401,19 @@ + + if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) { + oh = headerCopyLoad(utd->data); +- nh = headerCopy(oh); +- headerFree(oh); + rpmtdFreeData(utd); ++ } else { ++ /* XXX should we warn if the immutable region is corrupt/missing? */ ++ oh = headerLink(*hdrp); ++ } ++ ++ if (oh) { ++ /* Perform a copy to eliminate crud from buggy signing tools etc */ ++ nh = headerCopy(oh); + headerFree(*hdrp); + *hdrp = headerLink(nh); + headerFree(nh); ++ headerFree(oh); + } + } + diff --git a/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch b/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch new file mode 100644 index 0000000..ac45734 --- /dev/null +++ b/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch @@ -0,0 +1,490 @@ +From ce6e8556a8f93327d6de0446f21ac5e549861d82 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Mark Wielaard +Date: Mon, 17 Jun 2019 11:23:24 +0200 +Subject: [PATCH 1/3] debugedit: Refactor reading/writing of relocated values. + +This refactors the reading and writing of relocated values into seperate +helper functions (setup_relbuf and update_rela_data). It will be easier +to reuse this code in case we want to read/write relocated values in other +sections than DEBUG_INFO. The only functional change is that we explicitly +track whether the relocation data is updated, and only explicitly update +and write out the relocation data if so. In the case there were no strp +or stmt updates, there will also not be any relocation updates, even if +there is relocation data available. + +All new debugedit testcases pass before and after this refactoring. +--- + tools/debugedit.c | 395 +++++++++++++++++++++++++--------------------- + 1 file changed, 216 insertions(+), 179 deletions(-) + +diff --git a/tools/debugedit.c b/tools/debugedit.c +index 4be85b979..cf9cc3ca9 100644 +--- a/tools/debugedit.c ++++ b/tools/debugedit.c +@@ -401,13 +401,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v) + relend). Might just update the addend. So relocations need to be + updated at the end. */ + ++static bool rel_updated; ++ + #define do_write_32_relocated(ptr,val) ({ \ + if (relptr && relptr < relend && relptr->ptr == ptr) \ + { \ + if (reltype == SHT_REL) \ + do_write_32 (ptr, val - relptr->addend); \ + else \ +- relptr->addend = val; \ ++ { \ ++ relptr->addend = val; \ ++ rel_updated = true; \ ++ } \ + } \ + else \ + do_write_32 (ptr,val); \ +@@ -418,14 +423,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v) + ptr += 4; \ + }) + +-static struct ++typedef struct debug_section + { + const char *name; + unsigned char *data; + Elf_Data *elf_data; + size_t size; + int sec, relsec; +- } debug_sections[] = ++ REL *relbuf; ++ REL *relend; ++ } debug_section; ++ ++static debug_section debug_sections[] = + { + #define DEBUG_INFO 0 + #define DEBUG_ABBREV 1 +@@ -458,6 +467,201 @@ static struct + { NULL, NULL, NULL, 0, 0, 0 } + }; + ++static int ++rel_cmp (const void *a, const void *b) ++{ ++ REL *rela = (REL *) a, *relb = (REL *) b; ++ ++ if (rela->ptr < relb->ptr) ++ return -1; ++ ++ if (rela->ptr > relb->ptr) ++ return 1; ++ ++ return 0; ++} ++ ++/* Returns a malloced REL array, or NULL when there are no relocations ++ for this section. When there are relocations, will setup relend, ++ as the last REL, and reltype, as SHT_REL or SHT_RELA. */ ++static void ++setup_relbuf (DSO *dso, debug_section *sec, int *reltype) ++{ ++ int ndx, maxndx; ++ GElf_Rel rel; ++ GElf_Rela rela; ++ GElf_Sym sym; ++ GElf_Addr base = dso->shdr[sec->sec].sh_addr; ++ Elf_Data *symdata = NULL; ++ int rtype; ++ REL *relbuf; ++ Elf_Scn *scn; ++ Elf_Data *data; ++ int i = sec->relsec; ++ ++ /* No relocations, or did we do this already? */ ++ if (i == 0 || sec->relbuf != NULL) ++ { ++ relptr = sec->relbuf; ++ relend = sec->relend; ++ return; ++ } ++ ++ scn = dso->scn[i]; ++ data = elf_getdata (scn, NULL); ++ assert (data != NULL && data->d_buf != NULL); ++ assert (elf_getdata (scn, data) == NULL); ++ assert (data->d_off == 0); ++ assert (data->d_size == dso->shdr[i].sh_size); ++ maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize; ++ relbuf = malloc (maxndx * sizeof (REL)); ++ *reltype = dso->shdr[i].sh_type; ++ if (relbuf == NULL) ++ error (1, errno, "%s: Could not allocate memory", dso->filename); ++ ++ symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL); ++ assert (symdata != NULL && symdata->d_buf != NULL); ++ assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) == NULL); ++ assert (symdata->d_off == 0); ++ assert (symdata->d_size == dso->shdr[dso->shdr[i].sh_link].sh_size); ++ ++ for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) ++ { ++ if (dso->shdr[i].sh_type == SHT_REL) ++ { ++ gelf_getrel (data, ndx, &rel); ++ rela.r_offset = rel.r_offset; ++ rela.r_info = rel.r_info; ++ rela.r_addend = 0; ++ } ++ else ++ gelf_getrela (data, ndx, &rela); ++ gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); ++ /* Relocations against section symbols are uninteresting in REL. */ ++ if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) ++ continue; ++ /* Only consider relocations against .debug_str, .debug_line ++ and .debug_abbrev. */ ++ if (sym.st_shndx != debug_sections[DEBUG_STR].sec ++ && sym.st_shndx != debug_sections[DEBUG_LINE].sec ++ && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) ++ continue; ++ rela.r_addend += sym.st_value; ++ rtype = ELF64_R_TYPE (rela.r_info); ++ switch (dso->ehdr.e_machine) ++ { ++ case EM_SPARC: ++ case EM_SPARC32PLUS: ++ case EM_SPARCV9: ++ if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) ++ goto fail; ++ break; ++ case EM_386: ++ if (rtype != R_386_32) ++ goto fail; ++ break; ++ case EM_PPC: ++ case EM_PPC64: ++ if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) ++ goto fail; ++ break; ++ case EM_S390: ++ if (rtype != R_390_32) ++ goto fail; ++ break; ++ case EM_IA_64: ++ if (rtype != R_IA64_SECREL32LSB) ++ goto fail; ++ break; ++ case EM_X86_64: ++ if (rtype != R_X86_64_32) ++ goto fail; ++ break; ++ case EM_ALPHA: ++ if (rtype != R_ALPHA_REFLONG) ++ goto fail; ++ break; ++#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32) ++ case EM_AARCH64: ++ if (rtype != R_AARCH64_ABS32) ++ goto fail; ++ break; ++#endif ++ case EM_68K: ++ if (rtype != R_68K_32) ++ goto fail; ++ break; ++#if defined(EM_RISCV) && defined(R_RISCV_32) ++ case EM_RISCV: ++ if (rtype != R_RISCV_32) ++ goto fail; ++ break; ++#endif ++ default: ++ fail: ++ error (1, 0, "%s: Unhandled relocation %d in %s section", ++ dso->filename, rtype, sec->name); ++ } ++ relend->ptr = sec->data ++ + (rela.r_offset - base); ++ relend->addend = rela.r_addend; ++ relend->ndx = ndx; ++ ++(relend); ++ } ++ if (relbuf == relend) ++ { ++ free (relbuf); ++ relbuf = NULL; ++ relend = NULL; ++ } ++ else ++ qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); ++ ++ sec->relbuf = relbuf; ++ sec->relend = relend; ++ relptr = relbuf; ++} ++ ++/* Updates SHT_RELA section associated with the given section based on ++ the relbuf data. The relbuf data is freed at the end. */ ++static void ++update_rela_data (DSO *dso, struct debug_section *sec) ++{ ++ Elf_Data *symdata; ++ int relsec_ndx = sec->relsec; ++ Elf_Data *data = elf_getdata (dso->scn[relsec_ndx], NULL); ++ symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link], ++ NULL); ++ ++ relptr = sec->relbuf; ++ relend = sec->relend; ++ while (relptr < relend) ++ { ++ GElf_Sym sym; ++ GElf_Rela rela; ++ int ndx = relptr->ndx; ++ ++ if (gelf_getrela (data, ndx, &rela) == NULL) ++ error (1, 0, "Couldn't get relocation: %s", ++ elf_errmsg (-1)); ++ ++ if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info), ++ &sym) == NULL) ++ error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1)); ++ ++ rela.r_addend = relptr->addend - sym.st_value; ++ ++ if (gelf_update_rela (data, ndx, &rela) == 0) ++ error (1, 0, "Couldn't update relocations: %s", ++ elf_errmsg (-1)); ++ ++ ++relptr; ++ } ++ elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); ++ ++ free (sec->relbuf); ++} ++ + struct abbrev_attr + { + unsigned int attr; +@@ -1743,20 +1947,6 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) + return ptr; + } + +-static int +-rel_cmp (const void *a, const void *b) +-{ +- REL *rela = (REL *) a, *relb = (REL *) b; +- +- if (rela->ptr < relb->ptr) +- return -1; +- +- if (rela->ptr > relb->ptr) +- return 1; +- +- return 0; +-} +- + static int + line_rel_cmp (const void *a, const void *b) + { +@@ -1871,132 +2061,7 @@ edit_dwarf2 (DSO *dso) + htab_t abbrev; + struct abbrev_tag tag, *t; + int phase; +- REL *relbuf = NULL; +- +- if (debug_sections[DEBUG_INFO].relsec) +- { +- int ndx, maxndx; +- GElf_Rel rel; +- GElf_Rela rela; +- GElf_Sym sym; +- GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr; +- Elf_Data *symdata = NULL; +- int rtype; +- +- i = debug_sections[DEBUG_INFO].relsec; +- scn = dso->scn[i]; +- data = elf_getdata (scn, NULL); +- assert (data != NULL && data->d_buf != NULL); +- assert (elf_getdata (scn, data) == NULL); +- assert (data->d_off == 0); +- assert (data->d_size == dso->shdr[i].sh_size); +- maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize; +- relbuf = malloc (maxndx * sizeof (REL)); +- reltype = dso->shdr[i].sh_type; +- if (relbuf == NULL) +- error (1, errno, "%s: Could not allocate memory", dso->filename); +- +- symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL); +- assert (symdata != NULL && symdata->d_buf != NULL); +- assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) +- == NULL); +- assert (symdata->d_off == 0); +- assert (symdata->d_size +- == dso->shdr[dso->shdr[i].sh_link].sh_size); +- +- for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) +- { +- if (dso->shdr[i].sh_type == SHT_REL) +- { +- gelf_getrel (data, ndx, &rel); +- rela.r_offset = rel.r_offset; +- rela.r_info = rel.r_info; +- rela.r_addend = 0; +- } +- else +- gelf_getrela (data, ndx, &rela); +- gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); +- /* Relocations against section symbols are uninteresting +- in REL. */ +- if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) +- continue; +- /* Only consider relocations against .debug_str, .debug_line +- and .debug_abbrev. */ +- if (sym.st_shndx != debug_sections[DEBUG_STR].sec +- && sym.st_shndx != debug_sections[DEBUG_LINE].sec +- && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) +- continue; +- rela.r_addend += sym.st_value; +- rtype = ELF64_R_TYPE (rela.r_info); +- switch (dso->ehdr.e_machine) +- { +- case EM_SPARC: +- case EM_SPARC32PLUS: +- case EM_SPARCV9: +- if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) +- goto fail; +- break; +- case EM_386: +- if (rtype != R_386_32) +- goto fail; +- break; +- case EM_PPC: +- case EM_PPC64: +- if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) +- goto fail; +- break; +- case EM_S390: +- if (rtype != R_390_32) +- goto fail; +- break; +- case EM_IA_64: +- if (rtype != R_IA64_SECREL32LSB) +- goto fail; +- break; +- case EM_X86_64: +- if (rtype != R_X86_64_32) +- goto fail; +- break; +- case EM_ALPHA: +- if (rtype != R_ALPHA_REFLONG) +- goto fail; +- break; +-#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32) +- case EM_AARCH64: +- if (rtype != R_AARCH64_ABS32) +- goto fail; +- break; +-#endif +- case EM_68K: +- if (rtype != R_68K_32) +- goto fail; +- break; +-#if defined(EM_RISCV) && defined(R_RISCV_32) +- case EM_RISCV: +- if (rtype != R_RISCV_32) +- goto fail; +- break; +-#endif +- default: +- fail: +- error (1, 0, "%s: Unhandled relocation %d in .debug_info section", +- dso->filename, rtype); +- } +- relend->ptr = debug_sections[DEBUG_INFO].data +- + (rela.r_offset - base); +- relend->addend = rela.r_addend; +- relend->ndx = ndx; +- ++relend; +- } +- if (relbuf == relend) +- { +- free (relbuf); +- relbuf = NULL; +- relend = NULL; +- } +- else +- qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); +- } ++ bool info_rel_updated = false; + + for (phase = 0; phase < 2; phase++) + { +@@ -2008,7 +2073,8 @@ edit_dwarf2 (DSO *dso) + break; + + ptr = debug_sections[DEBUG_INFO].data; +- relptr = relbuf; ++ setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype); ++ rel_updated = false; + endsec = ptr + debug_sections[DEBUG_INFO].size; + while (ptr < endsec) + { +@@ -2096,6 +2162,10 @@ edit_dwarf2 (DSO *dso) + htab_delete (abbrev); + } + ++ /* Remember whether any .debug_info relocations might need ++ to be updated. */ ++ info_rel_updated = rel_updated; ++ + /* We might have to recalculate/rewrite the debug_line + section. We need to do that before going into phase one + so we have all new offsets. We do this separately from +@@ -2240,41 +2310,8 @@ edit_dwarf2 (DSO *dso) + dirty_section (DEBUG_INFO); + + /* Update any debug_info relocations addends we might have touched. */ +- if (relbuf != NULL && reltype == SHT_RELA) +- { +- Elf_Data *symdata; +- int relsec_ndx = debug_sections[DEBUG_INFO].relsec; +- data = elf_getdata (dso->scn[relsec_ndx], NULL); +- symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link], +- NULL); +- +- relptr = relbuf; +- while (relptr < relend) +- { +- GElf_Sym sym; +- GElf_Rela rela; +- int ndx = relptr->ndx; +- +- if (gelf_getrela (data, ndx, &rela) == NULL) +- error (1, 0, "Couldn't get relocation: %s", +- elf_errmsg (-1)); +- +- if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info), +- &sym) == NULL) +- error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1)); +- +- rela.r_addend = relptr->addend - sym.st_value; +- +- if (gelf_update_rela (data, ndx, &rela) == 0) +- error (1, 0, "Couldn't update relocations: %s", +- elf_errmsg (-1)); +- +- ++relptr; +- } +- elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); +- } +- +- free (relbuf); ++ if (info_rel_updated) ++ update_rela_data (dso, &debug_sections[DEBUG_INFO]); + } + + return 0; +-- +2.23.0 + diff --git a/0002-Add-RPMTAG_IDENTITY-reservation.patch b/0002-Add-RPMTAG_IDENTITY-reservation.patch new file mode 100644 index 0000000..9dca222 --- /dev/null +++ b/0002-Add-RPMTAG_IDENTITY-reservation.patch @@ -0,0 +1,34 @@ +From a74ea72cb47dcdc1006ffbdd23643964bd40f580 Mon Sep 17 00:00:00 2001 +From: "Vladimir D. Seleznev" +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 +--- + 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 + diff --git a/0002-Handle-.debug_macro-in-debugedit.patch b/0002-Handle-.debug_macro-in-debugedit.patch new file mode 100644 index 0000000..368beb8 --- /dev/null +++ b/0002-Handle-.debug_macro-in-debugedit.patch @@ -0,0 +1,304 @@ +From 201a71ce18734b1cebc337225f345fd754a6414f Mon Sep 17 00:00:00 2001 +Message-Id: <201a71ce18734b1cebc337225f345fd754a6414f.1573552234.git.pmatilai@redhat.com> +In-Reply-To: +References: +From: Mark Wielaard +Date: Mon, 17 Jun 2019 11:23:25 +0200 +Subject: [PATCH 2/3] Handle .debug_macro in debugedit. + +When compiling with -g3 gcc will generate a .debug_macro section +which has pointers to the .debug_str section. Since we might rewrite +the .debug_str section, we also need to update any .debug_macro +pointers. + +Updated the debugedit.at testcase by building everything with -g +and add various checks to see the .debug_macro section looks OK +after running debugedit. Added a new rpmbuild.at testcase to check +handing of .debug_macro in the whole rpmbuild debuginfo pipeline +to double check the separate .debug file also contains the macros. + +Original patch by Michael Schroeder . Extended by +Mark Wielaard to deal with relocations and possible +multiple COMDAT .debug_macro sections. +--- + tests/Makefile.am | 1 + + tests/data/SPECS/hello-g3.spec | 60 ++++++++++ + tests/debugedit.at | 79 ++++++++++++- + tests/rpmbuild.at | 33 ++++++ + tools/debugedit.c | 196 +++++++++++++++++++++++++++++++-- + 5 files changed, 356 insertions(+), 13 deletions(-) + create mode 100644 tests/data/SPECS/hello-g3.spec + +[ test-suite part edited out, too painful to backport ] + +diff --git a/tools/debugedit.c b/tools/debugedit.c +index cf9cc3ca9..84483ef5e 100644 +--- a/tools/debugedit.c ++++ b/tools/debugedit.c +@@ -41,6 +41,7 @@ + #include + #include + ++ + /* Unfortunately strtab manipulation functions were only officially added + to elfutils libdw in 0.167. Before that there were internal unsupported + ebl variants. While libebl.h isn't supported we'll try to use it anyway +@@ -432,6 +433,7 @@ typedef struct debug_section + int sec, relsec; + REL *relbuf; + REL *relend; ++ struct debug_section *next; /* Only happens for COMDAT .debug_macro. */ + } debug_section; + + static debug_section debug_sections[] = +@@ -1989,11 +1991,35 @@ edit_dwarf2 (DSO *dso) + for (j = 0; debug_sections[j].name; ++j) + if (strcmp (name, debug_sections[j].name) == 0) + { ++ struct debug_section *debug_sec = &debug_sections[j]; + if (debug_sections[j].data) + { +- error (0, 0, "%s: Found two copies of %s section", +- dso->filename, name); +- return 1; ++ if (j != DEBUG_MACRO) ++ { ++ error (0, 0, "%s: Found two copies of %s section", ++ dso->filename, name); ++ return 1; ++ } ++ else ++ { ++ /* In relocatable files .debug_macro might ++ appear multiple times as COMDAT ++ section. */ ++ struct debug_section *sec; ++ sec = calloc (sizeof (struct debug_section), 1); ++ if (sec == NULL) ++ error (1, errno, ++ "%s: Could not allocate more macro sections", ++ dso->filename); ++ sec->name = ".debug_macro"; ++ ++ struct debug_section *macro_sec = debug_sec; ++ while (macro_sec->next != NULL) ++ macro_sec = macro_sec->next; ++ ++ macro_sec->next = sec; ++ debug_sec = sec; ++ } + } + + scn = dso->scn[i]; +@@ -2002,10 +2028,10 @@ edit_dwarf2 (DSO *dso) + assert (elf_getdata (scn, data) == NULL); + assert (data->d_off == 0); + assert (data->d_size == dso->shdr[i].sh_size); +- debug_sections[j].data = data->d_buf; +- debug_sections[j].elf_data = data; +- debug_sections[j].size = data->d_size; +- debug_sections[j].sec = i; ++ debug_sec->data = data->d_buf; ++ debug_sec->elf_data = data; ++ debug_sec->size = data->d_size; ++ debug_sec->sec = i; + break; + } + +@@ -2028,7 +2054,26 @@ edit_dwarf2 (DSO *dso) + + (dso->shdr[i].sh_type == SHT_RELA), + debug_sections[j].name) == 0) + { +- debug_sections[j].relsec = i; ++ if (j == DEBUG_MACRO) ++ { ++ /* Pick the correct one. */ ++ int rel_target = dso->shdr[i].sh_info; ++ struct debug_section *macro_sec = &debug_sections[j]; ++ while (macro_sec != NULL) ++ { ++ if (macro_sec->sec == rel_target) ++ { ++ macro_sec->relsec = i; ++ break; ++ } ++ macro_sec = macro_sec->next; ++ } ++ if (macro_sec == NULL) ++ error (0, 1, "No .debug_macro reloc section: %s", ++ dso->filename); ++ } ++ else ++ debug_sections[j].relsec = i; + break; + } + } +@@ -2062,6 +2107,7 @@ edit_dwarf2 (DSO *dso) + struct abbrev_tag tag, *t; + int phase; + bool info_rel_updated = false; ++ bool macro_rel_updated = false; + + for (phase = 0; phase < 2; phase++) + { +@@ -2279,6 +2325,113 @@ edit_dwarf2 (DSO *dso) + } + } + ++ /* The .debug_macro section also contains offsets into the ++ .debug_str section and references to the .debug_line ++ tables, so we need to update those as well if we update ++ the strings or the stmts. */ ++ if ((need_strp_update || need_stmt_update) ++ && debug_sections[DEBUG_MACRO].data) ++ { ++ /* There might be multiple (COMDAT) .debug_macro sections. */ ++ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; ++ while (macro_sec != NULL) ++ { ++ setup_relbuf(dso, macro_sec, &reltype); ++ rel_updated = false; ++ ++ ptr = macro_sec->data; ++ endsec = ptr + macro_sec->size; ++ int op = 0, macro_version, macro_flags; ++ int offset_len = 4, line_offset = 0; ++ ++ while (ptr < endsec) ++ { ++ if (!op) ++ { ++ macro_version = read_16 (ptr); ++ macro_flags = read_8 (ptr); ++ if (macro_version < 4 || macro_version > 5) ++ error (1, 0, "unhandled .debug_macro version: %d", ++ macro_version); ++ if ((macro_flags & ~2) != 0) ++ error (1, 0, "unhandled .debug_macro flags: 0x%x", ++ macro_flags); ++ ++ offset_len = (macro_flags & 0x01) ? 8 : 4; ++ line_offset = (macro_flags & 0x02) ? 1 : 0; ++ ++ if (offset_len != 4) ++ error (0, 1, ++ "Cannot handle 8 byte macro offsets: %s", ++ dso->filename); ++ ++ /* Update the line_offset if it is there. */ ++ if (line_offset) ++ { ++ if (phase == 0) ++ ptr += offset_len; ++ else ++ { ++ size_t idx, new_idx; ++ idx = do_read_32_relocated (ptr); ++ new_idx = find_new_list_offs (&dso->lines, ++ idx); ++ write_32_relocated (ptr, new_idx); ++ } ++ } ++ } ++ ++ op = read_8 (ptr); ++ if (!op) ++ continue; ++ switch(op) ++ { ++ case DW_MACRO_GNU_define: ++ case DW_MACRO_GNU_undef: ++ read_uleb128 (ptr); ++ ptr = ((unsigned char *) strchr ((char *) ptr, '\0') ++ + 1); ++ break; ++ case DW_MACRO_GNU_start_file: ++ read_uleb128 (ptr); ++ read_uleb128 (ptr); ++ break; ++ case DW_MACRO_GNU_end_file: ++ break; ++ case DW_MACRO_GNU_define_indirect: ++ case DW_MACRO_GNU_undef_indirect: ++ read_uleb128 (ptr); ++ if (phase == 0) ++ { ++ size_t idx = read_32_relocated (ptr); ++ record_existing_string_entry_idx (&dso->strings, ++ idx); ++ } ++ else ++ { ++ struct stridxentry *entry; ++ size_t idx, new_idx; ++ idx = do_read_32_relocated (ptr); ++ entry = string_find_entry (&dso->strings, idx); ++ new_idx = strent_offset (entry->entry); ++ write_32_relocated (ptr, new_idx); ++ } ++ break; ++ case DW_MACRO_GNU_transparent_include: ++ ptr += offset_len; ++ break; ++ default: ++ error (1, 0, "Unhandled DW_MACRO op 0x%x", op); ++ break; ++ } ++ } ++ ++ if (rel_updated) ++ macro_rel_updated = true; ++ macro_sec = macro_sec->next; ++ } ++ } ++ + /* Same for the debug_str section. Make sure everything is + in place for phase 1 updating of debug_info + references. */ +@@ -2308,10 +2461,24 @@ edit_dwarf2 (DSO *dso) + new strp, strings and/or linep offsets. */ + if (need_strp_update || need_string_replacement || need_stmt_update) + dirty_section (DEBUG_INFO); ++ if (need_strp_update || need_stmt_update) ++ dirty_section (DEBUG_MACRO); ++ if (need_stmt_update) ++ dirty_section (DEBUG_LINE); + +- /* Update any debug_info relocations addends we might have touched. */ ++ /* Update any relocations addends we might have touched. */ + if (info_rel_updated) + update_rela_data (dso, &debug_sections[DEBUG_INFO]); ++ ++ if (macro_rel_updated) ++ { ++ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; ++ while (macro_sec != NULL) ++ { ++ update_rela_data (dso, macro_sec); ++ macro_sec = macro_sec->next; ++ } ++ } + } + + return 0; +@@ -2843,6 +3010,17 @@ main (int argc, char *argv[]) + destroy_lines (&dso->lines); + free (dso); + ++ /* In case there were multiple (COMDAT) .debug_macro sections, ++ free them. */ ++ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; ++ macro_sec = macro_sec->next; ++ while (macro_sec != NULL) ++ { ++ struct debug_section *next = macro_sec->next; ++ free (macro_sec); ++ macro_sec = next; ++ } ++ + poptFreeContext (optCon); + + return 0; +-- +2.23.0 + diff --git a/0002-Remove-use-of-bool-type-for-consistency.patch b/0002-Remove-use-of-bool-type-for-consistency.patch new file mode 100644 index 0000000..332b002 --- /dev/null +++ b/0002-Remove-use-of-bool-type-for-consistency.patch @@ -0,0 +1,53 @@ +From 845b5c3882b1eecb31d712b61a4e91fe0eb70712 Mon Sep 17 00:00:00 2001 +From: Matthew Almond +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 + #include +-#include + #if WITH_CAP + #include + #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 + diff --git a/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch b/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch new file mode 100644 index 0000000..5b08ce7 --- /dev/null +++ b/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch @@ -0,0 +1,77 @@ +From 172e1f5ec0e37c8aab91a2ae35bd73ea594432cb Mon Sep 17 00:00:00 2001 +Message-Id: <172e1f5ec0e37c8aab91a2ae35bd73ea594432cb.1571920849.git.pmatilai@redhat.com> +In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 4 Oct 2018 13:36:09 +0300 +Subject: [PATCH 2/5] Use Python 3 -compatible exception syntax in tests + +Makes a few tests pass that failed before, and others now fail +a little bit later... + +(cherry picked from commit 511eef19298765e3639bccbe98bc3a50023f45b2) +--- + tests/rpmpython.at | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/tests/rpmpython.at b/tests/rpmpython.at +index 3a7c251f1..1daaf1216 100644 +--- a/tests/rpmpython.at ++++ b/tests/rpmpython.at +@@ -96,7 +96,7 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]: + try: + x = getattr(h, a) + myprint(x) +- except AttributeError, exc: ++ except AttributeError as exc: + myprint(exc) + ], + [testpkg-5:1.0-1.noarch +@@ -119,7 +119,7 @@ h2['dirindexes'] = [ 0, 0, 1 ] + for h in [h1, h2]: + try: + myprint(','.join(h['filenames'])) +- except rpm.error, exc: ++ except rpm.error as exc: + myprint(exc) + ], + [invalid header data +@@ -164,7 +164,7 @@ rpm.setLogFile(sink) + try: + h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm') + myprint(h['arch']) +-except rpm.error, e: ++except rpm.error as e: + myprint(e) + ], + [public key not available +@@ -183,7 +183,7 @@ ts.setKeyring(keyring) + try: + h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm') + myprint(h['arch']) +-except rpm.error, e: ++except rpm.error as e: + myprint(e) + ], + [x86_64] +@@ -207,7 +207,7 @@ h = rpm.hdr() + h['name'] = "foo" + try: + ts.addInstall(h, 'foo', 'u') +-except rpm.error, err: ++except rpm.error as err: + myprint(err) + for e in ts: + myprint(e.NEVRA()) +@@ -228,7 +228,7 @@ h['dirnames'] = ['/opt' '/flopt'] + h['dirindexes'] = [ 1, 2, 3 ] + try: + ts.addInstall(h, 'foo', 'u') +-except rpm.error, err: ++except rpm.error as err: + myprint(err) + for e in ts: + myprint(e.NEVRA()) +-- +2.21.0 + diff --git a/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch b/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch new file mode 100644 index 0000000..713d336 --- /dev/null +++ b/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch @@ -0,0 +1,44 @@ +From 6525a9bf1529944741f273cb9fde5619f006a673 Mon Sep 17 00:00:00 2001 +Message-Id: <6525a9bf1529944741f273cb9fde5619f006a673.1571920849.git.pmatilai@redhat.com> +In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 4 Oct 2018 17:41:19 +0300 +Subject: [PATCH 3/5] Fix couple of bytes vs strings issues in Python tests + +For the purposes of rpmio testing and importing public key, we're +dealing with bytes rather than encoded strings. In the carefree days +of Python 2 such details didn't matter, in Python 3 they cause failures. +The signed package test still fails after this one but it's due to +a more general issue. + +(cherry picked from commit 86f7898dd6a7fa8718c02675f5a7ee04ff987422) +--- + tests/rpmpython.at | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/rpmpython.at b/tests/rpmpython.at +index 1daaf1216..ae020ae95 100644 +--- a/tests/rpmpython.at ++++ b/tests/rpmpython.at +@@ -33,7 +33,7 @@ prexp(mname) + []) + + RPMPY_TEST([basic rpmio],[ +-msg = 'Killroy was here\n' ++msg = b'Killroy was here\n' + data = msg * 10 + # TODO: test other compression types too if built in + for iot in [ 'fpio', 'fdio', 'ufdio', 'gzdio' ]: +@@ -173,7 +173,7 @@ except rpm.error as e: + + RPMPY_TEST([reading a signed package file 2],[ + +-keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub').read() ++keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub', 'rb').read() + pubkey = rpm.pubkey(keydata) + keyring = rpm.keyring() + keyring.addKey(pubkey) +-- +2.21.0 + diff --git a/0003-Match-formatting-style-of-existing-code.patch b/0003-Match-formatting-style-of-existing-code.patch new file mode 100644 index 0000000..aae1035 --- /dev/null +++ b/0003-Match-formatting-style-of-existing-code.patch @@ -0,0 +1,1249 @@ +From aa31421bfe835dadd29da3aa46ee446038f80d02 Mon Sep 17 00:00:00 2001 +From: Matthew Almond +Date: Sun, 31 Jan 2021 13:51:16 -0800 +Subject: [PATCH 03/30] Match formatting/style of existing code + +The existing code contains some variability in formatting. I'm not sure +if { is meant to be on the end of the line, or on a new line, but I've +standardized on the former. + +The indentation is intended to match the existing convention: 4 column +indent, but 8 column wide tab characters. This is easy to follow/use in +vim, but is surprisingly difficult to get right in vscode. I am doing +this reformat here and now, and future changes will be after this. + +I'm keen to fold the patches together, but for now, I'm trying to keep +the history of #1470 linear so everyone can follow along. +--- + lib/rpmplugins.c | 6 +- + plugins/reflink.c | 407 ++++++++++++++++++--------------- + rpm2extents.c | 562 ++++++++++++++++++++-------------------------- + 3 files changed, 462 insertions(+), 513 deletions(-) + +diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c +index c5084d398..3da3097af 100644 +--- a/lib/rpmplugins.c ++++ b/lib/rpmplugins.c +@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, + 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. ++ /* 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 { +diff --git a/plugins/reflink.c b/plugins/reflink.c +index d7f19acd9..9eaa87094 100644 +--- a/plugins/reflink.c ++++ b/plugins/reflink.c +@@ -32,31 +32,32 @@ + #include "lib/rpmhash.H" + #include "lib/rpmhash.C" + +-/* +-We use this in find to indicate a key wasn't found. This is an unrecoverable +-error, but we can at least show a decent error. 0 is never a valid offset +-because it's the offset of the start of the file. +-*/ ++/* We use this in find to indicate a key wasn't found. This is an ++ * unrecoverable error, but we can at least show a decent error. 0 is never a ++ * valid offset because it's the offset of the start of the file. ++ */ + #define NOT_FOUND 0 + + #define BUFFER_SIZE (1024 * 128) + +-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ ++/* 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; +- char *buffer; ++ /* Stuff that's used across rpms */ ++ long fundamental_block_size; ++ char *buffer; + +- /* stuff that's used/updated per psm */ +- uint32_t keys, keysize; ++ /* stuff that's used/updated per psm */ ++ uint32_t keys, keysize; + +- // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) +- unsigned char *table; +- FD_t fd; +- rpmfiles files; +- inodeIndexHash inodeIndexes; ++ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */ ++ unsigned char *table; ++ FD_t fd; ++ rpmfiles files; ++ inodeIndexHash inodeIndexes; + }; + + typedef struct reflink_state_s * reflink_state; +@@ -73,60 +74,62 @@ static unsigned int inodeId(rpm_ino_t a) + } + + static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { +- reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); ++ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); + +- /* +- IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and +- length arguments to be aligned to the fundamental block size. ++ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset ++ * and length arguments to be aligned to the fundamental block size. ++ * ++ * The value of "fundamental block size" is directly related to the ++ * system's page size, so we should use that. ++ */ ++ state->fundamental_block_size = sysconf(_SC_PAGESIZE); ++ state->buffer = rcalloc(1, BUFFER_SIZE); ++ rpmPluginSetData(plugin, state); + +- The value of "fundamental block size" is directly related to the system's +- page size, so we should use that. +- */ +- state->fundamental_block_size = sysconf(_SC_PAGESIZE); +- state->buffer = rcalloc(1, BUFFER_SIZE); +- rpmPluginSetData(plugin, state); +- +- return RPMRC_OK; ++ return RPMRC_OK; + } + + static void reflink_cleanup(rpmPlugin plugin) { +- reflink_state state = rpmPluginGetData(plugin); +- free(state->buffer); +- free(state); ++ reflink_state state = rpmPluginGetData(plugin); ++ free(state->buffer); ++ free(state); + } + + static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { + 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; ++ 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; ++ 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; ++ 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")); +- return RPMRC_FAIL; +- } +- return RPMRC_OK; ++ 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")); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; + } + rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); + Header h = rpmteHeader(te); +@@ -136,53 +139,60 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { + headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon"); + headerFree(h); + state->files = rpmteFiles(te); +- /* tail of file contains offset_table, offset_checksums +- then magic +- */ ++ /* tail of file contains offset_table, offset_checksums then magic */ + if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) { +- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), ++ state->fd); ++ return RPMRC_FAIL; + } + rpm_loff_t table_start; + len = sizeof(table_start); + if (Fread(&table_start, len, 1, state->fd) != len) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); ++ return RPMRC_FAIL; + } + if (Fseek(state->fd, table_start, SEEK_SET) < 0) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); ++ return RPMRC_FAIL; + } + len = sizeof(state->keys); + if (Fread(&state->keys, len, 1, state->fd) != len) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); ++ return RPMRC_FAIL; + } + len = sizeof(state->keysize); + if (Fread(&state->keysize, len, 1, state->fd) != len) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); ++ return RPMRC_FAIL; + } +- rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); +- // now get digest table if there is a reason to have one. ++ rpmlog( ++ RPMLOG_DEBUG, ++ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), ++ table_start, state->keys, state->keysize ++ ); ++ /* now get digest table if there is a reason to have one. */ + if (state->keys == 0 || state->keysize == 0) { +- // no files (or no digests(!)) +- state->table = NULL; ++ /* no files (or no digests(!)) */ ++ state->table = NULL; + } else { +- int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); +- state->table = rcalloc(1, table_size); +- if (Fread(state->table, table_size, 1, state->fd) != table_size) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); +- return RPMRC_FAIL; +- } +- state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); ++ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); ++ state->table = rcalloc(1, table_size); ++ if (Fread(state->table, table_size, 1, state->fd) != table_size) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); ++ return RPMRC_FAIL; ++ } ++ state->inodeIndexes = inodeIndexHashCreate( ++ state->keys, inodeId, inodeCmp, NULL, NULL ++ ); + } + +- // seek back to original location +- // might not be needed if we seek to offset immediately ++ /* Seek back to original location. ++ * Might not be needed if we seek to offset immediately ++ */ + if (Fseek(state->fd, current, SEEK_SET) < 0) { +- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); +- return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, ++ _("reflink: unable to seek back to original location\n")); ++ return RPMRC_FAIL; + } + return RPMRC_OK; + } +@@ -192,40 +202,45 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) + reflink_state state = rpmPluginGetData(plugin); + state->files = rpmfilesFree(state->files); + if (state->table) { +- free(state->table); +- state->table = NULL; ++ free(state->table); ++ state->table = NULL; + } + if (state->inodeIndexes) { +- inodeIndexHashFree(state->inodeIndexes); +- state->inodeIndexes = NULL; ++ inodeIndexHashFree(state->inodeIndexes); ++ state->inodeIndexes = NULL; + } + return RPMRC_OK; + } + + +-// have a prototype, warnings system ++/* have a prototype, warnings system */ + 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); +- } ++ /* 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"), 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); +- if (entry == NULL) { +- return NOT_FOUND; +- } +- rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); +- return offset; ++ rpmlog(RPMLOG_DEBUG, ++ _("reflink: bsearch(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); ++ if (entry == NULL) { ++ return NOT_FOUND; ++ } ++ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); ++ return offset; + } + +-static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) ++static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, ++ mode_t file_mode, rpmFsmOp op) + { + struct file_clone_range fcr; + rpm_loff_t size; +@@ -234,99 +249,119 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, + + reflink_state state = rpmPluginGetData(plugin); + if (state->table == NULL) { +- // no table means rpm is not in reflink format, so leave. Now. +- return RPMRC_OK; ++ /* no table means rpm is not in reflink format, so leave. Now. */ ++ return RPMRC_OK; + } + if (op == FA_TOUCH) { +- // we're not overwriting an existing file +- return RPMRC_OK; ++ /* we're not overwriting an existing file. */ ++ return RPMRC_OK; + } + fcr.dest_offset = 0; + if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { +- rpm_ino_t inode = rpmfiFInode(fi); +- /* 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)) { +- // entry is in table, use hard link +- char *fn = rpmfilesFN(state->files, hlix[0]); +- if (link(fn, path) != 0) { +- rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); +- free(fn); +- return RPMRC_FAIL; +- } +- free(fn); +- return RPMRC_PLUGIN_CONTENTS; +- } +- /* if we didn't hard link, then we'll track this inode as being created soon */ +- if (rpmfiFNlink(fi) > 1) { +- /* minor optimization: only store files with more than one link */ +- inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); +- } +- /* derived from wfd_open in fsm.c */ +- mode_t old_umask = umask(0577); +- dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); +- umask(old_umask); +- if (dst == -1) { +- rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); +- return RPMRC_FAIL; +- } +- size = rpmfiFSize(fi); +- if (size > 0) { +- /* round src_length down to fundamental_block_size multiple */ +- fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; +- if ((size % state->fundamental_block_size) > 0) { +- /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ +- fcr.src_length += state->fundamental_block_size; +- } +- fcr.src_fd = Fileno(state->fd); +- if (fcr.src_fd == -1) { +- close(dst); +- rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); +- return RPMRC_FAIL; +- } +- fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); +- if (fcr.src_offset == NOT_FOUND) { +- close(dst); +- rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); +- return RPMRC_FAIL; +- } +- rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); +- rc = ioctl(dst, FICLONERANGE, &fcr); +- if (rc) { +- rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); +- if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { +- close(dst); +- rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); +- return RPMRC_FAIL; +- } +- rpm_loff_t left = size; +- size_t len, read, written; +- while (left) { +- len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); +- read = Fread(state->buffer, len, 1, state->fd); +- if (read != len) { +- close(dst); +- rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); +- return RPMRC_FAIL; +- } +- written = write(dst, state->buffer, len); +- if (read != written) { +- close(dst); +- rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); +- return RPMRC_FAIL; +- } +- left -= len; +- } +- } else { +- /* reflink worked, so truncate */ +- rc = ftruncate(dst, size); +- if (rc) { +- rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); +- return RPMRC_FAIL; +- } +- } +- } +- close(dst); +- return RPMRC_PLUGIN_CONTENTS; ++ rpm_ino_t inode = rpmfiFInode(fi); ++ /* 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)) { ++ /* entry is in table, use hard link */ ++ char *fn = rpmfilesFN(state->files, hlix[0]); ++ if (link(fn, path) != 0) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to hard link %s -> %s due to %s\n"), ++ fn, path, strerror(errno)); ++ free(fn); ++ return RPMRC_FAIL; ++ } ++ free(fn); ++ return RPMRC_PLUGIN_CONTENTS; ++ } ++ /* if we didn't hard link, then we'll track this inode as being ++ * created soon ++ */ ++ if (rpmfiFNlink(fi) > 1) { ++ /* minor optimization: only store files with more than one link */ ++ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); ++ } ++ /* derived from wfd_open in fsm.c */ ++ mode_t old_umask = umask(0577); ++ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); ++ umask(old_umask); ++ if (dst == -1) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), ++ path, strerror(errno), rpmfiFFlags(fi)); ++ return RPMRC_FAIL; ++ } ++ size = rpmfiFSize(fi); ++ if (size > 0) { ++ /* round src_length down to fundamental_block_size multiple */ ++ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; ++ if ((size % state->fundamental_block_size) > 0) { ++ /* round up to next fundamental_block_size. We expect the data ++ * in the rpm to be similarly padded. ++ */ ++ fcr.src_length += state->fundamental_block_size; ++ } ++ fcr.src_fd = Fileno(state->fd); ++ if (fcr.src_fd == -1) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); ++ return RPMRC_FAIL; ++ } ++ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); ++ if (fcr.src_offset == NOT_FOUND) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); ++ return RPMRC_FAIL; ++ } ++ rpmlog(RPMLOG_DEBUG, ++ _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), ++ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); ++ rc = ioctl(dst, FICLONERANGE, &fcr); ++ if (rc) { ++ rpmlog(RPMLOG_WARNING, ++ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), ++ path, rc, errno, strerror(errno)); ++ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: unable to seek on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ rpm_loff_t left = size; ++ size_t len, read, written; ++ while (left) { ++ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); ++ read = Fread(state->buffer, len, 1, state->fd); ++ if (read != len) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: short read on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ written = write(dst, state->buffer, len); ++ if (read != written) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: short write on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ left -= len; ++ } ++ } else { ++ /* reflink worked, so truncate */ ++ rc = ftruncate(dst, size); ++ if (rc) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to truncate %s to %ld due to %s\n"), ++ path, size, strerror(errno)); ++ return RPMRC_FAIL; ++ } ++ } ++ } ++ close(dst); ++ return RPMRC_PLUGIN_CONTENTS; + } + return RPMRC_OK; + } +diff --git a/rpm2extents.c b/rpm2extents.c +index 5662b86a6..c111be0a2 100644 +--- a/rpm2extents.c ++++ b/rpm2extents.c +@@ -24,7 +24,7 @@ + #include "debug.h" + + /* hash of void * (pointers) to file digests to offsets within output. +- The length of the key depends on what the FILEDIGESTALGO is. ++ * The length of the key depends on what the FILEDIGESTALGO is. + */ + #undef HASHTYPE + #undef HTKEYTYPE +@@ -34,7 +34,9 @@ + #include "lib/rpmhash.H" + #include "lib/rpmhash.C" + +-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ ++/* magic value at end of file (64 bits) that indicates this is a transcoded ++ * rpm. ++ */ + #define MAGIC 3472329499408095051 + + struct digestoffset { +@@ -64,77 +66,54 @@ static int digestor( + int algo; + rpmRC rc = RPMRC_FAIL; + +- for (algo = 0; algo < algos_len; algo++) +- { +- fdInitDigest(fdi, algos[algo], 0); ++ 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; ++ if (fdilength == -1) { ++ fprintf(stderr, _("digest cat failed\n")); ++ goto exit; + } + + len = sizeof(fdilength); +- if (Fwrite(&fdilength, len, 1, validationo) != len) +- { +- fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); +- goto exit; ++ if (Fwrite(&fdilength, len, 1, validationo) != 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")); +- goto exit; ++ if (Fwrite(&algos_len, len, 1, validationo) != len) { ++ fprintf(stderr, _("Unable to write number of validation digests\n")); ++ goto exit; + } +- for (algo = 0; algo < algos_len; algo++) +- { +- fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); +- +- algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); +- algo_name_len = (uint32_t)strlen(algo_name); +- algo_digest_len = (uint32_t)filedigest_len; +- +- len = sizeof(algo_name_len); +- if (Fwrite(&algo_name_len, len, 1, validationo) != len) +- { +- fprintf( +- stderr, +- _("Unable to write validation algo name length\n") +- ); +- goto exit; +- } +- len = sizeof(algo_digest_len); +- if (Fwrite(&algo_digest_len, len, 1, validationo) != len) +- { +- fprintf( +- stderr, +- _("Unable to write number of bytes for validation 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")); +- goto exit; +- } +- if ( +- Fwrite( +- filedigest, +- algo_digest_len, +- 1, +- validationo +- ) != algo_digest_len +- ) +- { +- fprintf( +- stderr, +- _("Unable to write validation digest value %u, %zu\n"), +- algo_digest_len, +- filedigest_len +- ); +- goto exit; +- } ++ for (algo = 0; algo < algos_len; algo++) { ++ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); ++ ++ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); ++ algo_name_len = (uint32_t)strlen(algo_name); ++ algo_digest_len = (uint32_t)filedigest_len; ++ ++ len = sizeof(algo_name_len); ++ if (Fwrite(&algo_name_len, len, 1, validationo) != len) { ++ fprintf(stderr, ++ _("Unable to write validation algo name length\n")); ++ goto exit; ++ } ++ len = sizeof(algo_digest_len); ++ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) { ++ fprintf(stderr, ++ _("Unable to write number of bytes for validation 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")); ++ goto exit; ++ } ++ if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) { ++ fprintf(stderr, ++ _("Unable to write validation digest value %u, %zu\n"), ++ algo_digest_len, filedigest_len); ++ goto exit; ++ } + } + rc = RPMRC_OK; + exit: +@@ -145,23 +124,20 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) + { + uint32_t diglen; + /* GNU C extension: can use diglen from outer context */ +- int digestSetCmp(const unsigned char * a, const unsigned char * b) +- { +- return memcmp(a, b, diglen); ++ int digestSetCmp(const unsigned char * a, const unsigned char * b) { ++ return memcmp(a, b, diglen); + } + +- unsigned int digestSetHash(const unsigned char * digest) +- { ++ unsigned int digestSetHash(const unsigned char * digest) { + /* assumes sizeof(unsigned int) < diglen */ + return *(unsigned int *)digest; + } + +- int digestoffsetCmp(const void * a, const void * b) +- { +- return digestSetCmp( +- ((struct digestoffset *)a)->digest, +- ((struct digestoffset *)b)->digest +- ); ++ int digestoffsetCmp(const void * a, const void * b) { ++ return digestSetCmp( ++ ((struct digestoffset *)a)->digest, ++ ((struct digestoffset *)b)->digest ++ ); + } + + FD_t fdo; +@@ -179,65 +155,52 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) + + fdo = fdDup(STDOUT_FILENO); + +- if (rpmReadPackageRaw(fdi, &sigh, &h)) +- { +- fprintf(stderr, _("Error reading package\n")); +- exit(EXIT_FAILURE); ++ if (rpmReadPackageRaw(fdi, &sigh, &h)) { ++ fprintf(stderr, _("Error reading package\n")); ++ exit(EXIT_FAILURE); + } + + if (rpmLeadWrite(fdo, h)) + { +- fprintf( +- stderr, +- _("Unable to write package lead: %s\n"), +- Fstrerror(fdo) +- ); +- exit(EXIT_FAILURE); ++ fprintf(stderr, _("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)); +- exit(EXIT_FAILURE); ++ if (rpmWriteSignature(fdo, sigh)) { ++ fprintf(stderr, _("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)); +- exit(EXIT_FAILURE); ++ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { ++ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); ++ 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); ++ { ++ 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); + +- if (gzdi == NULL) +- { +- fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); +- exit(EXIT_FAILURE); ++ if (gzdi == NULL) { ++ fprintf(stderr, _("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 +- ); ++ rpmfi 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?) +- */ ++ * now?) ++ */ + diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi)); +- digestSet ds = digestSetCreate( +- rpmfiFC(fi), +- digestSetHash, +- digestSetCmp, +- NULL +- ); ++ digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, ++ NULL); + struct digestoffset offsets[rpmfiFC(fi)]; + pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); + +@@ -247,139 +210,114 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) + + zeros = xcalloc(fundamental_block_size, 1); + +- 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) +- { +- fprintf(stderr, _("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) +- { +- fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); +- goto exit; +- } +- pos += size; ++ 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) { ++ fprintf(stderr, _("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) { ++ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); ++ goto exit; ++ } ++ pos += size; + } + 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); + + len = sizeof(offset_ix); +- if (Fwrite(&offset_ix, len, 1, fdo) != len) +- { +- fprintf(stderr, _("Unable to write length of table\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (Fwrite(&offset_ix, len, 1, fdo) != len) { ++ fprintf(stderr, _("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")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (Fwrite(&diglen, len, 1, fdo) != len) { ++ fprintf(stderr, _("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")); +- rc = RPMRC_FAIL; +- goto exit; +- } +- if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) +- { +- fprintf(stderr, _("Unable to write offset\n")); +- rc = RPMRC_FAIL; +- goto exit; +- } ++ for (int x = 0; x < offset_ix; x++) { ++ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { ++ fprintf(stderr, _("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")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } + } + validation_pos = ( +- pos + sizeof(offset_ix) + sizeof(diglen) + +- offset_ix * (diglen + sizeof(rpm_loff_t)) ++ pos + sizeof(offset_ix) + sizeof(diglen) + ++ offset_ix * (diglen + sizeof(rpm_loff_t)) + ); + + ssize_t validation_len = ufdCopy(validationi, fdo); +- if (validation_len == -1) +- { +- fprintf(stderr, _("digest table ufdCopy failed\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (validation_len == -1) { ++ fprintf(stderr, _("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 ++ * 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) +- { +- fprintf(stderr, _("Unable to write final padding\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ 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")); ++ rc = RPMRC_FAIL; ++ goto exit; + } + zeros = _free(zeros); +- if (Fwrite(&pos, len, 1, fdo) != len) +- { +- fprintf(stderr, _("Unable to write offset of digest table\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (Fwrite(&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 table\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (Fwrite(&validation_pos, len, 1, fdo) != len) { ++ fprintf(stderr, _("Unable to write offset of validation table\n")); ++ rc = RPMRC_FAIL; ++ goto exit; + } + uint64_t magic = MAGIC; + len = sizeof(magic); +- if (Fwrite(&magic, len, 1, fdo) != len) +- { +- fprintf(stderr, _("Unable to write magic\n")); +- rc = RPMRC_FAIL; +- goto exit; ++ if (Fwrite(&magic, len, 1, fdo) != len) { ++ fprintf(stderr, _("Unable to write magic\n")); ++ rc = RPMRC_FAIL; ++ goto exit; + } + + exit: +@@ -389,8 +327,7 @@ exit: + return rc; + } + +-int main(int argc, char *argv[]) +-{ ++int main(int argc, char *argv[]) { + rpmRC rc; + int cprc = 0; + uint8_t algos[argc - 1]; +@@ -402,118 +339,95 @@ int main(int argc, char *argv[]) + xsetprogname(argv[0]); /* Portability call -- see system.h */ + rpmReadConfigFiles(NULL, NULL); + +- 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 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { ++ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); ++ exit(EXIT_FAILURE); + } + +- if (argc == 1) +- { +- fprintf( +- stderr, +- _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") +- ); +- exit(EXIT_FAILURE); ++ if (argc == 1) { ++ fprintf(stderr, ++ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); ++ exit(EXIT_FAILURE); + } + +- for (int x = 0; x < (argc - 1); x++) +- { +- if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) +- { +- fprintf( +- stderr, +- _("Unable to resolve '%s' as a digest algorithm, exiting\n"), +- argv[x + 1] +- ); +- exit(EXIT_FAILURE); +- } ++ for (int x = 0; x < (argc - 1); x++) { ++ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) ++ { ++ fprintf(stderr, ++ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), ++ argv[x + 1]); ++ exit(EXIT_FAILURE); ++ } + } + + +- if (pipe(mainpipefd) == -1) +- { +- fprintf(stderr, _("Main pipe failure\n")); +- exit(EXIT_FAILURE); ++ 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); ++ 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, argc - 1); +- Fclose(validationo); +- Fclose(fdo); +- Fclose(fdi); ++ 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, argc - 1); ++ Fclose(validationo); ++ Fclose(fdo); ++ Fclose(fdi); + } else { +- /* parent: main program */ +- 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. */ +- 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 failed\n")); +- 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; +- } ++ /* parent: main program */ ++ 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. ++ */ ++ 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 failed\n")); ++ 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; ++ } + } +- if (rc != RPMRC_OK) +- { +- /* translate rpmRC into generic failure return code. */ +- return EXIT_FAILURE; ++ if (rc != RPMRC_OK) { ++ /* translate rpmRC into generic failure return code. */ ++ return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } +-- +2.35.1 + diff --git a/0003-Use-lower-level-headerPut-for-file-signing.patch b/0003-Use-lower-level-headerPut-for-file-signing.patch new file mode 100644 index 0000000..129f420 --- /dev/null +++ b/0003-Use-lower-level-headerPut-for-file-signing.patch @@ -0,0 +1,58 @@ +From 492823ca53f5666b82e94fcfdd422bdcd67005cb Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0003-Verify-packages-before-signing-RhBug-1646388.patch b/0003-Verify-packages-before-signing-RhBug-1646388.patch new file mode 100644 index 0000000..c950748 --- /dev/null +++ b/0003-Verify-packages-before-signing-RhBug-1646388.patch @@ -0,0 +1,114 @@ +From df089e178da0918dc74a8572a99324b0987bce30 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com> +References: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Mon, 18 Mar 2019 15:56:34 +0200 +Subject: [PATCH 3/3] Verify packages before signing (RhBug:1646388) + +Permitting corrupted packages to be signed is bad business for everybody +involved, this is something we should've always done. Besides being an +actual security risk, it can lead to odd results with verification +especially with the payload digest on signed packages. + +One point worth noting is that this means that pre 4.14-packages cannot +be signed in FIPS mode now because there's no way to validate the package +payload range due to MD5 being disabled. This seems like a feature and +not a limitation, so disabler for the verify step intentionally left out. + +Optimally we'd verify the package on the same read that's passed +to gpg but for simplicitys sake that's left as an future exercise, +now we simply read the package twice. +--- + sign/rpmgensig.c | 32 ++++++++++++++++++++++++++++++++ + tests/rpmsigdig.at | 20 ++++++++++++++++++++ + 2 files changed, 52 insertions(+) + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 2bcbab768..5be542001 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -21,6 +21,7 @@ + + #include "lib/rpmlead.h" + #include "lib/signature.h" ++#include "lib/rpmvs.h" + #include "sign/rpmsignfiles.h" + + #include "debug.h" +@@ -489,6 +490,31 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) + #endif + } + ++static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata) ++{ ++ char **msg = cbdata; ++ if (sinfo->rc && *msg == NULL) ++ *msg = rpmsinfoMsg(sinfo); ++ return (sinfo->rc != RPMRC_FAIL); ++} ++ ++/* Require valid digests on entire package for signing. */ ++static int checkPkg(FD_t fd, char **msg) ++{ ++ int rc; ++ struct rpmvs_s *vs = rpmvsCreate(RPMSIG_DIGEST_TYPE, 0, NULL); ++ off_t offset = Ftell(fd); ++ ++ Fseek(fd, 0, SEEK_SET); ++ rc = rpmpkgRead(vs, fd, NULL, NULL, msg); ++ if (!rc) ++ rc = rpmvsVerify(vs, RPMSIG_DIGEST_TYPE, msgCb, msg); ++ Fseek(fd, offset, SEEK_SET); ++ ++ rpmvsFree(vs); ++ return rc; ++} ++ + /** \ingroup rpmcli + * Create/modify elements in signature header. + * @param rpm path to package +@@ -519,6 +545,12 @@ static int rpmSign(const char *rpm, int deleting, int signfiles) + if (manageFile(&fd, rpm, O_RDWR)) + goto exit; + ++ /* Ensure package is intact before attempting to sign */ ++ if ((rc = checkPkg(fd, &msg))) { ++ rpmlog(RPMLOG_ERR, "not signing corrupt package %s: %s\n", rpm, msg); ++ goto exit; ++ } ++ + if ((rc = rpmLeadRead(fd, &msg)) != RPMRC_OK) { + rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg); + goto exit; +diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at +index 413c3d2c8..e93420306 100644 +--- a/tests/rpmsigdig.at ++++ b/tests/rpmsigdig.at +@@ -472,3 +472,23 @@ run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64-sign + [], + []) + AT_CLEANUP ++ ++AT_SETUP([rpmsign --addsign ]) ++AT_KEYWORDS([rpmsign signature]) ++AT_CHECK([ ++RPMDB_CLEAR ++RPMDB_INIT ++rm -rf "${TOPDIR}" ++ ++pkg="hello-2.0-1.x86_64.rpm" ++cp "${RPMTEST}"/data/RPMS/${pkg} "${RPMTEST}"/tmp/${pkg} ++dd if=/dev/zero of="${RPMTEST}"/tmp/${pkg} \ ++ conv=notrunc bs=1 seek=333 count=4 2> /dev/null ++run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}/tmp/${pkg}" ++], ++[1], ++[/home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm: ++], ++[error: not signing corrupt package /home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm: MD5 digest: BAD (Expected 007ca1d8b35cca02a1854ba301c5432e != 137ca1d8b35cca02a1854ba301c5432e) ++]) ++AT_CLEANUP +-- +2.20.1 + diff --git a/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch b/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch new file mode 100644 index 0000000..5bdc8f0 --- /dev/null +++ b/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch @@ -0,0 +1,30 @@ +From 00a0afd5e079a73ef6871f1538f34fa4e67892e6 Mon Sep 17 00:00:00 2001 +Message-Id: <00a0afd5e079a73ef6871f1538f34fa4e67892e6.1573552234.git.pmatilai@redhat.com> +In-Reply-To: +References: +From: Mark Wielaard +Date: Mon, 17 Jun 2019 11:23:26 +0200 +Subject: [PATCH 3/3] debugedit: Make sure .debug_line old/new idx start equal. + +Found by running the debugedit tests under valgrind. +If the old and new .debug_line offset isn't changed then we might +write out an uninitialized new_idx. +--- + tools/debugedit.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/debugedit.c b/tools/debugedit.c +index 84483ef5e..9f8dcd0fb 100644 +--- a/tools/debugedit.c ++++ b/tools/debugedit.c +@@ -1177,6 +1177,7 @@ get_line_table (DSO *dso, size_t off, struct line_table **table) + *table = NULL; + + t->old_idx = off; ++ t->new_idx = off; + t->size_diff = 0; + t->replace_dirs = false; + t->replace_files = false; +-- +2.23.0 + diff --git a/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch b/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch new file mode 100644 index 0000000..7e31e41 --- /dev/null +++ b/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch @@ -0,0 +1,109 @@ +From 0b1456ed4c00a021389acea4b6b10d475986b660 Mon Sep 17 00:00:00 2001 +Message-Id: <0b1456ed4c00a021389acea4b6b10d475986b660.1571920849.git.pmatilai@redhat.com> +In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 4 Oct 2018 18:05:37 +0300 +Subject: [PATCH 4/5] Bump the minimum Python version requirement to 2.7 + +Older Python versions are long since past their EOL, we don't need to +support them either. Python 2.7 is also the least incompatible version +compared to Python 3, going forward. Nuke the now unnecessary compat +macros. + +(cherry picked from commit 3f3cb3eabf7bb49dcc6e691601f89500b3487e06) +--- + configure.ac | 2 +- + python/header-py.c | 4 ++-- + python/rpmsystem-py.h | 33 --------------------------------- + python/spec-py.c | 2 +- + 4 files changed, 4 insertions(+), 37 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 34ea85f9f..4d1a48e5f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -800,7 +800,7 @@ esac], + + WITH_PYTHON_SUBPACKAGE=0 + AS_IF([test "$enable_python" = yes],[ +- AM_PATH_PYTHON([2.6],[ ++ AM_PATH_PYTHON([2.7],[ + PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}], [WITH_PYTHON_SUBPACKAGE=1]) + AC_SUBST(PYTHON_CFLAGS) + AC_SUBST(PYTHON_LIB) +diff --git a/python/header-py.c b/python/header-py.c +index 628b48534..c9d54e869 100644 +--- a/python/header-py.c ++++ b/python/header-py.c +@@ -376,8 +376,8 @@ static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) + + if (obj == NULL) { + h = headerNew(); +- } else if (CAPSULE_CHECK(obj)) { +- h = CAPSULE_EXTRACT(obj, "rpm._C_Header"); ++ } else if (PyCapsule_CheckExact(obj)) { ++ h = PyCapsule_GetPointer(obj, "rpm._C_Header"); + headerLink(h); + } else if (hdrObject_Check(obj)) { + h = headerCopy(((hdrObject*) obj)->h); +diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h +index c8423e3dc..955d60cd3 100644 +--- a/python/rpmsystem-py.h ++++ b/python/rpmsystem-py.h +@@ -9,39 +9,6 @@ + #include + #include + +-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0205 +-typedef ssize_t Py_ssize_t; +-typedef Py_ssize_t (*lenfunc)(PyObject *); +-#endif +- +-/* Compatibility macros for Python < 2.6 */ +-#ifndef PyVarObject_HEAD_INIT +-#define PyVarObject_HEAD_INIT(type, size) \ +- PyObject_HEAD_INIT(type) size, +-#endif +- +-#ifndef Py_TYPE +-#define Py_TYPE(o) ((o)->ob_type) +-#endif +- +-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0206 +-#define PyBytes_Check PyString_Check +-#define PyBytes_FromString PyString_FromString +-#define PyBytes_FromStringAndSize PyString_FromStringAndSize +-#define PyBytes_Size PyString_Size +-#define PyBytes_AsString PyString_AsString +-#endif +- +-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) >= 0x0207 +-#define CAPSULE_BUILD(ptr,name) PyCapsule_New(ptr, name, NULL) +-#define CAPSULE_CHECK(obj) PyCapsule_CheckExact(obj) +-#define CAPSULE_EXTRACT(obj,name) PyCapsule_GetPointer(obj, name) +-#else +-#define CAPSULE_BUILD(ptr,name) PyCObject_FromVoidPtr(ptr, NULL) +-#define CAPSULE_CHECK(obj) PyCObject_Check(obj) +-#define CAPSULE_EXTRACT(obj,name) PyCObject_AsVoidPtr(obj) +-#endif +- + /* For Python 3, use the PyLong type throughout in place of PyInt */ + #if PY_MAJOR_VERSION >= 3 + #define PyInt_Check PyLong_Check +diff --git a/python/spec-py.c b/python/spec-py.c +index fa7e58928..4efdbf4bf 100644 +--- a/python/spec-py.c ++++ b/python/spec-py.c +@@ -34,7 +34,7 @@ static PyObject *makeHeader(Header h) + PyObject *rpmmod = PyImport_ImportModuleNoBlock("rpm"); + if (rpmmod == NULL) return NULL; + +- PyObject *ptr = CAPSULE_BUILD(h, "rpm._C_Header"); ++ PyObject *ptr = PyCapsule_New(h, "rpm._C_Header", NULL); + PyObject *hdr = PyObject_CallMethod(rpmmod, "hdr", "(O)", ptr); + Py_XDECREF(ptr); + Py_XDECREF(rpmmod); +-- +2.21.0 + diff --git a/0004-Fix-printf-formatting-in-reflink.c.patch b/0004-Fix-printf-formatting-in-reflink.c.patch new file mode 100644 index 0000000..c33f3d5 --- /dev/null +++ b/0004-Fix-printf-formatting-in-reflink.c.patch @@ -0,0 +1,27 @@ +From 15127592f8cc3221129f61b79319d88c7727bec3 Mon Sep 17 00:00:00 2001 +From: Matthew Almond +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 + diff --git a/0004-Place-file-signatures-into-the-signature-header-wher.patch b/0004-Place-file-signatures-into-the-signature-header-wher.patch new file mode 100644 index 0000000..12f8d8b --- /dev/null +++ b/0004-Place-file-signatures-into-the-signature-header-wher.patch @@ -0,0 +1,329 @@ +From f354c5a4265ddad758ad41abfb2f5fe174a54c69 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch b/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch new file mode 100644 index 0000000..fe0ffef --- /dev/null +++ b/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch @@ -0,0 +1,41 @@ +From 98470eccf09b80ed11528ac893852d649c50be72 Mon Sep 17 00:00:00 2001 +Message-Id: <98470eccf09b80ed11528ac893852d649c50be72.1571920849.git.pmatilai@redhat.com> +In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Fri, 5 Oct 2018 14:05:27 +0300 +Subject: [PATCH 5/5] Drop an unnecessary Python 2 vs 3 incompatibility from + the test + +Python 2 speaks about 'type' whereas 3 speaks about 'class', which from +our perspective is just unnecessary pain with no gain. + +(cherry picked from commit ff3d8ac2e5cb4456ad1355f227f3ccef08e01972) +--- + tests/rpmpython.at | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/tests/rpmpython.at b/tests/rpmpython.at +index ae020ae95..bc42e49e4 100644 +--- a/tests/rpmpython.at ++++ b/tests/rpmpython.at +@@ -92,7 +92,7 @@ h['arch'] = 'noarch' + myprint(h['nevra']) + del h['epoch'] + myprint(h['nevra']) +-for a in ['name', 'bugurl', '__class__', '__foo__', ]: ++for a in ['name', 'bugurl', '__foo__', ]: + try: + x = getattr(h, a) + myprint(x) +@@ -103,7 +103,6 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]: + testpkg-1.0-1.noarch + testpkg + None +- + 'rpm.hdr' object has no attribute '__foo__'] + ) + +-- +2.21.0 + diff --git a/0005-Unbreak-file-signing-from-previous-commit.patch b/0005-Unbreak-file-signing-from-previous-commit.patch new file mode 100644 index 0000000..ce68ba5 --- /dev/null +++ b/0005-Unbreak-file-signing-from-previous-commit.patch @@ -0,0 +1,30 @@ +From: Panu Matilainen +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 + diff --git a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch new file mode 100644 index 0000000..282dff0 --- /dev/null +++ b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch @@ -0,0 +1,73 @@ +From fd4060dcfbe4127fb0d19f1878d0d8b9f34c7b9a Mon Sep 17 00:00:00 2001 +From: chantra +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 ++# ++# 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 + diff --git a/0006-Assume-failure-in-rpmSignFiles.patch b/0006-Assume-failure-in-rpmSignFiles.patch new file mode 100644 index 0000000..1b987f5 --- /dev/null +++ b/0006-Assume-failure-in-rpmSignFiles.patch @@ -0,0 +1,71 @@ +From bcdd8505e792fd67c1480d43d987b92a61710e53 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0006-rpm2extents-verify-package-signature-during-transcod.patch b/0006-rpm2extents-verify-package-signature-during-transcod.patch new file mode 100644 index 0000000..c2eb42c --- /dev/null +++ b/0006-rpm2extents-verify-package-signature-during-transcod.patch @@ -0,0 +1,431 @@ +From ea1177fcef609519f0c2377ebee236001d2a8fae Mon Sep 17 00:00:00 2001 +From: chantra +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 + #include /* rpmReadPackageFile .. */ ++#include + #include + #include + #include +@@ -10,6 +12,7 @@ + + #include + #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]* "); + +- 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 + diff --git a/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch b/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch new file mode 100644 index 0000000..b70d845 --- /dev/null +++ b/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch @@ -0,0 +1,108 @@ +From 0a7318ab4467d3156723c7a265dbd3456b8d1e20 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 /* rpmlog */ +-#include /* rnibble */ ++#include + #include /* 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 + diff --git a/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch b/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch new file mode 100644 index 0000000..07c84fd --- /dev/null +++ b/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch @@ -0,0 +1,282 @@ +From a4755a5ed793ca439bb23b804ba7a8ab080ff110 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0008-Eliminate-redundant-signature-length-calculation-fun.patch b/0008-Eliminate-redundant-signature-length-calculation-fun.patch new file mode 100644 index 0000000..1d7daa4 --- /dev/null +++ b/0008-Eliminate-redundant-signature-length-calculation-fun.patch @@ -0,0 +1,105 @@ +From ff2fb80469e9aa478ea4de3eae5d9c13ca411382 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch b/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch new file mode 100644 index 0000000..ddbf31d --- /dev/null +++ b/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch @@ -0,0 +1,116 @@ +From c705a6287f8c7fb5e37dad0ac87257731a41fa69 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0009-Drop-redundant-check-on-hash-algo-name.patch b/0009-Drop-redundant-check-on-hash-algo-name.patch new file mode 100644 index 0000000..627511c --- /dev/null +++ b/0009-Drop-redundant-check-on-hash-algo-name.patch @@ -0,0 +1,29 @@ +From efd41edd0c9ba848814a5434d986338c1691418e Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch new file mode 100644 index 0000000..a0e9757 --- /dev/null +++ b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch @@ -0,0 +1,70 @@ +From 44b86112136e4804eb606636cbcb4ae847cad773 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0010-Drop-redundant-check-on-hash-algo-name.patch b/0010-Drop-redundant-check-on-hash-algo-name.patch new file mode 100644 index 0000000..e619007 --- /dev/null +++ b/0010-Drop-redundant-check-on-hash-algo-name.patch @@ -0,0 +1,40 @@ +From 3461bd52ef2d403de1c420962aac52834f6e4b34 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch b/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch new file mode 100644 index 0000000..98987d6 --- /dev/null +++ b/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch @@ -0,0 +1,204 @@ +From 7da1e826ccb08fdd404524146736b3f12a473e31 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch b/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch new file mode 100644 index 0000000..d86b96b --- /dev/null +++ b/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch @@ -0,0 +1,129 @@ +From 9e1a49197a6ddd0e984c12c9dc15fe7af435b611 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 "), +@@ -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 + diff --git a/0011-rpm2extents-Perform-digest-computation-within-the-va.patch b/0011-rpm2extents-Perform-digest-computation-within-the-va.patch new file mode 100644 index 0000000..ea98bed --- /dev/null +++ b/0011-rpm2extents-Perform-digest-computation-within-the-va.patch @@ -0,0 +1,389 @@ +From 86776bf17f1644c76fdf8b87042645cf77bd3873 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch b/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch new file mode 100644 index 0000000..f287e92 --- /dev/null +++ b/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch @@ -0,0 +1,201 @@ +From 031b8481a0dfe875e9cf0f5d440b9379a62651a6 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 ]) ++AT_SETUP([rpmsign --addsign --rpmv3 ]) + 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 ]) ++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 ]) +-- +2.27.0 + diff --git a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch new file mode 100644 index 0000000..6a48dc8 --- /dev/null +++ b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch @@ -0,0 +1,299 @@ +From ecab80b80e3917d3acf0f909c9cc84691a207fc0 Mon Sep 17 00:00:00 2001 +From: chantra +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 ++#include ++ ++#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 ++ ++/* 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 + #include "lib/rpmlib.h" + #include "lib/rpmplugin.h" ++#include "lib/rpmextents_internal.h" + #include "lib/rpmte_internal.h" + #include + #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 +@@ -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 + diff --git a/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch b/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch new file mode 100644 index 0000000..70975fa --- /dev/null +++ b/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch @@ -0,0 +1,27 @@ +From 5e11a52627882efe6a15622ec256835a821e3eff Mon Sep 17 00:00:00 2001 +From: Igor Kanyuka +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 + diff --git a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch new file mode 100644 index 0000000..56bb554 --- /dev/null +++ b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch @@ -0,0 +1,109 @@ +From 5c97d7f83f56015d6a37934cee4e55ed8d747890 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0014-Drop-support-for-dmalloc.patch b/0014-Drop-support-for-dmalloc.patch new file mode 100644 index 0000000..55dd7d4 --- /dev/null +++ b/0014-Drop-support-for-dmalloc.patch @@ -0,0 +1,48 @@ +From 6398807623ca24eafac0607b3d09b244cc5dfd5d Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + +-#ifdef DMALLOC +-#include +-#endif +- + #define RPMDBG_TOSTR(a) RPMDBG_TOSTR_ARG(a) + #define RPMDBG_TOSTR_ARG(a) #a + +-- +2.27.0 + diff --git a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch new file mode 100644 index 0000000..737368d --- /dev/null +++ b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch @@ -0,0 +1,79 @@ +From ad46eb4132cbd2c4ee23686a1c52f2fc57afffc5 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch b/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch new file mode 100644 index 0000000..8183898 --- /dev/null +++ b/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch @@ -0,0 +1,33 @@ +From b2fc576828af873a1993bdaa2fcb7c860b94df3e Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch new file mode 100644 index 0000000..e6dae81 --- /dev/null +++ b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch @@ -0,0 +1,28 @@ +From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch new file mode 100644 index 0000000..89845cb --- /dev/null +++ b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch @@ -0,0 +1,136 @@ +From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 ]], ++ [[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 "), + N_("") }, +@@ -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 + diff --git a/0016-test-new-runroot_plugins-function-to-run-command-in-.patch b/0016-test-new-runroot_plugins-function-to-run-command-in-.patch new file mode 100644 index 0000000..1bd2253 --- /dev/null +++ b/0016-test-new-runroot_plugins-function-to-run-command-in-.patch @@ -0,0 +1,32 @@ +From e04b5d20a6d8c64dba7416edba8e435145a5d7d3 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch new file mode 100644 index 0000000..ae64146 --- /dev/null +++ b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch @@ -0,0 +1,51 @@ +From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch b/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch new file mode 100644 index 0000000..20e572f --- /dev/null +++ b/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch @@ -0,0 +1,63 @@ +From e86207d3395e0963f19363b047551100569900df Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch new file mode 100644 index 0000000..7a5c5fd --- /dev/null +++ b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch @@ -0,0 +1,97 @@ +From 048db395b6de8544dc88231f0afebee8570daee6 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch new file mode 100644 index 0000000..77a8b31 --- /dev/null +++ b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch @@ -0,0 +1,52 @@ +From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 "), ++ N_("") }, + #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 + diff --git a/0019-Implement-rpmSignVerity.patch b/0019-Implement-rpmSignVerity.patch new file mode 100644 index 0000000..70e873a --- /dev/null +++ b/0019-Implement-rpmSignVerity.patch @@ -0,0 +1,243 @@ +From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 ++ */ ++ ++#include "system.h" ++ ++#include /* RPMSIGTAG & related */ ++#include /* rpmlog */ ++#include ++#include /* rpmDigestLength */ ++#include "lib/header.h" /* HEADERGET_MINMEM */ ++#include "lib/header_internal.h" ++#include "lib/rpmtypes.h" /* rpmRC */ ++#include ++#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(¶ms, 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, ++ ¶ms, &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 ++#include ++ ++#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 + diff --git a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch new file mode 100644 index 0000000..1e98fd1 --- /dev/null +++ b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch @@ -0,0 +1,156 @@ +From 5f762af17c6e72e86e4710975dcdfd71fc5d1b07 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch new file mode 100644 index 0000000..b099eaf --- /dev/null +++ b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch @@ -0,0 +1,95 @@ +From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch b/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch new file mode 100644 index 0000000..24f0711 --- /dev/null +++ b/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch @@ -0,0 +1,35 @@ +From 13aea986ada3ed7d26182d81d8878bcc807a6ab5 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch new file mode 100644 index 0000000..6caee37 --- /dev/null +++ b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch @@ -0,0 +1,210 @@ +From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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(¶ms, 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, ¶ms, &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(¶ms, 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, +- ¶ms, &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 + diff --git a/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch b/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch new file mode 100644 index 0000000..250aa6b --- /dev/null +++ b/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch @@ -0,0 +1,43 @@ +From 3e363f853a4379e0199db81f777f4b610e158eae Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0022-reflink-fix-support-for-hardlinks.patch b/0022-reflink-fix-support-for-hardlinks.patch new file mode 100644 index 0000000..e4d6558 --- /dev/null +++ b/0022-reflink-fix-support-for-hardlinks.patch @@ -0,0 +1,132 @@ +From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch new file mode 100644 index 0000000..dba0ca6 --- /dev/null +++ b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch @@ -0,0 +1,162 @@ +From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0023-Process-verity-tag-on-package-read.patch b/0023-Process-verity-tag-on-package-read.patch new file mode 100644 index 0000000..4f682c7 --- /dev/null +++ b/0023-Process-verity-tag-on-package-read.patch @@ -0,0 +1,189 @@ +From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + #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 + diff --git a/0023-rpm2extents-Improve-logging.patch b/0023-rpm2extents-Improve-logging.patch new file mode 100644 index 0000000..8ac52f7 --- /dev/null +++ b/0023-rpm2extents-Improve-logging.patch @@ -0,0 +1,393 @@ +From a2c959085250d186c54130b78af076095c3d3cd3 Mon Sep 17 00:00:00 2001 +From: chantra +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]* "); + + 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 + diff --git a/0024-Generate-a-zero-length-signature-for-symlinks.patch b/0024-Generate-a-zero-length-signature-for-symlinks.patch new file mode 100644 index 0000000..2fc3f5a --- /dev/null +++ b/0024-Generate-a-zero-length-signature-for-symlinks.patch @@ -0,0 +1,33 @@ +From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); + params.version = 1; +-- +2.27.0 + diff --git a/0024-rpm2extents-create-footer-struct-and-helpers.patch b/0024-rpm2extents-create-footer-struct-and-helpers.patch new file mode 100644 index 0000000..baabce0 --- /dev/null +++ b/0024-rpm2extents-create-footer-struct-and-helpers.patch @@ -0,0 +1,200 @@ +From aabaa6c6587c37b84a1b9cfd98bff31f1b69345e Mon Sep 17 00:00:00 2001 +From: chantra +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 + #include ++#include ++#include ++ + + #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 + ++/** \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 + diff --git a/0025-extents-move-more-functions-helpers-behind-rpmextent.patch b/0025-extents-move-more-functions-helpers-behind-rpmextent.patch new file mode 100644 index 0000000..71a54e6 --- /dev/null +++ b/0025-extents-move-more-functions-helpers-behind-rpmextent.patch @@ -0,0 +1,176 @@ +From 8235711d92d8783abe63d6e4f29afd495fc4b22e Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/0025-rpmsignverity.c-Clean-up-debug-logging.patch new file mode 100644 index 0000000..bb6e4f3 --- /dev/null +++ b/0025-rpmsignverity.c-Clean-up-debug-logging.patch @@ -0,0 +1,40 @@ +From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0026-fix-integer-underflow-in-vfyFDCb.patch b/0026-fix-integer-underflow-in-vfyFDCb.patch new file mode 100644 index 0000000..5fe1900 --- /dev/null +++ b/0026-fix-integer-underflow-in-vfyFDCb.patch @@ -0,0 +1,25 @@ +From 3372e6c917e54b3a84c04ca4274000da04a98e86 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/0026-fsverity-add-tag-for-fsverity-algorithm.patch new file mode 100644 index 0000000..d1c12c9 --- /dev/null +++ b/0026-fsverity-add-tag-for-fsverity-algorithm.patch @@ -0,0 +1,161 @@ +From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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(¶ms, 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 + diff --git a/0027-plugins-fsverity-Install-fsverity-signatures.patch b/0027-plugins-fsverity-Install-fsverity-signatures.patch new file mode 100644 index 0000000..aa78311 --- /dev/null +++ b/0027-plugins-fsverity-Install-fsverity-signatures.patch @@ -0,0 +1,281 @@ +From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 ++ */ ++ ++#include "system.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + diff --git a/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch b/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch new file mode 100644 index 0000000..7bb79b2 --- /dev/null +++ b/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch @@ -0,0 +1,169 @@ +From 1e0850cf7649578e1d7da815751efaa8101773e7 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/0028-fsverity-plugin-Use-tag-for-algorithm.patch new file mode 100644 index 0000000..0b9bb41 --- /dev/null +++ b/0028-fsverity-plugin-Use-tag-for-algorithm.patch @@ -0,0 +1,116 @@ +From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0028-reflink-remove-requirement-for-executable-stack-flag.patch b/0028-reflink-remove-requirement-for-executable-stack-flag.patch new file mode 100644 index 0000000..a3158f6 --- /dev/null +++ b/0028-reflink-remove-requirement-for-executable-stack-flag.patch @@ -0,0 +1,117 @@ +From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch new file mode 100644 index 0000000..6575b99 --- /dev/null +++ b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch @@ -0,0 +1,28 @@ +From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch b/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch new file mode 100644 index 0000000..f4bf8e3 --- /dev/null +++ b/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch @@ -0,0 +1,109 @@ +From 5753b178a08043316e6f3556754741cdd9cd19c5 Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch new file mode 100644 index 0000000..d872d5e --- /dev/null +++ b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch @@ -0,0 +1,117 @@ +From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch b/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch new file mode 100644 index 0000000..3e64a30 --- /dev/null +++ b/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch @@ -0,0 +1,91 @@ +From dc53b002bd3d03a21e9af406a9aff5e588710b5b Mon Sep 17 00:00:00 2001 +From: chantra +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 + diff --git a/0031-Update-man-page-for-rpmsign.patch b/0031-Update-man-page-for-rpmsign.patch new file mode 100644 index 0000000..938e0f1 --- /dev/null +++ b/0031-Update-man-page-for-rpmsign.patch @@ -0,0 +1,72 @@ +From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + Erik Troan + Panu Matilainen + Fionnuala Gunter ++Jes Sorensen + .fi +-- +2.27.0 + diff --git a/0031-rpmcow-denylist.patch b/0031-rpmcow-denylist.patch new file mode 100644 index 0000000..da7aee3 --- /dev/null +++ b/0031-rpmcow-denylist.patch @@ -0,0 +1,386 @@ +From: Richard Phibel + +Subject: RPM with Copy on Write: add deny list mechanism + +commit 3431550e6c92ba4bc6d091cb244f70c158dfbbaa +Author: Richard Phibel +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 + +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]) diff --git a/0032-rpmcow-workaround.patch b/0032-rpmcow-workaround.patch new file mode 100644 index 0000000..69d5178 --- /dev/null +++ b/0032-rpmcow-workaround.patch @@ -0,0 +1,385 @@ +From: Richard Phibel + +Subject: RPM with Copy on Write: workaround for corrupt signature header + +commit 7976c921f60ec5d20c50c4c702ec5636b39210ba +Author: Richard Phibel +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 + +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); diff --git a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch new file mode 100644 index 0000000..c3f56e8 --- /dev/null +++ b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch @@ -0,0 +1,168 @@ +From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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_("") }, + { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, + N_("use file signing cert "), + N_("") }, +@@ -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 + #include + #include ++#include ++#ifdef WITH_FSVERITY ++#include ++#endif + + #include /* RPMSIGTAG & related */ + #include +@@ -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 + diff --git a/0033-Enable-fsverity-in-CI.patch b/0033-Enable-fsverity-in-CI.patch new file mode 100644 index 0000000..55a209f --- /dev/null +++ b/0033-Enable-fsverity-in-CI.patch @@ -0,0 +1,27 @@ +From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch b/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch new file mode 100644 index 0000000..2ea2066 --- /dev/null +++ b/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch @@ -0,0 +1,80 @@ +From 937f9bc67b905851c78719d8397926eaa97b174a Mon Sep 17 00:00:00 2001 +From: Richard Phibel +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 + diff --git a/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch b/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch new file mode 100644 index 0000000..709472d --- /dev/null +++ b/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch @@ -0,0 +1,28 @@ +From a3b6102b4d2e79a8b74b036c6a29272a7f6e5c6a Mon Sep 17 00:00:00 2001 +From: Richard Phibel +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 + diff --git a/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch b/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch new file mode 100644 index 0000000..692ab33 --- /dev/null +++ b/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch @@ -0,0 +1,257 @@ +From aee5af8e4fe7908df90649eb699c3a1decf06b0c Mon Sep 17 00:00:00 2001 +From: Yu Wu +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 "), + N_("") }, ++ { "pkcs11_engine", '\0', POPT_ARG_STRING, &pkcs11Engine, 0, ++ N_("use pkcs#11 token for fsverity signing key with openssl engine "), ++ N_("") }, ++ { "pkcs11_module", '\0', POPT_ARG_STRING, &pkcs11Module, 0, ++ N_("use pkcs#11 token for fsverity signing key with openssl module "), ++ N_("") }, ++ { "pkcs11_keyid", '\0', POPT_ARG_STRING, &pkcs11KeyId, 0, ++ N_("use pkcs#11 token for fsverity signing key with keyid "), ++ N_("") }, + #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 + } diff --git a/0035-fix-IMA-signature-lengths-assumed-constant.patch b/0035-fix-IMA-signature-lengths-assumed-constant.patch new file mode 100644 index 0000000..bed129d --- /dev/null +++ b/0035-fix-IMA-signature-lengths-assumed-constant.patch @@ -0,0 +1,161 @@ +From 07f1d3132f0c7b7ecb69a47a9930edb534a9250e Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/1381.patch b/1381.patch new file mode 100644 index 0000000..dd1a649 --- /dev/null +++ b/1381.patch @@ -0,0 +1,23 @@ +From 7ae16d6bd37abdcc0430fbb1b25a0f821a60c234 Mon Sep 17 00:00:00 2001 +From: Matthew Almond +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) diff --git a/1534.patch b/1534.patch new file mode 100644 index 0000000..d5acd42 --- /dev/null +++ b/1534.patch @@ -0,0 +1,1359 @@ +From 3a5d2ee0f56d049927c4dcdd03e8e275ac03e20d Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 8 Feb 2021 10:45:59 +0200 +Subject: [PATCH 01/10] Clean up file unpack iteration logic a bit + +Handle rpmfiNext() in the while-condition directly to make it more like +similar other constructs elsewhere, adjust for the end of iteration +code after the loop. Also take the file index from rpmfiNext() so +we don't need multiple calls to rpmfiFX() later. +--- + lib/fsm.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 432bcbd90..f71b9bc1e 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -865,6 +865,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + struct stat sb; + int saveerrno = errno; + int rc = 0; ++ int fx = -1; + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; + int firsthardlink = -1; +@@ -886,17 +887,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + /* Detect and create directories not explicitly in package. */ + rc = fsmMkdirs(files, fs, plugins); + +- while (!rc) { +- /* Read next payload header. */ +- rc = rpmfiNext(fi); +- +- if (rc < 0) { +- if (rc == RPMERR_ITER_END) +- rc = 0; +- break; +- } +- +- action = rpmfsGetAction(fs, rpmfiFX(fi)); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ action = rpmfsGetAction(fs, fx); + skip = XFA_SKIPPING(action); + if (action != FA_TOUCH) { + suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; +@@ -920,7 +912,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (rc) { + skip = 1; + } else { +- setFileState(fs, rpmfiFX(fi)); ++ setFileState(fs, fx); + } + + if (!skip) { +@@ -1022,6 +1014,9 @@ touch: + fpath = _free(fpath); + } + ++ if (!rc && fx != RPMERR_ITER_END) ++ rc = fx; ++ + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + +-- +2.34.1 + + +From 3096acbddc57eb2b65c96aad1ed3524ea9d0cead Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 08:25:28 +0200 +Subject: [PATCH 02/10] Drop unused filename variable + +--- + lib/fsm.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index f71b9bc1e..8e6a6c08b 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -976,11 +976,9 @@ touch: + /* On FA_TOUCH no hardlinks are created thus this is skipped. */ + /* we skip the hard linked file containing the content */ + /* write the content to the first used instead */ +- char *fn = rpmfilesFN(files, firsthardlink); + rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); + wfd_close(&firstlinkfile); + firsthardlink = -1; +- free(fn); + } + + if (rc) { +-- +2.34.1 + + +From 9561315538f1fc4a5b207a43ac39805134e7153f Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 09:57:17 +0200 +Subject: [PATCH 03/10] Don't update path info if rename failed on file commit + +--- + lib/fsm.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 8e6a6c08b..138b55297 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -797,14 +797,16 @@ static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *su + /* Rename temporary to final file name if needed. */ + if (dest != *path) { + rc = fsmRename(*path, dest); +- if (!rc && nsuffix) { +- char * opath = fsmFsPath(fi, NULL); +- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), +- opath, dest); +- free(opath); ++ if (!rc) { ++ if (nsuffix) { ++ char * opath = fsmFsPath(fi, NULL); ++ rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), ++ opath, dest); ++ free(opath); ++ } ++ free(*path); ++ *path = dest; + } +- free(*path); +- *path = dest; + } + } + +-- +2.34.1 + + +From 73d090166a60c57484e4be40e46fcb07f026cbf8 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Thu, 27 Aug 2020 10:31:07 +0300 +Subject: [PATCH 04/10] Upgrade FA_TOUCH to FA_CREATE if the file went away + (RhBug:1872141) + +When %_minimize_writes is enabled, we determine unchanged files during +fingerprinting and only update their metadata (FA_TOUCH) instead of +always recreating from scratch (FA_CREATE) during install. However +package scriptlets (and administrators) can and will do arbitrary stuff +in the meanwhile, such as rm -f their own files in %pre, hoping to +get a fresh copy of contents no matter what. Or something. +Now, if the file was determined to not need changing by rpm, this will +just fail with chown & friends trying to touch non-existent file. +One can consider this a case of package shooting itself in the foot, but +when a package update fails or succeeds depending on %_minimize_writes this +to me suggests the feature is at fault as much as the package. + +Do fsmVerify() on all files to be FA_TOUCH'ed to detect files whose +type changed or were removed since fingerprinting. This still doesn't +ensure correctness if something tampers with the contents in the meanwhile, +(for that we'd need to run the file through the whole machinery again, +checksumming and all) but covers the most glaring cases. +--- + lib/fsm.c | 15 ++++++--- + tests/Makefile.am | 1 + + tests/data/SPECS/suicidal.spec | 19 ++++++++++++ + tests/rpmi.at | 56 ++++++++++++++++++++++++++++++++++ + 4 files changed, 87 insertions(+), 4 deletions(-) + create mode 100644 tests/data/SPECS/suicidal.spec + +diff --git a/lib/fsm.c b/lib/fsm.c +index 138b55297..8a4ecaf05 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -920,10 +920,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!skip) { + int setmeta = 1; + +- /* When touching we don't need any of this... */ +- if (action == FA_TOUCH) +- goto touch; +- + /* Directories replacing something need early backup */ + if (!suffix) { + rc = fsmBackup(fi, action); +@@ -935,6 +931,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rc = RPMERR_ENOENT; + } + ++ /* See if the file was removed while our attention was elsewhere */ ++ if (rc == RPMERR_ENOENT && action == FA_TOUCH) { ++ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); ++ action = FA_CREATE; ++ fsmDebug(fpath, action, &sb); ++ } ++ ++ /* When touching we don't need any of this... */ ++ if (action == FA_TOUCH) ++ goto touch; ++ + if (S_ISREG(sb.st_mode)) { + if (rc == RPMERR_ENOENT) { + rc = fsmMkfile(fi, fpath, files, psm, nodigest, +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 7a6641d4f..d540e2a7b 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -59,6 +59,7 @@ EXTRA_DIST += data/SPECS/verifyscript.spec + EXTRA_DIST += data/SPECS/fakeshell.spec + EXTRA_DIST += data/SPECS/scripts.spec + EXTRA_DIST += data/SPECS/selfconflict.spec ++EXTRA_DIST += data/SPECS/suicidal.spec + EXTRA_DIST += data/SPECS/replacetest.spec + EXTRA_DIST += data/SPECS/triggers.spec + EXTRA_DIST += data/SPECS/filetriggers.spec +diff --git a/tests/data/SPECS/suicidal.spec b/tests/data/SPECS/suicidal.spec +new file mode 100644 +index 000000000..77d17d8c9 +--- /dev/null ++++ b/tests/data/SPECS/suicidal.spec +@@ -0,0 +1,19 @@ ++Name: suicidal ++Version: 1 ++Release: %{rel} ++License: GPL ++Group: Testing ++Summary: Testing suicidal package behavior ++BuildArch: noarch ++ ++%description ++ ++%build ++mkdir -p %{buildroot}/opt ++echo shoot > %{buildroot}/opt/foot ++ ++%pre -p ++os.remove('/opt/foot') ++ ++%files ++/opt/foot +diff --git a/tests/rpmi.at b/tests/rpmi.at +index e8d6e9b7a..71e17821b 100644 +--- a/tests/rpmi.at ++++ b/tests/rpmi.at +@@ -711,3 +711,59 @@ runroot rpm -e testdoc + []) + AT_CLEANUP + ++AT_SETUP([rpm -i --excludeartifacts]) ++AT_KEYWORDS([install]) ++RPMDB_INIT ++runroot rpmbuild --quiet -bb /data/SPECS/vattrtest.spec ++ ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm -i --excludeartifacts /build/RPMS/noarch/vattrtest-1.0-1.noarch.rpm ++test -e ${RPMTEST}/opt/vattrtest/a && exit 1 ++runroot rpm -e vattrtest ++runroot rpm -i /build/RPMS/noarch/vattrtest-1.0-1.noarch.rpm ++test -e ${RPMTEST}/opt/vattrtest/a || exit 1 ++], ++[0], ++[], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([rpm -U ]) ++AT_KEYWORDS([install]) ++RPMDB_INIT ++ ++for r in 1 2; do ++ runroot rpmbuild -bb --quiet \ ++ --define "rel ${r}" \ ++ /data/SPECS/suicidal.spec ++done ++ ++AT_CHECK([ ++RPMDB_INIT ++ ++for r in 1 2; do ++ runroot rpm -U \ ++ --define "_minimize_writes 0" \ ++ /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm ++done ++runroot rpm -V --nouser --nogroup suicidal ++], ++[0], ++[], ++[]) ++ ++AT_CHECK([ ++RPMDB_INIT ++ ++for r in 1 2; do ++ runroot rpm -U \ ++ --define "_minimize_writes 1" \ ++ /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm ++done ++runroot rpm -V --nouser --nogroup suicidal ++], ++[0], ++[], ++[]) ++AT_CLEANUP +-- +2.34.1 + + +From e78ea489eeed84cdee9f5cedcbbf35cfcf1a70b6 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 09:47:19 +0200 +Subject: [PATCH 05/10] Refactor file install and remove around a common struct + +Collect the common state info into a struct shared by both file install +and remove, update code accordingly. The change looks much more drastic +than it is - it's just adding fp-> prefix to a lot of places. +While we're at it, remember the state data throughout the operation. + +No functional changes here, just paving way for the next steps which +will look clearer with these pre-requisites in place. +--- + lib/fsm.c | 158 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 85 insertions(+), 73 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 8a4ecaf05..ab15c2bf3 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -38,6 +38,14 @@ static int strict_erasures = 0; + #define _dirPerms 0755 + #define _filePerms 0644 + ++struct filedata_s { ++ int skip; ++ rpmFileAction action; ++ const char *suffix; ++ char *fpath; ++ struct stat sb; ++}; ++ + /* + * XXX Forward declarations for previously exported functions to avoid moving + * things around needlessly +@@ -864,19 +872,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; + int saveerrno = errno; + int rc = 0; + int fx = -1; ++ int fc = rpmfilesFC(files); + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; + int firsthardlink = -1; + FD_t firstlinkfile = NULL; +- int skip; +- rpmFileAction action; + char *tid = NULL; +- const char *suffix; +- char *fpath = NULL; ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; +@@ -890,96 +895,99 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rc = fsmMkdirs(files, fs, plugins); + + while (!rc && (fx = rpmfiNext(fi)) >= 0) { +- action = rpmfsGetAction(fs, fx); +- skip = XFA_SKIPPING(action); +- if (action != FA_TOUCH) { +- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; ++ struct filedata_s *fp = &fdata[fx]; ++ fp->action = rpmfsGetAction(fs, fx); ++ fp->skip = XFA_SKIPPING(fp->action); ++ if (fp->action != FA_TOUCH) { ++ fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; + } else { +- suffix = NULL; ++ fp->suffix = NULL; + } +- fpath = fsmFsPath(fi, suffix); ++ fp->fpath = fsmFsPath(fi, fp->suffix); + + /* Remap file perms, owner, and group. */ +- rc = rpmfiStat(fi, 1, &sb); ++ rc = rpmfiStat(fi, 1, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + + /* Exit on error. */ + if (rc) + break; + + /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); + if (rc) { +- skip = 1; ++ fp->skip = 1; + } else { + setFileState(fs, fx); + } + +- if (!skip) { ++ if (!fp->skip) { + int setmeta = 1; + + /* Directories replacing something need early backup */ +- if (!suffix) { +- rc = fsmBackup(fi, action); ++ if (!fp->suffix) { ++ rc = fsmBackup(fi, fp->action); + } + /* Assume file does't exist when tmp suffix is in use */ +- if (!suffix) { +- rc = fsmVerify(fpath, fi); ++ if (!fp->suffix) { ++ rc = fsmVerify(fp->fpath, fi); + } else { + rc = RPMERR_ENOENT; + } + + /* See if the file was removed while our attention was elsewhere */ +- if (rc == RPMERR_ENOENT && action == FA_TOUCH) { +- rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); +- action = FA_CREATE; +- fsmDebug(fpath, action, &sb); ++ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { ++ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", ++ fp->fpath); ++ fp->action = FA_CREATE; ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + } + + /* When touching we don't need any of this... */ +- if (action == FA_TOUCH) ++ if (fp->action == FA_TOUCH) + goto touch; + +- if (S_ISREG(sb.st_mode)) { ++ if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fpath, files, psm, nodigest, ++ rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, + &setmeta, &firsthardlink, &firstlinkfile); + } +- } else if (S_ISDIR(sb.st_mode)) { ++ } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- mode_t mode = sb.st_mode; ++ mode_t mode = fp->sb.st_mode; + mode &= ~07777; + mode |= 00700; +- rc = fsmMkdir(fpath, mode); ++ rc = fsmMkdir(fp->fpath, mode); + } +- } else if (S_ISLNK(sb.st_mode)) { ++ } else if (S_ISLNK(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmSymlink(rpmfiFLink(fi), fpath); ++ rc = fsmSymlink(rpmfiFLink(fi), fp->fpath); + } +- } else if (S_ISFIFO(sb.st_mode)) { ++ } else if (S_ISFIFO(fp->sb.st_mode)) { + /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfifo(fpath, 0000); ++ rc = fsmMkfifo(fp->fpath, 0000); + } +- } else if (S_ISCHR(sb.st_mode) || +- S_ISBLK(sb.st_mode) || +- S_ISSOCK(sb.st_mode)) ++ } else if (S_ISCHR(fp->sb.st_mode) || ++ S_ISBLK(fp->sb.st_mode) || ++ S_ISSOCK(fp->sb.st_mode)) + { + if (rc == RPMERR_ENOENT) { +- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); ++ rc = fsmMknod(fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); + } + } else { + /* XXX Special case /dev/log, which shouldn't be packaged anyways */ +- if (!IS_DEV_LOG(fpath)) ++ if (!IS_DEV_LOG(fp->fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; + } + + touch: + /* Set permissions, timestamps etc for non-hardlink entries */ + if (!rc && setmeta) { +- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); ++ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, ++ &fp->sb, nofcaps); + } + } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { + /* On FA_TOUCH no hardlinks are created thus this is skipped. */ +@@ -991,10 +999,10 @@ touch: + } + + if (rc) { +- if (!skip) { ++ if (!fp->skip) { + /* XXX only erase if temp fn w suffix is in use */ +- if (suffix) { +- (void) fsmRemove(fpath, sb.st_mode); ++ if (fp->suffix) { ++ (void) fsmRemove(fp->fpath, fp->sb.st_mode); + } + errno = saveerrno; + } +@@ -1002,23 +1010,22 @@ touch: + /* Notify on success. */ + rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); + +- if (!skip) { ++ if (!fp->skip) { + /* Backup file if needed. Directories are handled earlier */ +- if (suffix) +- rc = fsmBackup(fi, action); ++ if (fp->suffix) ++ rc = fsmBackup(fi, fp->action); + + if (!rc) +- rc = fsmCommit(&fpath, fi, action, suffix); ++ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); + } + } + + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = xstrdup(fp->fpath); + + /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); +- fpath = _free(fpath); ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); + } + + if (!rc && fx != RPMERR_ITER_END) +@@ -1034,7 +1041,9 @@ exit: + rpmfiFree(fi); + Fclose(payload); + free(tid); +- free(fpath); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); + + return rc; + } +@@ -1046,29 +1055,31 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, + rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; ++ int fc = rpmfilesFC(files); ++ int fx = -1; ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + int rc = 0; +- char *fpath = NULL; + +- while (!rc && rpmfiNext(fi) >= 0) { +- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); +- fpath = fsmFsPath(fi, NULL); +- rc = fsmStat(fpath, 1, &sb); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); ++ fp->fpath = fsmFsPath(fi, NULL); ++ rc = fsmStat(fp->fpath, 1, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + + /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); + +- if (!XFA_SKIPPING(action)) +- rc = fsmBackup(fi, action); ++ if (!XFA_SKIPPING(fp->action)) ++ rc = fsmBackup(fi, fp->action); + + /* Remove erased files. */ +- if (action == FA_ERASE) { ++ if (fp->action == FA_ERASE) { + int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); + +- rc = fsmRemove(fpath, sb.st_mode); ++ rc = fsmRemove(fp->fpath, fp->sb.st_mode); + + /* + * Missing %ghost or %missingok entries are not errors. +@@ -1093,20 +1104,20 @@ 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"), +- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), +- fpath, strerror(errno)); ++ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), ++ fp->fpath, strerror(errno)); + } + } + + /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); + + /* XXX Failure to remove is not (yet) cause for failure. */ + if (!strict_erasures) rc = 0; + + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = xstrdup(fp->fpath); + + if (rc == 0) { + /* Notify on success. */ +@@ -1114,10 +1125,11 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, + rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); + rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + } +- fpath = _free(fpath); + } + +- free(fpath); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); + rpmfiFree(fi); + + return rc; +-- +2.34.1 + + +From 215525131b0e4e015d83c25828700d7531fec6dd Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 10:08:27 +0200 +Subject: [PATCH 06/10] Refactor fsmMkfile() to take advantage of the new state + struct + +Move setmeta into the struct too (we'll want this later anyhow), +and now we only need to pass the struct to fsmMkfile(). One less +argument to pass around, it has way too many still. + +No functional changes. +--- + lib/fsm.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index ab15c2bf3..6c873206c 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -39,6 +39,7 @@ static int strict_erasures = 0; + #define _filePerms 0644 + + struct filedata_s { ++ int setmeta; + int skip; + rpmFileAction action; + const char *suffix; +@@ -279,8 +280,8 @@ exit: + return rc; + } + +-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, +- rpmpsm psm, int nodigest, int *setmeta, ++static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, ++ rpmpsm psm, int nodigest, + int * firsthardlink, FD_t *firstlinkfile) + { + int rc = 0; +@@ -290,11 +291,11 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, + /* Create first hardlinked file empty */ + if (*firsthardlink < 0) { + *firsthardlink = rpmfiFX(fi); +- rc = wfd_open(firstlinkfile, dest); ++ rc = wfd_open(firstlinkfile, fp->fpath); + } else { + /* Create hard links for others */ + char *fn = rpmfilesFN(files, *firsthardlink); +- rc = link(fn, dest); ++ rc = link(fn, fp->fpath); + if (rc < 0) { + rc = RPMERR_LINK_FAILED; + } +@@ -305,14 +306,14 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, + existing) file with content */ + if (numHardlinks<=1) { + if (!rc) +- rc = expandRegular(fi, dest, psm, nodigest); ++ rc = expandRegular(fi, fp->fpath, psm, nodigest); + } else if (rpmfiArchiveHasContent(fi)) { + if (!rc) + rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); + wfd_close(firstlinkfile); + *firsthardlink = -1; + } else { +- *setmeta = 0; ++ fp->setmeta = 0; + } + + return rc; +@@ -898,6 +899,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + struct filedata_s *fp = &fdata[fx]; + fp->action = rpmfsGetAction(fs, fx); + fp->skip = XFA_SKIPPING(fp->action); ++ fp->setmeta = 1; + if (fp->action != FA_TOUCH) { + fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; + } else { +@@ -924,8 +926,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + } + + if (!fp->skip) { +- int setmeta = 1; +- + /* Directories replacing something need early backup */ + if (!fp->suffix) { + rc = fsmBackup(fi, fp->action); +@@ -951,8 +951,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + + if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, +- &setmeta, &firsthardlink, &firstlinkfile); ++ rc = fsmMkfile(fi, fp, files, psm, nodigest, ++ &firsthardlink, &firstlinkfile); + } + } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +@@ -985,7 +985,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + + touch: + /* Set permissions, timestamps etc for non-hardlink entries */ +- if (!rc && setmeta) { ++ if (!rc && fp->setmeta) { + rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, + &fp->sb, nofcaps); + } +-- +2.34.1 + + +From 062167c2532a066301b15a0e85a1ac6cb6c07472 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 10:24:22 +0200 +Subject: [PATCH 07/10] Clarify file installation temporary suffix rule + +We only use a temporary suffix for regular files that we are actually +creating, skipped and touched files should not have it. Add XFA_CREATING() +macro to accomppany XFA_SKIPPING() to easily check whether the file +is being created or something else. + +No functional changes but makes the logic clearer. +--- + lib/fsm.c | 5 +---- + lib/rpmfiles.h | 3 +++ + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 6c873206c..e4842a200 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -900,11 +900,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + fp->action = rpmfsGetAction(fs, fx); + fp->skip = XFA_SKIPPING(fp->action); + fp->setmeta = 1; +- if (fp->action != FA_TOUCH) { ++ if (XFA_CREATING(fp->action)) + fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; +- } else { +- fp->suffix = NULL; +- } + fp->fpath = fsmFsPath(fi, fp->suffix); + + /* Remap file perms, owner, and group. */ +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index 64b33281a..7f3f82662 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e { + #define XFA_SKIPPING(_a) \ + ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) + ++#define XFA_CREATING(_a) \ ++ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) ++ + /** + * We pass these around as an array with a sentinel. + */ +-- +2.34.1 + + +From b3c6a3358dc4ec72fda0a229c22a5b79ac392848 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 10:24:22 +0200 +Subject: [PATCH 08/10] Clarify file installation temporary suffix rule + +We only use a temporary suffix for regular files that we are actually +creating, skipped and touched files should not have it. Add XFA_CREATING() +macro to accomppany XFA_SKIPPING() to easily check whether the file +is being created or something else. + +No functional changes but makes the logic clearer. +--- + lib/fsm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index e4842a200..4d7c03895 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -900,8 +900,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + fp->action = rpmfsGetAction(fs, fx); + fp->skip = XFA_SKIPPING(fp->action); + fp->setmeta = 1; +- if (XFA_CREATING(fp->action)) +- fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; ++ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) ++ fp->suffix = tid; + fp->fpath = fsmFsPath(fi, fp->suffix); + + /* Remap file perms, owner, and group. */ +-- +2.34.1 + + +From 9097021b19c658ff55f7515878bae0592fd86377 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 11:25:10 +0200 +Subject: [PATCH 09/10] Handle hardlink tracking with a file state pointer + +No functional changes, just makes it a little cleaner as firstlink now +points to the actual file data instead of a index number somewhere. +--- + lib/fsm.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 4d7c03895..cef17e669 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -282,24 +282,22 @@ exit: + + static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, + rpmpsm psm, int nodigest, +- int * firsthardlink, FD_t *firstlinkfile) ++ struct filedata_s ** firstlink, FD_t *firstlinkfile) + { + int rc = 0; + int numHardlinks = rpmfiFNlink(fi); + + if (numHardlinks > 1) { + /* Create first hardlinked file empty */ +- if (*firsthardlink < 0) { +- *firsthardlink = rpmfiFX(fi); ++ if (*firstlink == NULL) { ++ *firstlink = fp; + rc = wfd_open(firstlinkfile, fp->fpath); + } else { + /* Create hard links for others */ +- char *fn = rpmfilesFN(files, *firsthardlink); +- rc = link(fn, fp->fpath); ++ rc = link((*firstlink)->fpath, fp->fpath); + if (rc < 0) { + rc = RPMERR_LINK_FAILED; + } +- free(fn); + } + } + /* Write normal files or fill the last hardlinked (already +@@ -311,7 +309,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, + if (!rc) + rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); + wfd_close(firstlinkfile); +- *firsthardlink = -1; ++ *firstlink = NULL; + } else { + fp->setmeta = 0; + } +@@ -879,10 +877,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + int fc = rpmfilesFC(files); + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; +- int firsthardlink = -1; + FD_t firstlinkfile = NULL; + char *tid = NULL; + struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); ++ struct filedata_s *firstlink = NULL; + + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; +@@ -949,7 +947,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { + rc = fsmMkfile(fi, fp, files, psm, nodigest, +- &firsthardlink, &firstlinkfile); ++ &firstlink, &firstlinkfile); + } + } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +@@ -986,13 +984,13 @@ touch: + rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, + &fp->sb, nofcaps); + } +- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { ++ } else if (firstlink && rpmfiArchiveHasContent(fi)) { + /* On FA_TOUCH no hardlinks are created thus this is skipped. */ + /* we skip the hard linked file containing the content */ + /* write the content to the first used instead */ + rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); + wfd_close(&firstlinkfile); +- firsthardlink = -1; ++ firstlink = NULL; + } + + if (rc) { +-- +2.34.1 + + +From 357afe98316cb643a0757163ddbc276a071f1a18 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 10 Feb 2021 14:15:33 +0200 +Subject: [PATCH 10/10] Handle file install failures more gracefully + +Run the file installation in multiple stages: +1) gather intel +2) unpack the archive to temporary files +3) set file metadatas +4) commit files to final location +5) mop up leftovers on failure + +This means we no longer leave behind a trail of untracked, potentially +harmful junk on installation failure. + +If commit step fails the package can still be left in an inconsistent stage, +this could be further improved by first backing up old files to temporary +location to allow undo on failure, but leaving that for some other day. +Also unowned directories will still be left behind. + +And yes, this is a somewhat scary change as it's the biggest ever change +to how rpm lays down files on install. Adopt the hardlink test spec +over to install tests and add some more tests for the new behavior. + +Fixes: #967 (+ multiple reports over the years) +--- + lib/fsm.c | 147 ++++++++++++++++++++------------ + tests/data/SPECS/hlinktest.spec | 4 + + tests/rpmbuild.at | 33 ------- + tests/rpmi.at | 92 ++++++++++++++++++++ + 4 files changed, 189 insertions(+), 87 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index cef17e669..82af6f39f 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -38,7 +38,17 @@ static int strict_erasures = 0; + #define _dirPerms 0755 + #define _filePerms 0644 + ++enum filestage_e { ++ FILE_COMMIT = -1, ++ FILE_NONE = 0, ++ FILE_PRE = 1, ++ FILE_UNPACK = 2, ++ FILE_PREP = 3, ++ FILE_POST = 4, ++}; ++ + struct filedata_s { ++ int stage; + int setmeta; + int skip; + rpmFileAction action; +@@ -868,10 +878,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { + FD_t payload = rpmtePayload(te); +- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ rpmfi fi = NULL; + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- int saveerrno = errno; + int rc = 0; + int fx = -1; + int fc = rpmfilesFC(files); +@@ -882,20 +891,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + struct filedata_s *firstlink = NULL; + +- if (fi == NULL) { +- rc = RPMERR_BAD_MAGIC; +- goto exit; +- } +- + /* transaction id used for temporary path suffix while installing */ + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); + +- /* Detect and create directories not explicitly in package. */ +- rc = fsmMkdirs(files, fs, plugins); +- ++ /* Collect state data for the whole operation */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); + while (!rc && (fx = rpmfiNext(fi)) >= 0) { + struct filedata_s *fp = &fdata[fx]; +- fp->action = rpmfsGetAction(fs, fx); ++ if (rpmfiFFlags(fi) & RPMFILE_GHOST) ++ fp->action = FA_SKIP; ++ else ++ fp->action = rpmfsGetAction(fs, fx); + fp->skip = XFA_SKIPPING(fp->action); + fp->setmeta = 1; + if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) +@@ -905,20 +911,32 @@ 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); + +- /* Exit on error. */ +- if (rc) +- break; +- + /* Run fsm file pre hook for all plugins */ + rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, + fp->sb.st_mode, fp->action); +- if (rc) { +- fp->skip = 1; +- } else { +- setFileState(fs, fx); +- } ++ fp->stage = FILE_PRE; ++ } ++ fi = rpmfiFree(fi); ++ ++ if (rc) ++ goto exit; ++ ++ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ if (fi == NULL) { ++ rc = RPMERR_BAD_MAGIC; ++ goto exit; ++ } ++ ++ /* Detect and create directories not explicitly in package. */ ++ if (!rc) ++ rc = fsmMkdirs(files, fs, plugins); ++ ++ /* Process the payload */ ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; + + if (!fp->skip) { + /* Directories replacing something need early backup */ +@@ -942,7 +960,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + + /* When touching we don't need any of this... */ + if (fp->action == FA_TOUCH) +- goto touch; ++ continue; + + if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +@@ -978,12 +996,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rc = RPMERR_UNKNOWN_FILETYPE; + } + +-touch: +- /* Set permissions, timestamps etc for non-hardlink entries */ +- if (!rc && fp->setmeta) { +- rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, +- &fp->sb, nofcaps); +- } + } else if (firstlink && rpmfiArchiveHasContent(fi)) { + /* On FA_TOUCH no hardlinks are created thus this is skipped. */ + /* we skip the hard linked file containing the content */ +@@ -993,47 +1005,74 @@ touch: + firstlink = NULL; + } + +- if (rc) { +- if (!fp->skip) { +- /* XXX only erase if temp fn w suffix is in use */ +- if (fp->suffix) { +- (void) fsmRemove(fp->fpath, fp->sb.st_mode); +- } +- errno = saveerrno; +- } +- } else { +- /* Notify on success. */ ++ /* Notify on success. */ ++ if (rc) ++ *failedFile = xstrdup(fp->fpath); ++ else + rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); ++ fp->stage = FILE_UNPACK; ++ } ++ fi = rpmfiFree(fi); + +- if (!fp->skip) { +- /* Backup file if needed. Directories are handled earlier */ +- if (fp->suffix) +- rc = fsmBackup(fi, fp->action); ++ if (!rc && fx < 0 && fx != RPMERR_ITER_END) ++ rc = fx; + +- if (!rc) +- rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); +- } ++ /* Set permissions, timestamps etc for non-hardlink entries */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ if (!fp->skip && fp->setmeta) { ++ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, ++ &fp->sb, nofcaps); + } +- + if (rc) + *failedFile = xstrdup(fp->fpath); ++ fp->stage = FILE_PREP; ++ } ++ fi = rpmfiFree(fi); + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, +- fp->sb.st_mode, fp->action, rc); ++ /* If all went well, commit files to final destination */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ if (!fp->skip) { ++ /* Backup file if needed. Directories are handled earlier */ ++ if (!rc && fp->suffix) ++ rc = fsmBackup(fi, fp->action); ++ ++ if (!rc) ++ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); ++ ++ if (!rc) ++ fp->stage = FILE_COMMIT; ++ else ++ *failedFile = xstrdup(fp->fpath); ++ } + } ++ fi = rpmfiFree(fi); + +- if (!rc && fx != RPMERR_ITER_END) +- rc = fx; ++ /* Walk backwards in case we need to erase */ ++ fi = rpmfilesIter(files, RPMFI_ITER_BACK); ++ while ((fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ /* Run fsm file post hook for all plugins for all processed files */ ++ if (fp->stage) { ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); ++ } ++ ++ /* On failure, erase non-committed files */ ++ if (rc && fp->stage > FILE_NONE && !fp->skip) { ++ (void) fsmRemove(fp->fpath, fp->sb.st_mode); ++ } ++ } + + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + + exit: +- +- /* No need to bother with close errors on read */ +- rpmfiArchiveClose(fi); +- rpmfiFree(fi); ++ fi = rpmfiFree(fi); + Fclose(payload); + free(tid); + for (int i = 0; i < fc; i++) +diff --git a/tests/data/SPECS/hlinktest.spec b/tests/data/SPECS/hlinktest.spec +index b3b8866fc..1f453524e 100644 +--- a/tests/data/SPECS/hlinktest.spec ++++ b/tests/data/SPECS/hlinktest.spec +@@ -1,5 +1,6 @@ + %bcond_with unpackaged_dirs + %bcond_with unpackaged_files ++%bcond_with owned_dir + + Summary: Testing hard link behavior + Name: hlinktest +@@ -38,4 +39,7 @@ touch $RPM_BUILD_ROOT/toot + + %files + %defattr(-,root,root) ++%if %{with owned_dir} ++%dir /foo ++%endif + /foo/* +diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at +index 4294fd97c..c99fa7a63 100644 +--- a/tests/rpmbuild.at ++++ b/tests/rpmbuild.at +@@ -139,39 +139,6 @@ drwxrwxrwx zoot zoot /j/dir + []) + AT_CLEANUP + +-# ------------------------------ +-# hardlink tests +-AT_SETUP([rpmbuild hardlink]) +-AT_KEYWORDS([build]) +-AT_CHECK([ +-RPMDB_CLEAR +-RPMDB_INIT +-rm -rf ${TOPDIR} +- +-runroot rpmbuild \ +- -bb --quiet /data/SPECS/hlinktest.spec +- +-runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm +- +-runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest +-runroot rpm -V --nouser --nogroup hlinktest +-ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l +- +-], +-[0], +-[2 /foo/aaaa +-1 /foo/copyllo +-4 /foo/hello +-4 /foo/hello-bar +-4 /foo/hello-foo +-4 /foo/hello-world +-2 /foo/zzzz +-87 +-1 +-], +-[]) +-AT_CLEANUP +- + AT_SETUP([rpmbuild unpackaged files]) + AT_KEYWORDS([build]) + AT_CHECK([ +diff --git a/tests/rpmi.at b/tests/rpmi.at +index 71e17821b..bf1606b6d 100644 +--- a/tests/rpmi.at ++++ b/tests/rpmi.at +@@ -767,3 +767,95 @@ runroot rpm -V --nouser --nogroup suicidal + [], + []) + AT_CLEANUP ++ ++# ------------------------------ ++# hardlink tests ++AT_SETUP([rpm -i hardlinks]) ++AT_KEYWORDS([build install]) ++RPMDB_INIT ++ ++# Need a reproducable test package ++runroot rpmbuild \ ++ --define "%optflags -O2 -g" \ ++ --define "%_target_platform noarch-linux" \ ++ --define "%_binary_payload w.ufdio" \ ++ --define "%_buildhost localhost" \ ++ --define "%use_source_date_epoch_as_buildtime 1" \ ++ --define "%source_date_epoch_from_changelog 1" \ ++ --define "%clamp_mtime_to_source_date_epoch 1" \ ++ --with owned_dir \ ++ -bb --quiet /data/SPECS/hlinktest.spec ++ ++pkg="/build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm" ++ ++cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/1.rpm" ++dd if=/dev/zero of="${RPMTEST}/tmp/1.rpm" \ ++ conv=notrunc bs=1 seek=8180 count=6 2> /dev/null ++ ++cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/2.rpm" ++dd if=/dev/zero of="${RPMTEST}/tmp/2.rpm" \ ++ conv=notrunc bs=1 seek=8150 count=6 2> /dev/null ++ ++cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/3.rpm" ++dd if=/dev/zero of="${RPMTEST}/tmp/3.rpm" \ ++ conv=notrunc bs=1 seek=8050 count=6 2> /dev/null ++ ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm -i --noverify /tmp/1.rpm ++# test that nothing of the contents remains after failure ++test -d "${RPMTEST}/foo" ++], ++[1], ++[], ++[error: unpacking of archive failed: cpio: Archive file not in header ++error: hlinktest-1.0-1.noarch: install failed ++]) ++ ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm -i --noverify /tmp/2.rpm ++# test that nothing of the contents remains after failure ++test -d "${RPMTEST}/foo" ++], ++[1], ++[], ++[error: unpacking of archive failed: cpio: Bad/unreadable header ++error: hlinktest-1.0-1.noarch: install failed ++]) ++ ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm -i --noverify /tmp/3.rpm 2>&1| sed 's/;.*:/:/g' ++# test that nothing of the contents remains after failure ++test -d "${RPMTEST}/foo" ++], ++[1], ++[error: unpacking of archive failed on file /foo/hello-world: Digest mismatch ++error: hlinktest-1.0-1.noarch: install failed ++], ++[]) ++ ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm ++runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest ++ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l ++runroot rpm -e hlinktest ++ ++], ++[0], ++[1 /foo ++2 /foo/aaaa ++1 /foo/copyllo ++4 /foo/hello ++4 /foo/hello-bar ++4 /foo/hello-foo ++4 /foo/hello-world ++2 /foo/zzzz ++87 ++1 ++], ++[]) ++AT_CLEANUP ++ +-- +2.34.1 + diff --git a/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch b/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch deleted file mode 100644 index 4ecdab7..0000000 --- a/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5b21f2f2a12adfd9e1adffc2bf1ad7171ee5d03c Mon Sep 17 00:00:00 2001 -From: "Vladimir D. Seleznev" -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 ---- - 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 - diff --git a/SOURCES/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch b/SOURCES/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch deleted file mode 100644 index 5601c58..0000000 --- a/SOURCES/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 1da9e839bb573b9187403983f5a69853ab364306 Mon Sep 17 00:00:00 2001 -From: Pavlina Moravcova Varekova -Date: Sun, 17 Mar 2019 06:47:26 +0100 -Subject: [PATCH] Add flag to use strip -g instead of full strip on DSOs - (RhBug:1663264) - -The find-debuginfo.sh flag -g had exactly this meaning. But from -version rpm-4.13.0-alpha flag -g changes its behavior. It affects -both libraries and executables. - -For some packages the original behavior was preferred. That is why -the new find-debuginfo.sh flag --g-libs is created. - -Options -g and --g-libs are mutually exclusive. - - -Adjusted for rpm-4.14.2 in RHEL - ---- rpm-4.14.2/scripts/find-debuginfo.sh.orig 2019-04-24 15:14:29.351010878 +0200 -+++ rpm-4.14.2/scripts/find-debuginfo.sh 2019-04-24 15:19:42.296240705 +0200 -@@ -4,6 +4,7 @@ - # - # Usage: find-debuginfo.sh [--strict-build-id] [-g] [-r] [-m] [-i] [-n] - # [--keep-section SECTION] [--remove-section SECTION] -+# [--g-libs] - # [-j N] [--jobs N] - # [-o debugfiles.list] - # [-S debugsourcefiles.list] -@@ -16,6 +17,8 @@ - # [builddir] - # - # The -g flag says to use strip -g instead of full strip on DSOs or EXEs. -+# The --g-libs flag says to use strip -g instead of full strip ONLY on DSOs. -+# Options -g and --g-libs are mutually exclusive. - # The -r flag says to use eu-strip --reloc-debug-sections. - # Use --keep-section SECTION or --remove-section SECTION to explicitly - # keep a (non-allocated) section in the main executable or explicitly -@@ -68,6 +71,9 @@ - # With -g arg, pass it to strip on libraries or executables. - strip_g=false - -+# With --g-libs arg, pass it to strip on libraries. -+strip_glibs=false -+ - # with -r arg, pass --reloc-debug-sections to eu-strip. - strip_r=false - -@@ -135,6 +141,9 @@ - unique_debug_src_base=$2 - shift - ;; -+ --g-libs) -+ strip_glibs=true -+ ;; - -g) - strip_g=true - ;; -@@ -204,6 +213,11 @@ - exit 2 - fi - -+if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then -+ echo >&2 "*** ERROR: -g and --g-libs cannot be used together" -+ exit 2 -+fi -+ - i=0 - while ((i < nout)); do - outs[$i]="$BUILDDIR/${outs[$i]}" -@@ -237,6 +251,9 @@ - application/x-executable*) g=-g ;; - application/x-pie-executable*) g=-g ;; - esac -+ $strip_glibs && case "$(file -bi "$2")" in -+ application/x-sharedlib*) g=-g ;; -+ esac - eu-strip --remove-comment $r $g ${keep_remove_args} -f "$1" "$2" || exit - chmod 444 "$1" || exit - } -@@ -430,8 +430,12 @@ - # libraries. Other executable ELF files (like kernel modules) don't need it. - if [ "$include_minidebug" = "true" -a "$strip_g" = "false" ]; then - skip_mini=true -+ if [ "$strip_glibs" = "false" ]; then -+ case "$(file -bi "$f")" in -+ application/x-sharedlib*) skip_mini=false ;; -+ esac -+ fi - case "$(file -bi "$f")" in -- application/x-sharedlib*) skip_mini=false ;; - application/x-executable*) skip_mini=false ;; - application/x-pie-executable*) skip_mini=false ;; - esac diff --git a/SOURCES/0001-Add-limits-to-autopatch-macro.patch b/SOURCES/0001-Add-limits-to-autopatch-macro.patch deleted file mode 100644 index 3235922..0000000 --- a/SOURCES/0001-Add-limits-to-autopatch-macro.patch +++ /dev/null @@ -1,44 +0,0 @@ -From f00bb5be9caa62220c6aeaf3f7264840d5c089e3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= -Date: Tue, 5 Feb 2019 18:15:47 +0100 -Subject: [PATCH] Add limits to autopatch macro - -Limits allow to apply only range of patches with given parameters. -Useful if something needs to be done between patch sets. Allows applying -of patches with different -pX parameter in one spec file. - -Resolves: #626 -Co-authored-by: Florian Festi ---- - macros.in | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/macros.in b/macros.in -index 7b5b63020..912ad5997 100644 ---- a/macros.in -+++ b/macros.in -@@ -1265,11 +1265,19 @@ else\ - end} - - # Automatically apply all patches --%autopatch(vp:)\ -+# -m Apply patches with number >= min only -+# -M Apply patches with number <= max only -+%autopatch(vp:m:M:)\ - %{lua:\ - local options = rpm.expand("%{!-v:-q} %{-p:-p%{-p*}} ")\ -+local low_limit = tonumber(rpm.expand("%{-m:%{-m*}}"))\ -+local high_limit = tonumber(rpm.expand("%{-M:%{-M*}}"))\ - for i, p in ipairs(patches) do\ -- print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n"))\ -+ local inum = patch_nums[i]\ -+ if ((not low_limit or inum>=low_limit) and (not high_limit or inum<=high_limit)) \ -+ then\ -+ print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n")) \ -+ end\ - end} - - # One macro to (optionally) do it all. --- -2.26.2 - diff --git a/SOURCES/0001-Always-close-libelf-handle-1313.patch b/SOURCES/0001-Always-close-libelf-handle-1313.patch deleted file mode 100644 index 81a1296..0000000 --- a/SOURCES/0001-Always-close-libelf-handle-1313.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 38c03ddb18e86c84d89af695f72442d8365eb64e Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Tue, 21 Jul 2020 10:45:20 +0200 -Subject: [PATCH] Always close libelf handle (#1313) - -Otherwise executables that are not proper elf files are leaking libelf -handles. This results in file being left open (mmap'ed) and fails the -build on NFS as those files can't be deleted properly there. - -Resolves: rhbz#1840728 -See also: https://bugzilla.redhat.com/show_bug.cgi?id=1840728 ---- - build/files.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/build/files.c b/build/files.c -index f675306f7..62489c07c 100644 ---- a/build/files.c -+++ b/build/files.c -@@ -1935,8 +1935,8 @@ static int generateBuildIDs(FileList fl, ARGV_t *files) - if (terminate) - rc = 1; - } -- elf_end (elf); - } -+ elf_end (elf); - close (fd); - } - } --- -2.26.2 - diff --git a/SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch b/SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch deleted file mode 100644 index df0aaab..0000000 --- a/SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch +++ /dev/null @@ -1,37 +0,0 @@ -From c4f285cff8f830447857e52848ecf909cedb192a Mon Sep 17 00:00:00 2001 -Message-Id: -From: Panu Matilainen -Date: Tue, 6 Nov 2018 12:22:55 +0200 -Subject: [PATCH] Document --noverify in the man page (RhBug:1646458) - -Should've been in commit 765e2c72ae8be369ada41d4747b8999519a0e327 ---- - doc/rpm.8 | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/doc/rpm.8 b/doc/rpm.8 -index 5ab61b2ac..31c51d821 100644 ---- a/doc/rpm.8 -+++ b/doc/rpm.8 -@@ -104,7 +104,7 @@ Scripts and triggers: - [\fB--ignoresize\fR] [\fB--ignorearch\fR] [\fB--ignoreos\fR] - [\fB--includedocs\fR] [\fB--justdb\fR] - [\fB--nodeps\fR] [\fB--nodigest\fR] [\fB--noplugins\fR] -- [\fB--nocaps\fR] [\fB--noorder\fR] -+ [\fB--nocaps\fR] [\fB--noorder\fR] [\fB--noverify\fR] - [\fB--nosignature\fR] [\fB--noscripts\fR] [\fB--notriggers\fR] - [\fB--oldpackage\fR] [\fB--percent\fR] [\fB--prefix \fINEWPATH\fB\fR] - [\fB--relocate \fIOLDPATH\fB=\fINEWPATH\fB\fR] -@@ -315,6 +315,9 @@ Don't set file capabilities. - Don't reorder the packages for an install. The list of - packages would normally be reordered to satisfy dependencies. - .TP -+\fB--noverify\fR -+Don't perform verify package files prior to installation. -+.TP - \fB--noplugins\fR - Do not load and execute plugins. - .TP --- -2.19.2 - diff --git a/SOURCES/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch b/SOURCES/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch deleted file mode 100644 index df98eaa..0000000 --- a/SOURCES/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 13f70e3710b2df49a923cc6450ff4a8f86e65666 Mon Sep 17 00:00:00 2001 -Message-Id: <13f70e3710b2df49a923cc6450ff4a8f86e65666.1555050140.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Wed, 20 Mar 2019 12:38:00 +0200 -Subject: [PATCH] Fix FA_TOUCH on files with suid/sgid bits and/or capabilities - -FA_TOUCH used to set suffix to "" instead of NULL which causes fsmCommit() -to rename the file onto itself, which is a bit dumb but mostly harmless -with regular permission. On suid/sgid/capabilities we strip any extra -privileges on rename to make sure hardlinks are neutered, and because -rename occurs after other permissions etc setting, on FA_TOUCH those -extra privileges are stripped and much brokenness will follow. - -A more minimal fix would be a strategically placed strcmp(), but NULL -is what the rest of the fsm expects for no suffix and differentiating -between empty and NULL suffix is too subtle for its own good as -witnessed here. So now, NULL suffix is no suffix again and the rest -of the code will do the right thing except where related to creation, -and creation is what FA_TOUCH wont do so lets just explicitly skip it -and restore the original code otherwise. The goto is ugly but reindenting -gets even uglier, shrug. Add a test-case to go with it. - -This has been broken since its introduction in commit -79ca74e15e15c1d91a9a31a9ee90abc91736f390 so all current 4.14.x versions -are affected. ---- - lib/fsm.c | 17 ++++++++++---- - tests/data/SPECS/replacetest.spec | 2 +- - tests/rpmverify.at | 38 ++++++++++++++++++++++++++++++- - 3 files changed, 50 insertions(+), 7 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 8eb2c185c..432bcbd90 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -898,12 +898,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - action = rpmfsGetAction(fs, rpmfiFX(fi)); - skip = XFA_SKIPPING(action); -- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - if (action != FA_TOUCH) { -- fpath = fsmFsPath(fi, suffix); -+ suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - } else { -- fpath = fsmFsPath(fi, ""); -+ suffix = NULL; - } -+ fpath = fsmFsPath(fi, suffix); - - /* Remap file perms, owner, and group. */ - rc = rpmfiStat(fi, 1, &sb); -@@ -926,6 +926,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (!skip) { - int setmeta = 1; - -+ /* When touching we don't need any of this... */ -+ if (action == FA_TOUCH) -+ goto touch; -+ - /* Directories replacing something need early backup */ - if (!suffix) { - rc = fsmBackup(fi, action); -@@ -934,7 +938,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (!suffix) { - rc = fsmVerify(fpath, fi); - } else { -- rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT; -+ rc = RPMERR_ENOENT; - } - - if (S_ISREG(sb.st_mode)) { -@@ -970,11 +974,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (!IS_DEV_LOG(fpath)) - rc = RPMERR_UNKNOWN_FILETYPE; - } -+ -+touch: - /* Set permissions, timestamps etc for non-hardlink entries */ - if (!rc && setmeta) { - rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); - } - } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { -+ /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ - /* write the content to the first used instead */ - char *fn = rpmfilesFN(files, firsthardlink); -@@ -987,7 +994,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (rc) { - if (!skip) { - /* XXX only erase if temp fn w suffix is in use */ -- if (suffix && (action != FA_TOUCH)) { -+ if (suffix) { - (void) fsmRemove(fpath, sb.st_mode); - } - errno = saveerrno; -diff --git a/tests/data/SPECS/replacetest.spec b/tests/data/SPECS/replacetest.spec -index 54974567b..d5a1729d3 100644 ---- a/tests/data/SPECS/replacetest.spec -+++ b/tests/data/SPECS/replacetest.spec -@@ -46,4 +46,4 @@ rm -rf $RPM_BUILD_ROOT - - %files - %defattr(-,%{user},%{grp},-) --/opt/* -+%{?fileattr} /opt/* -diff --git a/tests/rpmverify.at b/tests/rpmverify.at -index 52ee2abfb..f7dd57531 100644 ---- a/tests/rpmverify.at -+++ b/tests/rpmverify.at -@@ -575,3 +575,39 @@ - ], - []) - AT_CLEANUP -+ -+AT_SETUP([Upgraded verification with min_writes 5 (suid files)]) -+AT_KEYWORDS([upgrade verify min_writes]) -+AT_CHECK([ -+RPMDB_CLEAR -+RPMDB_INIT -+tf="${RPMTEST}"/opt/foo -+rm -rf "${tf}" "${tf}".rpm* -+rm -rf "${TOPDIR}" -+ -+for v in "1.0" "2.0"; do -+ runroot rpmbuild --quiet -bb \ -+ --define "ver $v" \ -+ --define "filetype file" \ -+ --define "filedata foo" \ -+ --define "fileattr %attr(2755,-,-)" \ -+ /data/SPECS/replacetest.spec -+done -+ -+runroot rpm -U /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm -+runroot rpm -Va --nouser --nogroup replacetest -+runroot rpm -U \ -+ --define "_minimize_writes 1" \ -+ /build/RPMS/noarch/replacetest-2.0-1.noarch.rpm -+runroot rpm -Va --nouser --nogroup replacetest -+chmod 777 "${tf}" -+runroot rpm -U \ -+ --oldpackage \ -+ --define "_minimize_writes 1" \ -+ /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm -+runroot rpm -Va --nouser --nogroup replacetest -+], -+[0], -+[], -+[]) -+AT_CLEANUP --- -2.20.1 - diff --git a/SOURCES/0001-Fix-brp-strip-static-archive-parallelism.patch b/SOURCES/0001-Fix-brp-strip-static-archive-parallelism.patch deleted file mode 100644 index a1583f9..0000000 --- a/SOURCES/0001-Fix-brp-strip-static-archive-parallelism.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 1fd84fa0cfa6e493d1c15edfb7d9f0bb05e4f920 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Thu, 2 May 2019 17:17:56 +0200 -Subject: [PATCH] Fix brp-strip-static-archive parallelism - -The change made in fc2c986 can break for large values of %_smp_build_ncpus as -this many processes are able to overflow the following pipe. - -Thanks to Denys Vlasenko for testing this. - -This change solves this problem by running a whole processing pileline for each -parallel (file) process. This has also the benefit of running at least some -stip commands in parallel. - -The -n param fro xargs was increased to 32 to further reduce the over head of -spawing the helpers as they are now needed for each run of the file command. ---- - scripts/brp-strip-static-archive | 10 +++------- - 1 file changed, 3 insertions(+), 7 deletions(-) - -diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive -index 4dc449061..13d9a098b 100755 ---- a/scripts/brp-strip-static-archive -+++ b/scripts/brp-strip-static-archive -@@ -13,10 +13,6 @@ Darwin*) exit 0 ;; - esac - - # Strip static libraries. --for f in `find "$RPM_BUILD_ROOT" -type f | \ -- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -- xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \ -- grep 'current ar archive' | \ -- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do -- $STRIP -g "$f" --done -+find "$RPM_BUILD_ROOT" -type f | \ -+ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -+ xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0 --- -2.21.0 - diff --git a/SOURCES/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch b/SOURCES/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch deleted file mode 100644 index 809f065..0000000 --- a/SOURCES/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 60066aba510b3ff4a7db092021aae71948e3f8be Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Thu, 4 Jun 2020 11:18:01 +0300 -Subject: [PATCH] Fix python ts.addErase() not raising exception on not-found - packages - -The code would only raise an exception if TransactionSetCore.addErase() -returned an error, but the catch is that with many kinds of argument -types we'd silently skip the whole addition because no headers were found. -This looks to be a regression introduced some eleven years ago in -commit 9b20c706a4f93266450fae2f94007343b2e8fd9e. - -As a special case, a match iterator argument will not raise an exception -if it doesn't actually match anything. - -Fixes: #1214 ---- - python/rpm/transaction.py | 26 +++++++++++++++----------- - tests/rpmpython.at | 22 ++++++++++++++++++++++ - 2 files changed, 37 insertions(+), 11 deletions(-) - -diff --git a/python/rpm/transaction.py b/python/rpm/transaction.py -index 7c4a551d3..3c9ddb207 100644 ---- a/python/rpm/transaction.py -+++ b/python/rpm/transaction.py -@@ -91,14 +91,22 @@ class TransactionSet(TransactionSetCore): - - def addErase(self, item): - hdrs = [] -- if isinstance(item, rpm.hdr): -- hdrs = [item] -- elif isinstance(item, rpm.mi): -+ # match iterators are passed on as-is -+ if isinstance(item, rpm.mi): - hdrs = item -- elif isinstance(item, int): -- hdrs = self.dbMatch(rpm.RPMDBI_PACKAGES, item) -- elif isinstance(item, _string_types): -- hdrs = self.dbMatch(rpm.RPMDBI_LABEL, item) -+ elif isinstance(item, rpm.hdr): -+ hdrs.append(item) -+ elif isinstance(item, (int, _string_types)): -+ if isinstance(item, int): -+ dbi = rpm.RPMDBI_PACKAGES -+ else: -+ dbi = rpm.RPMDBI_LABEL -+ -+ for h in self.dbMatch(dbi, item): -+ hdrs.append(h) -+ -+ if not hdrs: -+ raise rpm.error("package not installed") - else: - raise TypeError("invalid type %s" % type(item)) - -@@ -106,10 +114,6 @@ class TransactionSet(TransactionSetCore): - if not TransactionSetCore.addErase(self, h): - raise rpm.error("package not installed") - -- # garbage collection should take care but just in case... -- if isinstance(hdrs, rpm.mi): -- del hdrs -- - def run(self, callback, data): - rc = TransactionSetCore.run(self, callback, data, self._probFilter) - -diff --git a/tests/rpmpython.at b/tests/rpmpython.at -index 3a7c251f1..de39c8417 100644 ---- a/tests/rpmpython.at -+++ b/tests/rpmpython.at -@@ -201,6 +201,28 @@ for e in ts: - [foo-1.0-1.noarch] - ) - -+RPMPY_TEST([add erasure to transaction],[ -+ts = rpm.ts() -+for i in ['foo', 1234]: -+ myprint('addErase %s' % i) -+ try: -+ ts.addErase(i) -+ except rpm.error as err: -+ myprint(err) -+myprint('addErase mi') -+mi = ts.dbMatch('name', 'foo') -+try: -+ ts.addErase(mi) -+except rpm.error as err: -+ myprint(err) -+], -+[addErase foo -+package not installed -+addErase 1234 -+package not installed -+addErase mi] -+) -+ - RPMPY_TEST([add bogus package to transaction 1],[ - ts = rpm.ts() - h = rpm.hdr() --- -2.26.2 - diff --git a/SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch b/SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch deleted file mode 100644 index b3c2f4b..0000000 --- a/SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch +++ /dev/null @@ -1,50 +0,0 @@ -From ed6c5573c09611ff9522ed290ef9d1ba717d8019 Mon Sep 17 00:00:00 2001 -Message-Id: -From: Panu Matilainen -Date: Thu, 21 Nov 2019 12:22:45 +0200 -Subject: [PATCH] Fix resource leaks on zstd open error paths - -If zstd stream initialization fails, the opened fd and the stream -itself are leaked. Handle error exit in a central label. ---- - rpmio/rpmio.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c -index 243942411..10ba20cd6 100644 ---- a/rpmio/rpmio.c -+++ b/rpmio/rpmio.c -@@ -1128,13 +1128,13 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode) - if ((flags & O_ACCMODE) == O_RDONLY) { /* decompressing */ - if ((_stream = (void *) ZSTD_createDStream()) == NULL - || ZSTD_isError(ZSTD_initDStream(_stream))) { -- return NULL; -+ goto err; - } - nb = ZSTD_DStreamInSize(); - } else { /* compressing */ - if ((_stream = (void *) ZSTD_createCStream()) == NULL - || ZSTD_isError(ZSTD_initCStream(_stream, level))) { -- return NULL; -+ goto err; - } - nb = ZSTD_CStreamOutSize(); - } -@@ -1149,6 +1149,14 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode) - zstd->b = xmalloc(nb); - - return zstd; -+ -+err: -+ fclose(fp); -+ if ((flags & O_ACCMODE) == O_RDONLY) -+ ZSTD_freeDStream(_stream); -+ else -+ ZSTD_freeCStream(_stream); -+ return NULL; - } - - static FD_t zstdFdopen(FD_t fd, int fdno, const char * fmode) --- -2.23.0 - diff --git a/SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch b/SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch deleted file mode 100644 index b39c52b..0000000 --- a/SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 6b6c4d881dc6fc99f949dac4aaf9a513542f9956 Mon Sep 17 00:00:00 2001 -Message-Id: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Wed, 3 Oct 2018 15:22:55 +0300 -Subject: [PATCH 1/5] Honor PYTHON from configure when running tests - -Pass PYTHON from configure down through all the nutty layers of make -to allow running test-suite with Python 3. In theory that is. - -(cherry picked from commit dcd5ab67c40b543f22b07df8c1028c34b94a7929) ---- - tests/Makefile.am | 1 + - tests/atlocal.in | 3 ++- - tests/local.at | 2 +- - 3 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/tests/Makefile.am b/tests/Makefile.am -index eaf817cc2..21ca216a8 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -117,6 +117,7 @@ atlocal: atlocal.in Makefile - -e "s,[@]usrlibdir[@],$(libdir)," \ - -e "s,[@]execprefix[@],$(exec_prefix)," \ - -e "s,[@]RPMCONFIGDIR[@],$(rpmconfigdir)," \ -+ -e "s,[@]PYTHON[@],$(PYTHON)," \ - < $(srcdir)/atlocal.in > atlocal - DISTCLEANFILES = atlocal - EXTRA_DIST += atlocal.in -diff --git a/tests/atlocal.in b/tests/atlocal.in -index d7d837f45..3b1474b56 100644 ---- rpm-4.14.3/tests/atlocal.in.orig 2020-04-28 14:19:26.866602968 +0200 -+++ rpm-4.14.3/tests/atlocal.in 2020-04-28 14:21:07.977910054 +0200 -@@ -3,7 +3,8 @@ - PATH="${abs_builddir}/testing@rpmbindir@:${abs_builddir}/testing@usrbindir@:$PATH" - export PATH - --PYLIBDIR=`python2 -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))"` -+PYTHON=@PYTHON@ -+PYLIBDIR=$(${PYTHON} -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))") - PYTHONPATH="${abs_builddir}/testing${PYLIBDIR}" - export PYTHONPATH - ---- rpm-4.14.3/tests/local.at.orig 2020-04-28 14:28:33.106664317 +0200 -+++ rpm-4.14.3/tests/local.at 2020-04-28 14:29:02.064038653 +0200 -@@ -18,7 +18,7 @@ - sys.stdout.write('%s\n' % msg) - $1 - EOF --python2 test.py -+${PYTHON} test.py test.py - ]]) - - m4_define([RPMPY_CHECK],[ diff --git a/SOURCES/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch b/SOURCES/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch deleted file mode 100644 index 35f12c2..0000000 --- a/SOURCES/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch +++ /dev/null @@ -1,656 +0,0 @@ -From 84920f898315d09a57a3f1067433eaeb7de5e830 Mon Sep 17 00:00:00 2001 -Message-Id: <84920f898315d09a57a3f1067433eaeb7de5e830.1554884444.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Fri, 22 Feb 2019 19:44:16 +0200 -Subject: [PATCH] In Python 3, return all our string data as surrogate-escaped - utf-8 strings - -In the almost ten years of rpm sort of supporting Python 3 bindings, quite -obviously nobody has actually tried to use them. There's a major mismatch -between what the header API outputs (bytes) and what all the other APIs -accept (strings), resulting in hysterical TypeErrors all over the place, -including but not limited to labelCompare() (RhBug:1631292). Also a huge -number of other places have been returning strings and silently assuming -utf-8 through use of Py_BuildValue("s", ...), which will just irrevocably -fail when non-utf8 data is encountered. - -The politically Python 3-correct solution would be declaring all our data -as bytes with unspecified encoding - that's exactly what it historically is. -However doing so would by definition break every single rpm script people -have developed on Python 2. And when 99% of the rpm content in the world -actually is utf-8 encoded even if it doesn't say so (and in recent times -packages even advertise themselves as utf-8 encoded), the bytes-only route -seems a wee bit too draconian, even to this grumpy old fella. - -Instead, route all our string returns through a single helper macro -which on Python 2 just does what we always did, but in Python 3 converts -the data to surrogate-escaped utf-8 strings. This makes stuff "just work" -out of the box pretty much everywhere even with Python 3 (including -our own test-suite!), while still allowing to handle the non-utf8 case. -Handling the non-utf8 case is a bit more uglier but still possible, -which is exactly how you want corner-cases to be. There might be some -uses for retrieving raw byte data from the header, but worrying about -such an API is a case for some other rainy day, for now we mostly only -care that stuff works again. - -Also add test-cases for mixed data source labelCompare() and -non-utf8 insert to + retrieve from header. ---- - python/header-py.c | 2 +- - python/rpmds-py.c | 8 ++++---- - python/rpmfd-py.c | 6 +++--- - python/rpmfi-py.c | 24 ++++++++++++------------ - python/rpmfiles-py.c | 26 +++++++++++++------------- - python/rpmkeyring-py.c | 2 +- - python/rpmmacro-py.c | 2 +- - python/rpmmodule.c | 2 +- - python/rpmps-py.c | 8 ++++---- - python/rpmstrpool-py.c | 2 +- - python/rpmsystem-py.h | 7 +++++++ - python/rpmtd-py.c | 2 +- - python/rpmte-py.c | 16 ++++++++-------- - python/rpmts-py.c | 11 ++++++----- - python/spec-py.c | 8 ++++---- - tests/local.at | 1 + - tests/rpmpython.at | 34 ++++++++++++++++++++++++++++++++++ - 17 files changed, 102 insertions(+), 59 deletions(-) - -diff --git a/python/header-py.c b/python/header-py.c -index c9d54e869..93c241cb7 100644 ---- a/python/header-py.c -+++ b/python/header-py.c -@@ -231,7 +231,7 @@ static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds) - return NULL; - } - -- result = Py_BuildValue("s", r); -+ result = utf8FromString(r); - free(r); - - return result; -diff --git a/python/rpmds-py.c b/python/rpmds-py.c -index 39b26628e..ecc9af9d5 100644 ---- a/python/rpmds-py.c -+++ b/python/rpmds-py.c -@@ -31,19 +31,19 @@ rpmds_Ix(rpmdsObject * s) - static PyObject * - rpmds_DNEVR(rpmdsObject * s) - { -- return Py_BuildValue("s", rpmdsDNEVR(s->ds)); -+ return utf8FromString(rpmdsDNEVR(s->ds)); - } - - static PyObject * - rpmds_N(rpmdsObject * s) - { -- return Py_BuildValue("s", rpmdsN(s->ds)); -+ return utf8FromString(rpmdsN(s->ds)); - } - - static PyObject * - rpmds_EVR(rpmdsObject * s) - { -- return Py_BuildValue("s", rpmdsEVR(s->ds)); -+ return utf8FromString(rpmdsEVR(s->ds)); - } - - static PyObject * -@@ -261,7 +261,7 @@ rpmds_subscript(rpmdsObject * s, PyObject * key) - - ix = (int) PyInt_AsLong(key); - rpmdsSetIx(s->ds, ix); -- return Py_BuildValue("s", rpmdsDNEVR(s->ds)); -+ return utf8FromString(rpmdsDNEVR(s->ds)); - } - - static PyMappingMethods rpmds_as_mapping = { -diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c -index 85fb0cd24..4b05cce5f 100644 ---- a/python/rpmfd-py.c -+++ b/python/rpmfd-py.c -@@ -327,17 +327,17 @@ static PyObject *rpmfd_get_closed(rpmfdObject *s) - static PyObject *rpmfd_get_name(rpmfdObject *s) - { - /* XXX: rpm returns non-paths with [mumble], python files use */ -- return Py_BuildValue("s", Fdescr(s->fd)); -+ return utf8FromString(Fdescr(s->fd)); - } - - static PyObject *rpmfd_get_mode(rpmfdObject *s) - { -- return Py_BuildValue("s", s->mode); -+ return utf8FromString(s->mode); - } - - static PyObject *rpmfd_get_flags(rpmfdObject *s) - { -- return Py_BuildValue("s", s->flags); -+ return utf8FromString(s->flags); - } - - static PyGetSetDef rpmfd_getseters[] = { -diff --git a/python/rpmfi-py.c b/python/rpmfi-py.c -index 8d2f926d0..db405c231 100644 ---- a/python/rpmfi-py.c -+++ b/python/rpmfi-py.c -@@ -41,19 +41,19 @@ rpmfi_DX(rpmfiObject * s, PyObject * unused) - static PyObject * - rpmfi_BN(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiBN(s->fi)); -+ return utf8FromString(rpmfiBN(s->fi)); - } - - static PyObject * - rpmfi_DN(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiDN(s->fi)); -+ return utf8FromString(rpmfiDN(s->fi)); - } - - static PyObject * - rpmfi_FN(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiFN(s->fi)); -+ return utf8FromString(rpmfiFN(s->fi)); - } - - static PyObject * -@@ -98,7 +98,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused) - { - char *digest = rpmfiFDigestHex(s->fi, NULL); - if (digest) { -- PyObject *dig = Py_BuildValue("s", digest); -+ PyObject *dig = utf8FromString(digest); - free(digest); - return dig; - } else { -@@ -109,7 +109,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused) - static PyObject * - rpmfi_FLink(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiFLink(s->fi)); -+ return utf8FromString(rpmfiFLink(s->fi)); - } - - static PyObject * -@@ -133,13 +133,13 @@ rpmfi_FMtime(rpmfiObject * s, PyObject * unused) - static PyObject * - rpmfi_FUser(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiFUser(s->fi)); -+ return utf8FromString(rpmfiFUser(s->fi)); - } - - static PyObject * - rpmfi_FGroup(rpmfiObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmfiFGroup(s->fi)); -+ return utf8FromString(rpmfiFGroup(s->fi)); - } - - static PyObject * -@@ -155,7 +155,7 @@ rpmfi_FClass(rpmfiObject * s, PyObject * unused) - - if ((FClass = rpmfiFClass(s->fi)) == NULL) - FClass = ""; -- return Py_BuildValue("s", FClass); -+ return utf8FromString(FClass); - } - - static PyObject * -@@ -208,7 +208,7 @@ rpmfi_iternext(rpmfiObject * s) - Py_INCREF(Py_None); - PyTuple_SET_ITEM(result, 0, Py_None); - } else -- PyTuple_SET_ITEM(result, 0, Py_BuildValue("s", FN)); -+ PyTuple_SET_ITEM(result, 0, utf8FromString(FN)); - PyTuple_SET_ITEM(result, 1, PyLong_FromLongLong(FSize)); - PyTuple_SET_ITEM(result, 2, PyInt_FromLong(FMode)); - PyTuple_SET_ITEM(result, 3, PyInt_FromLong(FMtime)); -@@ -222,12 +222,12 @@ rpmfi_iternext(rpmfiObject * s) - Py_INCREF(Py_None); - PyTuple_SET_ITEM(result, 10, Py_None); - } else -- PyTuple_SET_ITEM(result, 10, Py_BuildValue("s", FUser)); -+ PyTuple_SET_ITEM(result, 10, utf8FromString(FUser)); - if (FGroup == NULL) { - Py_INCREF(Py_None); - PyTuple_SET_ITEM(result, 11, Py_None); - } else -- PyTuple_SET_ITEM(result, 11, Py_BuildValue("s", FGroup)); -+ PyTuple_SET_ITEM(result, 11, utf8FromString(FGroup)); - PyTuple_SET_ITEM(result, 12, rpmfi_Digest(s, NULL)); - - } else -@@ -313,7 +313,7 @@ rpmfi_subscript(rpmfiObject * s, PyObject * key) - - ix = (int) PyInt_AsLong(key); - rpmfiSetFX(s->fi, ix); -- return Py_BuildValue("s", rpmfiFN(s->fi)); -+ return utf8FromString(rpmfiFN(s->fi)); - } - - static PyMappingMethods rpmfi_as_mapping = { -diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c -index bc07dbeaf..557246cae 100644 ---- a/python/rpmfiles-py.c -+++ b/python/rpmfiles-py.c -@@ -41,37 +41,37 @@ static PyObject *rpmfile_dx(rpmfileObject *s) - static PyObject *rpmfile_name(rpmfileObject *s) - { - char * fn = rpmfilesFN(s->files, s->ix); -- PyObject *o = Py_BuildValue("s", fn); -+ PyObject *o = utf8FromString(fn); - free(fn); - return o; - } - - static PyObject *rpmfile_basename(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesBN(s->files, s->ix)); -+ return utf8FromString(rpmfilesBN(s->files, s->ix)); - } - - static PyObject *rpmfile_dirname(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); -+ return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); - } - - static PyObject *rpmfile_orig_name(rpmfileObject *s) - { - char * fn = rpmfilesOFN(s->files, s->ix); -- PyObject *o = Py_BuildValue("s", fn); -+ PyObject *o = utf8FromString(fn); - free(fn); - return o; - } - - static PyObject *rpmfile_orig_basename(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesOBN(s->files, s->ix)); -+ return utf8FromString(rpmfilesOBN(s->files, s->ix)); - } - - static PyObject *rpmfile_orig_dirname(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); -+ return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); - } - static PyObject *rpmfile_mode(rpmfileObject *s) - { -@@ -105,17 +105,17 @@ static PyObject *rpmfile_nlink(rpmfileObject *s) - - static PyObject *rpmfile_linkto(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFLink(s->files, s->ix)); -+ return utf8FromString(rpmfilesFLink(s->files, s->ix)); - } - - static PyObject *rpmfile_user(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFUser(s->files, s->ix)); -+ return utf8FromString(rpmfilesFUser(s->files, s->ix)); - } - - static PyObject *rpmfile_group(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFGroup(s->files, s->ix)); -+ return utf8FromString(rpmfilesFGroup(s->files, s->ix)); - } - - static PyObject *rpmfile_fflags(rpmfileObject *s) -@@ -145,7 +145,7 @@ static PyObject *rpmfile_digest(rpmfileObject *s) - NULL, &diglen); - if (digest) { - char * hex = pgpHexStr(digest, diglen); -- PyObject *o = Py_BuildValue("s", hex); -+ PyObject *o = utf8FromString(hex); - free(hex); - return o; - } -@@ -154,17 +154,17 @@ static PyObject *rpmfile_digest(rpmfileObject *s) - - static PyObject *rpmfile_class(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFClass(s->files, s->ix)); -+ return utf8FromString(rpmfilesFClass(s->files, s->ix)); - } - - static PyObject *rpmfile_caps(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFCaps(s->files, s->ix)); -+ return utf8FromString(rpmfilesFCaps(s->files, s->ix)); - } - - static PyObject *rpmfile_langs(rpmfileObject *s) - { -- return Py_BuildValue("s", rpmfilesFLangs(s->files, s->ix)); -+ return utf8FromString(rpmfilesFLangs(s->files, s->ix)); - } - - static PyObject *rpmfile_links(rpmfileObject *s) -diff --git a/python/rpmkeyring-py.c b/python/rpmkeyring-py.c -index d5f131e42..8968e0513 100644 ---- a/python/rpmkeyring-py.c -+++ b/python/rpmkeyring-py.c -@@ -38,7 +38,7 @@ static PyObject *rpmPubkey_new(PyTypeObject *subtype, - static PyObject * rpmPubkey_Base64(rpmPubkeyObject *s) - { - char *b64 = rpmPubkeyBase64(s->pubkey); -- PyObject *res = Py_BuildValue("s", b64); -+ PyObject *res = utf8FromString(b64); - free(b64); - return res; - } -diff --git a/python/rpmmacro-py.c b/python/rpmmacro-py.c -index 3cb1a51f5..d8a365547 100644 ---- a/python/rpmmacro-py.c -+++ b/python/rpmmacro-py.c -@@ -52,7 +52,7 @@ rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds) - if (rpmExpandMacros(NULL, macro, &str, 0) < 0) - PyErr_SetString(pyrpmError, "error expanding macro"); - else -- res = Py_BuildValue("s", str); -+ res = utf8FromString(str); - free(str); - } - return res; -diff --git a/python/rpmmodule.c b/python/rpmmodule.c -index 3faad23c7..05032edc7 100644 ---- a/python/rpmmodule.c -+++ b/python/rpmmodule.c -@@ -237,7 +237,7 @@ static void addRpmTags(PyObject *module) - - PyModule_AddIntConstant(module, tagname, tagval); - pyval = PyInt_FromLong(tagval); -- pyname = Py_BuildValue("s", shortname); -+ pyname = utf8FromString(shortname); - PyDict_SetItem(dict, pyval, pyname); - Py_DECREF(pyval); - Py_DECREF(pyname); -diff --git a/python/rpmps-py.c b/python/rpmps-py.c -index bdc899a60..902b2ae63 100644 ---- a/python/rpmps-py.c -+++ b/python/rpmps-py.c -@@ -18,12 +18,12 @@ static PyObject *rpmprob_get_type(rpmProblemObject *s, void *closure) - - static PyObject *rpmprob_get_pkgnevr(rpmProblemObject *s, void *closure) - { -- return Py_BuildValue("s", rpmProblemGetPkgNEVR(s->prob)); -+ return utf8FromString(rpmProblemGetPkgNEVR(s->prob)); - } - - static PyObject *rpmprob_get_altnevr(rpmProblemObject *s, void *closure) - { -- return Py_BuildValue("s", rpmProblemGetAltNEVR(s->prob)); -+ return utf8FromString(rpmProblemGetAltNEVR(s->prob)); - } - - static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure) -@@ -38,7 +38,7 @@ static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure) - - static PyObject *rpmprob_get_str(rpmProblemObject *s, void *closure) - { -- return Py_BuildValue("s", rpmProblemGetStr(s->prob)); -+ return utf8FromString(rpmProblemGetStr(s->prob)); - } - - static PyObject *rpmprob_get_num(rpmProblemObject *s, void *closure) -@@ -59,7 +59,7 @@ static PyGetSetDef rpmprob_getseters[] = { - static PyObject *rpmprob_str(rpmProblemObject *s) - { - char *str = rpmProblemString(s->prob); -- PyObject *res = Py_BuildValue("s", str); -+ PyObject *res = utf8FromString(str); - free(str); - return res; - } -diff --git a/python/rpmstrpool-py.c b/python/rpmstrpool-py.c -index 356bd1de5..a56e2b540 100644 ---- a/python/rpmstrpool-py.c -+++ b/python/rpmstrpool-py.c -@@ -44,7 +44,7 @@ static PyObject *strpool_id2str(rpmstrPoolObject *s, PyObject *item) - const char *str = rpmstrPoolStr(s->pool, id); - - if (str) -- ret = PyBytes_FromString(str); -+ ret = utf8FromString(str); - else - PyErr_SetObject(PyExc_KeyError, item); - } -diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h -index 955d60cd3..87c750571 100644 ---- a/python/rpmsystem-py.h -+++ b/python/rpmsystem-py.h -@@ -19,4 +19,11 @@ - #define PyInt_AsSsize_t PyLong_AsSsize_t - #endif - -+/* In Python 3, we return all strings as surrogate-escaped utf-8 */ -+#if PY_MAJOR_VERSION >= 3 -+#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape") -+#else -+#define utf8FromString(_s) PyBytes_FromString(_s) -+#endif -+ - #endif /* H_SYSTEM_PYTHON */ -diff --git a/python/rpmtd-py.c b/python/rpmtd-py.c -index 247c7502a..23ca10517 100644 ---- a/python/rpmtd-py.c -+++ b/python/rpmtd-py.c -@@ -17,7 +17,7 @@ PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass) - - switch (tclass) { - case RPM_STRING_CLASS: -- res = PyBytes_FromString(rpmtdGetString(td)); -+ res = utf8FromString(rpmtdGetString(td)); - break; - case RPM_NUMERIC_CLASS: - res = PyLong_FromLongLong(rpmtdGetNumber(td)); -diff --git a/python/rpmte-py.c b/python/rpmte-py.c -index 99ff2f496..2b3745754 100644 ---- a/python/rpmte-py.c -+++ b/python/rpmte-py.c -@@ -54,49 +54,49 @@ rpmte_TEType(rpmteObject * s, PyObject * unused) - static PyObject * - rpmte_N(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteN(s->te)); -+ return utf8FromString(rpmteN(s->te)); - } - - static PyObject * - rpmte_E(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteE(s->te)); -+ return utf8FromString(rpmteE(s->te)); - } - - static PyObject * - rpmte_V(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteV(s->te)); -+ return utf8FromString(rpmteV(s->te)); - } - - static PyObject * - rpmte_R(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteR(s->te)); -+ return utf8FromString(rpmteR(s->te)); - } - - static PyObject * - rpmte_A(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteA(s->te)); -+ return utf8FromString(rpmteA(s->te)); - } - - static PyObject * - rpmte_O(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteO(s->te)); -+ return utf8FromString(rpmteO(s->te)); - } - - static PyObject * - rpmte_NEVR(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteNEVR(s->te)); -+ return utf8FromString(rpmteNEVR(s->te)); - } - - static PyObject * - rpmte_NEVRA(rpmteObject * s, PyObject * unused) - { -- return Py_BuildValue("s", rpmteNEVRA(s->te)); -+ return utf8FromString(rpmteNEVRA(s->te)); - } - - static PyObject * -diff --git a/python/rpmts-py.c b/python/rpmts-py.c -index 1ddfc9a1e..96e3bb28e 100644 ---- a/python/rpmts-py.c -+++ b/python/rpmts-py.c -@@ -230,8 +230,9 @@ rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data) - - PyEval_RestoreThread(cbInfo->_save); - -- args = Py_BuildValue("(Oissi)", cbInfo->tso, -- rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds)); -+ args = Py_BuildValue("(OiNNi)", cbInfo->tso, -+ rpmdsTagN(ds), utf8FromString(rpmdsN(ds)), -+ utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds)); - result = PyEval_CallObject(cbInfo->cb, args); - Py_DECREF(args); - -@@ -409,7 +410,7 @@ rpmts_HdrCheck(rpmtsObject * s, PyObject *obj) - rpmrc = headerCheck(s->ts, uh, uc, &msg); - Py_END_ALLOW_THREADS; - -- return Py_BuildValue("(is)", rpmrc, msg); -+ return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg)); - } - - static PyObject * -@@ -500,7 +501,7 @@ rpmtsCallback(const void * hd, const rpmCallbackType what, - /* Synthesize a python object for callback (if necessary). */ - if (pkgObj == NULL) { - if (h) { -- pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME)); -+ pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME)); - } else { - pkgObj = Py_None; - Py_INCREF(pkgObj); -@@ -845,7 +846,7 @@ static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure) - - static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure) - { -- return Py_BuildValue("s", rpmtsRootDir(s->ts)); -+ return utf8FromString(rpmtsRootDir(s->ts)); - } - - static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure) -diff --git a/python/spec-py.c b/python/spec-py.c -index 4efdbf4bf..70b796531 100644 ---- a/python/spec-py.c -+++ b/python/spec-py.c -@@ -57,7 +57,7 @@ static PyObject *pkgGetSection(rpmSpecPkg pkg, int section) - { - char *sect = rpmSpecPkgGetSection(pkg, section); - if (sect != NULL) { -- PyObject *ps = PyBytes_FromString(sect); -+ PyObject *ps = utf8FromString(sect); - free(sect); - if (ps != NULL) - return ps; -@@ -158,7 +158,7 @@ static PyObject * getSection(rpmSpec spec, int section) - { - const char *sect = rpmSpecGetSection(spec, section); - if (sect) { -- return Py_BuildValue("s", sect); -+ return utf8FromString(sect); - } - Py_RETURN_NONE; - } -@@ -208,8 +208,8 @@ static PyObject * spec_get_sources(specObject *s, void *closure) - - rpmSpecSrcIter iter = rpmSpecSrcIterInit(s->spec); - while ((source = rpmSpecSrcIterNext(iter)) != NULL) { -- PyObject *srcUrl = Py_BuildValue("(sii)", -- rpmSpecSrcFilename(source, 1), -+ PyObject *srcUrl = Py_BuildValue("(Nii)", -+ utf8FromString(rpmSpecSrcFilename(source, 1)), - rpmSpecSrcNum(source), - rpmSpecSrcFlags(source)); - if (!srcUrl) { -diff --git a/tests/local.at b/tests/local.at -index 02ead66c9..42eef1c75 100644 ---- a/tests/local.at -+++ b/tests/local.at -@@ -10,6 +10,7 @@ rm -rf "${abs_builddir}"/testing`rpm --eval '%_dbpath'`/* - - m4_define([RPMPY_RUN],[[ - cat << EOF > test.py -+# coding=utf-8 - import rpm, sys - dbpath=rpm.expandMacro('%_dbpath') - rpm.addMacro('_dbpath', '${abs_builddir}/testing%s' % dbpath) -diff --git a/tests/rpmpython.at b/tests/rpmpython.at -index ff77f868c..58f3e84a6 100644 ---- a/tests/rpmpython.at -+++ b/tests/rpmpython.at -@@ -106,6 +106,25 @@ None - 'rpm.hdr' object has no attribute '__foo__'] - ) - -+RPMPY_TEST([non-utf8 data in header],[ -+str = u'älämölö' -+enc = 'iso-8859-1' -+b = str.encode(enc) -+h = rpm.hdr() -+h['group'] = b -+d = h['group'] -+try: -+ # python 3 -+ t = bytes(d, 'utf-8', 'surrogateescape') -+except TypeError: -+ # python 2 -+ t = bytes(d) -+res = t.decode(enc) -+myprint(str == res) -+], -+[True] -+) -+ - RPMPY_TEST([invalid header data],[ - h1 = rpm.hdr() - h1['basenames'] = ['bing', 'bang', 'bong'] -@@ -125,6 +144,21 @@ for h in [h1, h2]: - /opt/bing,/opt/bang,/flopt/bong] - ) - -+RPMPY_TEST([labelCompare],[ -+v = '1.0' -+r = '1' -+e = 3 -+h = rpm.hdr() -+h['name'] = 'testpkg' -+h['version'] = v -+h['release'] = r -+h['epoch'] = e -+myprint(rpm.labelCompare((str(h['epoch']), h['version'], h['release']), -+ (str(e), v, r))) -+], -+[0] -+) -+ - RPMPY_TEST([vfyflags API],[ - ts = rpm.ts() - dlv = ts.getVfyFlags() --- -2.20.1 - diff --git a/SOURCES/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch b/SOURCES/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch deleted file mode 100644 index ccf39e3..0000000 --- a/SOURCES/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 9ad4b813483f8cf6c641f56387248b33b6dfc570 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 20 Feb 2019 15:28:30 +0200 -Subject: [PATCH] Introduce patch_nums and source_nums Lua variables in spec - context - -The pre-existing patches and sources variables only contains patch and -source filenames, but for some purposes we need access to the associated -patch/source number too. We could use the number as the table key, but -that would make the table unsorted. That we could handle in our own -macros, but would break compatibility for anybody doing custom stuff -with these. So it seems best to just add parallel arrays sharing the -same array indexes so that both values are as easily accessible, -depending on the need. - -Inspired by Pascal "Pixel" Rigaux's similar patch in Mageia, which differs -in that the number-arrays are indexed by the filename and is unordered. -Compared to patches/sources this seemed against principle of least -surprise, and is slightly more cumbersome int the case we want the number -directly, such as in PR #626. The variable names differ so there -is no incompatibility to that downstream patch introduced. ---- - build/parsePreamble.c | 9 +++++++++ - build/spec.c | 3 ++- - 2 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/build/parsePreamble.c b/build/parsePreamble.c -index 812c41f9f..9520bac4b 100644 ---- a/build/parsePreamble.c -+++ b/build/parsePreamble.c -@@ -322,6 +322,15 @@ static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag - rpmluaSetVar(lua, var); - rpmluavFree(var); - rpmluaPop(lua); -+ -+ what = (flag & RPMBUILD_ISPATCH) ? "patch_nums" : "source_nums"; -+ rpmluaPushTable(lua, what); -+ var = rpmluavNew(); -+ rpmluavSetListMode(var, 1); -+ rpmluavSetValueNum(var, p->num); -+ rpmluaSetVar(lua, var); -+ rpmluavFree(var); -+ rpmluaPop(lua); - } - #endif - free(body); -diff --git a/build/spec.c b/build/spec.c -index 80eaca611..55095c6ce 100644 ---- a/build/spec.c -+++ b/build/spec.c -@@ -305,7 +305,8 @@ rpmSpec newSpec(void) - #ifdef WITH_LUA - /* make sure patches and sources tables always exist */ - rpmlua lua = NULL; /* global state */ -- const char * luavars[] = { "patches", "sources", NULL, }; -+ const char * luavars[] = { "patches", "sources", -+ "patch_nums", "source_nums", NULL, }; - for (const char **vp = luavars; vp && *vp; vp++) { - rpmluaDelVar(lua, *vp); - rpmluaPushTable(lua, *vp); --- -2.26.2 - diff --git a/SOURCES/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch b/SOURCES/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch deleted file mode 100644 index a95ea7c..0000000 --- a/SOURCES/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch +++ /dev/null @@ -1,41 +0,0 @@ -From e811c7ec0b4d2685b63b61803e3952466b1a4ac6 Mon Sep 17 00:00:00 2001 -Message-Id: -From: marxin -Date: Wed, 28 Nov 2018 10:52:01 +0100 -Subject: [PATCH] Isolate %_smp_build_ncpus and use it for %_smp_mflags. - -Refactor _smp_build_ncpus and use it in %_smp_mflags. Note that now -having a single CPU, %_smp_mflags is expanded to '-j1'. - -XXX: hand-edited to remove double quotes as per upstream commit - 9b6fdc65ef0507fff04a69c88e085a7a26711839 which isn't applicable - directly due to other changes - ---- - platform.in | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/platform.in b/platform.in -index 3eb67b55b..2dd951f87 100644 ---- a/platform.in -+++ b/platform.in -@@ -50,11 +50,14 @@ - - # Maximum number of CPU's to use when building, 0 for unlimited. - #%_smp_ncpus_max 0 --%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\ -+ -+%_smp_build_ncpus %([ -z "$RPM_BUILD_NCPUS" ] \\\ - && RPM_BUILD_NCPUS="`/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\ - ncpus_max=%{?_smp_ncpus_max}; \\\ - if [ -n "$ncpus_max" ] && [ "$ncpus_max" -gt 0 ] && [ "$RPM_BUILD_NCPUS" -gt "$ncpus_max" ]; then RPM_BUILD_NCPUS="$ncpus_max"; fi; \\\ -- if [ "$RPM_BUILD_NCPUS" -gt 1 ]; then echo "-j$RPM_BUILD_NCPUS"; fi) -+ echo "$RPM_BUILD_NCPUS";) -+ -+%_smp_mflags -j%{_smp_build_ncpus} - - #============================================================================== - # ---- Build policy macros. --- -2.23.0 - diff --git a/SOURCES/0001-Make-check-buildroot-check-the-build-files-in-parall.patch b/SOURCES/0001-Make-check-buildroot-check-the-build-files-in-parall.patch deleted file mode 100644 index bba479b..0000000 --- a/SOURCES/0001-Make-check-buildroot-check-the-build-files-in-parall.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f23af97c4135013d3134a17c881014fb6e9589c8 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Tue, 30 Apr 2019 17:12:35 +0200 -Subject: [PATCH] Make check-buildroot check the build files in parallel - -Thanks to Denys Vlasenko for pointing this out in rhbz#1704353 ---- - scripts/check-buildroot | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/scripts/check-buildroot b/scripts/check-buildroot -index 0cfb34f39..f91dc767b 100755 ---- a/scripts/check-buildroot -+++ b/scripts/check-buildroot -@@ -24,11 +24,12 @@ fi - - tmp=$(mktemp ${TMPDIR:-/tmp}/cbr.XXXXXX) - trap "rm -f $tmp" EXIT -+NCPUS=${RPM_BUILD_NCPUS:-1} - - find "$RPM_BUILD_ROOT" \! \( \ - -name '*.pyo' -o -name '*.pyc' -o -name '*.elc' -o -name '.packlist' \ - \) -type f -print0 | \ -- LANG=C xargs -0r grep -F "$RPM_BUILD_ROOT" >$tmp -+ LANG=C xargs -0r -P$NCPUS -n16 grep -F "$RPM_BUILD_ROOT" >>$tmp - - test -s "$tmp" && { - cat "$tmp" --- -2.21.0 - diff --git a/SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch b/SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch deleted file mode 100644 index 320385d..0000000 --- a/SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 57b4f21634429ccd29d47cf93ec0841f70b68404 Mon Sep 17 00:00:00 2001 -Message-Id: <57b4f21634429ccd29d47cf93ec0841f70b68404.1545311826.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Tue, 18 Sep 2018 11:02:36 +0300 -Subject: [PATCH] Mark elements with associated problems as failed - -An element with a problem can not possibly succeed so mark these failures -early. Doesn't make much of a difference as problems will prevent the -transaction from starting in the first place but it makes sense anyway. ---- - lib/rpmte.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/rpmte.c b/lib/rpmte.c -index 4bdeeaf68..c5d614f67 100644 ---- a/lib/rpmte.c -+++ b/lib/rpmte.c -@@ -703,6 +703,7 @@ static void appendProblem(rpmte te, rpmProblemType type, - if (te->probs == NULL) - te->probs = rpmpsCreate(); - rpmpsAppendProblem(te->probs, p); -+ rpmteMarkFailed(te); - } - rpmProblemFree(p); - } --- -2.19.2 - diff --git a/SOURCES/0001-Only-read-through-payload-on-verify-if-actually-need.patch b/SOURCES/0001-Only-read-through-payload-on-verify-if-actually-need.patch deleted file mode 100644 index f77c039..0000000 --- a/SOURCES/0001-Only-read-through-payload-on-verify-if-actually-need.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 362c4401979f896de1e69a3e18d33954953912cc Mon Sep 17 00:00:00 2001 -Message-Id: <362c4401979f896de1e69a3e18d33954953912cc.1554983588.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Tue, 11 Dec 2018 13:21:47 +0200 -Subject: [PATCH] Only read through payload on verify if actually needed - -If none of our verify items ranges over the payload, then why bother? - -To do this, add an internal rpmvs API to get it's range, and use -that to decide whether trip over the payload is needed or not. -In addition, the payload digest tag needs to be grabbed outside of the -condition to avoid depending on other values. The details including -RPMVSF_NEEDPAYLOAD will be handled internally to rpmvs which makes it -actually nicer code-wise too. ---- - lib/rpmchecksig.c | 8 ++++---- - lib/rpmvs.c | 12 ++++++++++++ - lib/rpmvs.h | 3 +++ - 3 files changed, 19 insertions(+), 4 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 1ba72a45e..810f7153d 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -187,11 +187,11 @@ rpmRC rpmpkgRead(struct rpmvs_s *vs, FD_t fd, - /* Finalize header range */ - rpmvsFiniRange(vs, RPMSIG_HEADER); - -- /* Unless disabled, read the payload, generating digest(s) on the fly. */ -- if (!(rpmvsFlags(vs) & RPMVSF_NEEDPAYLOAD)) { -- /* Fish interesting tags from the main header. This is a bit hacky... */ -- rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST); -+ /* Fish interesting tags from the main header. This is a bit hacky... */ -+ rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST); - -+ /* If needed and not explicitly disabled, read the payload as well. */ -+ if (rpmvsRange(vs) & RPMSIG_PAYLOAD) { - /* Initialize digests ranging over the payload only */ - rpmvsInitRange(vs, RPMSIG_PAYLOAD); - -diff --git a/lib/rpmvs.c b/lib/rpmvs.c -index 622e48011..0d475af86 100644 ---- a/lib/rpmvs.c -+++ b/lib/rpmvs.c -@@ -396,6 +396,18 @@ void rpmvsFiniRange(struct rpmvs_s *sis, int range) - } - } - -+int rpmvsRange(struct rpmvs_s *vs) -+{ -+ int range = 0; -+ for (int i = 0; i < vs->nsigs; i++) { -+ if (rpmsinfoDisabled(&vs->sigs[i], vs->vsflags)) -+ continue; -+ range |= vs->sigs[i].range; -+ } -+ -+ return range; -+} -+ - static int sinfoCmp(const void *a, const void *b) - { - const struct rpmsinfo_s *sa = a; ---- rpm-4.14.3/lib/rpmvs.h.orig 2020-04-28 10:57:19.727347211 +0200 -+++ rpm-4.14.3/lib/rpmvs.h 2020-04-28 10:57:43.622612015 +0200 -@@ -66,6 +66,8 @@ - - void rpmvsFiniRange(struct rpmvs_s *sis, int range); - -+int rpmvsRange(struct rpmvs_s *vs); -+ - int rpmvsVerify(struct rpmvs_s *sis, int type, - rpmsinfoCb cb, void *cbdata); - --- -2.20.1 diff --git a/SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch b/SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch deleted file mode 100644 index 0e28f75..0000000 --- a/SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch +++ /dev/null @@ -1,27 +0,0 @@ -From d97d7b71de158660eb96b4f11d40b6626b85521a Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Tue, 16 Apr 2019 09:50:57 +0200 -Subject: [PATCH] Pass RPM_BUILD_NCPUS to build scripts - -Use %_smp_build_ncpus instead of the initial value ---- - macros.in | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/macros.in b/macros.in -index fc587997d..a15e46f26 100644 ---- a/macros.in -+++ b/macros.in -@@ -807,7 +807,8 @@ package or when debugging this package.\ - RPM_OPT_FLAGS=\"%{optflags}\"\ - RPM_ARCH=\"%{_arch}\"\ - RPM_OS=\"%{_os}\"\ -- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\ -+ RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\ -+ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ - RPM_DOC_DIR=\"%{_docdir}\"\ - export RPM_DOC_DIR\ - RPM_PACKAGE_NAME=\"%{NAME}\"\ --- -2.21.0 - diff --git a/SOURCES/0001-RPM-with-Copy-on-Write.patch b/SOURCES/0001-RPM-with-Copy-on-Write.patch deleted file mode 100644 index 4f4e8ba..0000000 --- a/SOURCES/0001-RPM-with-Copy-on-Write.patch +++ /dev/null @@ -1,1344 +0,0 @@ -From 7bd31ce85b2ed377f495c31fcea2422a07739e24 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -Date: Fri, 8 Nov 2019 09:29:43 -0800 -Subject: [PATCH 01/30] RPM with Copy on Write - -This is part of https://fedoraproject.org/wiki/Changes/RPMCoW - -The majority of changes are in two new programs: - -= rpm2extents - -Modeled as a 'stream processor'. It reads a regular .rpm file on stdin, -and produces a modified .rpm file on stdout. The lead, signature and -headers are preserved 1:1 to allow all the normal metadata inspection, -signature verification to work as expected. Only the 'payload' is -modified. - -The primary motivation for this tool is to re-organize the payload as a -sequence of raw file extents (hence the name). The files are organized -by their digest identity instead of path/filename. If any digest is -repeated, then the file is skipped/de-duped. Only regular files are -represented. All other entries like directories, symlinks, devices are -fully described in the headers and are omitted. - -The files are padded so they start on `sysconf(_SC_PAGESIZE)` boundries -to permit 'reflink' syscalls to work in the `reflink` plugin. - -At the end of the file is a footer with 3 sections: - -1. List of calculated digests of the input stream. This is used in - `librepo` because the file *written* is a derivative, and not the - same as the repo metadata describes. `rpm2extents` takes one or more - positional arguments that described which digest algorithms are - desired. This is often just `SHA256`. This program is only measuring - and recording the digest - it does not express an opinion on whether - the file is correct. Due to the API on most compression libraries - directly reading the source file, the whole file digest is measured - using a subprocess and pipes. I don't love it, but it works. -2. Sorted List of file content digests + offset pairs. This is used in - the plugin with a trivial binary search to locate the start of file - content. The size is not needed because it's part of normal headers. -3. (offset of 1., offset of 2., 8 byte MAGIC value) triple - -= reflink plugin - -Looks for the 8 byte magic value at the end of the rpm file. If present -it alters the `RPMTAG_PAYLOADFORMAT` in memory to `clon`, and reads in -the digest-> offset table. - -`rpmPackageFilesInstall()` in `fsm.c` is -modified to alter the enumeration strategy from -`rpmfiNewArchiveReader()` to `rpmfilesIter()` if not `cpio`. This is -needed because there is no cpio to enumerate. In the same function, if -`rpmpluginsCallFsmFilePre()` returns `RPMRC_PLUGIN_CONTENTS` then -`fsmMkfile()` is skipped as it is assumed the plugin did the work. - -The majority of the work is in `reflink_fsm_file_pre()` - the per file -hook for RPM plugins. If the file enumerated in -`rpmPackageFilesInstall()` is a regular file, this function will look up -the offset in the digest->offset table and will try to reflink it, then -fall back to a regular copy. If reflinking does work: we will have -reflinked a whole number of pages, so we truncate the file to the -expected size. Therefore installing most files does involve two writes: -the reflink of the full size, then a fork/copy on write for the last -page worth. - -If the file passed to `reflink_fsm_file_pre()` is anything other than a -regular file, it return `RPMRC_OK` so the normal mechanics of -`rpmPackageFilesInstall()` are used. That handles directories, symlinks -and other non file types. - -= New API for internal use - -1. `rpmReadPackageRaw()` is used within `rpm2extents` to read all the - headers without trying to validate signatures. This eliminates the - runtime dependency on rpmdb. -2. `rpmteFd()` exposes the Fd behind the rpmte, so plugins can interact - with the rpm itself. -3. `RPMRC_PLUGIN_CONTENTS` in `rpmRC_e` for use in - `rpmpluginsCallFsmFilePre()` specifically. -4. `pgpStringVal()` is used to help parse the command line in - `rpm2extents` - the positional arguments are strings, and this - converts the values back to the values in the table. - -Nothing has been removed, and none of the changes are intended to be -used externally, so I don't think a soname bump is warranted here. ---- - Makefile.am | 6 +- - lib/depends.c | 2 + - lib/fsm.c | 45 +++- - lib/package.c | 40 ++++ - lib/rpmlib.h | 9 + - lib/rpmplugins.c | 21 +- - lib/rpmte.c | 5 + - lib/rpmte.h | 2 + - lib/rpmtypes.h | 3 +- - macros.in | 1 + - plugins/Makefile.am | 4 + - plugins/reflink.c | 340 +++++++++++++++++++++++++++++ - rpm2extents.c | 519 ++++++++++++++++++++++++++++++++++++++++++++ - rpmio/rpmpgp.c | 10 + - rpmio/rpmpgp.h | 9 + - 15 files changed, 1004 insertions(+), 12 deletions(-) - create mode 100644 plugins/reflink.c - create mode 100644 rpm2extents.c - -diff --git a/Makefile.am b/Makefile.am -index e5c75d7b4..288668819 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -99,7 +99,7 @@ pkginclude_HEADERS += build/rpmfc.h - pkginclude_HEADERS += build/rpmspec.h - - --bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec -+bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec rpm2extents - if WITH_ARCHIVE - bin_PROGRAMS += rpm2archive - endif -@@ -154,6 +154,10 @@ rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h - rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la - rpm2cpio_LDADD += @WITH_POPT_LIB@ - -+rpm2extents_SOURCES = rpm2extents.c debug.h system.h -+rpm2extents_LDADD = lib/librpm.la rpmio/librpmio.la -+rpm2extents_LDADD += @WITH_POPT_LIB@ -+ - rpm2archive_SOURCES = rpm2archive.c debug.h system.h - rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la - rpm2archive_LDADD += @WITH_POPT_LIB@ @WITH_ARCHIVE_LIB@ -diff --git a/lib/depends.c b/lib/depends.c -index 30234df3d..8998afcd3 100644 ---- a/lib/depends.c -+++ b/lib/depends.c -@@ -81,6 +81,8 @@ 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 935a0a5c6..90193c749 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -8,6 +8,7 @@ - - #include - #include -+#include - #if WITH_CAP - #include - #endif -@@ -19,6 +20,7 @@ - - #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" -@@ -52,6 +54,7 @@ struct filedata_s { - int stage; - int setmeta; - int skip; -+ int plugin_contents; - rpmFileAction action; - const char *suffix; - char *fpath; -@@ -891,6 +894,14 @@ 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); -+ bool cpio = true; -+ -+ if (payloadfmt && rstreq(payloadfmt, "clon")) { -+ cpio = false; -+ } -+ - /* transaction id used for temporary path suffix while installing */ - rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); - -@@ -911,12 +922,23 @@ 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 = false; -+ switch (rc) { -+ case RPMRC_OK: -+ setFileState(fs, fx); -+ break; -+ case RPMRC_PLUGIN_CONTENTS: -+ fp->plugin_contents = true; -+ // 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); -@@ -924,10 +946,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (rc) - goto exit; - -- fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -- if (fi == NULL) { -- rc = RPMERR_BAD_MAGIC; -- 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); - } - - /* Detect and create directories not explicitly in package. */ -@@ -969,8 +995,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firstlink, &firstlinkfile); -+ if(fp->plugin_contents) { -+ rc = RPMRC_OK; -+ }else { -+ rc = fsmMkfile(fi, fp, files, psm, nodigest, -+ &firstlink, &firstlinkfile); -+ } - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -1078,6 +1108,7 @@ 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/lib/package.c b/lib/package.c -index 281275029..90bd0d8a7 100644 ---- a/lib/package.c -+++ b/lib/package.c -@@ -404,5 +404,45 @@ exit: - return rc; - } - -+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp) -+{ -+ char *msg = NULL; -+ hdrblob sigblob = hdrblobCreate(); -+ hdrblob blob = hdrblobCreate(); -+ 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); -+ if (rc != RPMRC_OK) -+ goto exit; -+ -+ rc = hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, blob, &msg); -+ if (rc != RPMRC_OK) -+ goto exit; -+ -+ rc = hdrblobImport(sigblob, 0, &sigh, &msg); -+ if (rc) -+ goto exit; - -+ rc = hdrblobImport(blob, 0, &h, &msg); -+ if (rc) -+ goto exit; - -+ *sigp = headerLink(sigh); -+ *hdrp = headerLink(h); -+ -+exit: -+ if (rc != RPMRC_OK && msg) -+ rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg); -+ hdrblobFree(sigblob); -+ hdrblobFree(blob); -+ headerFree(sigh); -+ headerFree(h); -+ free(msg); -+ -+ return rc; -+} -diff --git a/lib/rpmlib.h b/lib/rpmlib.h -index 0879d04e5..a09ba0daf 100644 ---- a/lib/rpmlib.h -+++ b/lib/rpmlib.h -@@ -155,6 +155,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg); - rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, - const char * fn, Header * hdrp); - -+/** \ingroup header -+ * Return package signature, header from file handle, no verification. -+ * @param fd file handle -+ * @param[out] sigp address of header (or NULL) -+ * @param[out] hdrp address of header (or NULL) -+ * @return RPMRC_OK on success -+ */ -+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp); -+ - /** \ingroup rpmtrans - * Install source package. - * @param ts transaction set -diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index 62d75c4cf..c5084d398 100644 ---- a/lib/rpmplugins.c -+++ b/lib/rpmplugins.c -@@ -356,13 +356,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, - plugin_fsm_file_pre_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_pre); -- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) { -- rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name); -- rc = RPMRC_FAIL; -+ if (hookFunc) { -+ hook_rc = hookFunc(plugin, fi, path, file_mode, op); -+ if (hook_rc == RPMRC_FAIL) { -+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre 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; -+ } -+ } - } - } - -diff --git a/lib/rpmte.c b/lib/rpmte.c -index 3663604e7..d43dc41ad 100644 ---- a/lib/rpmte.c -+++ b/lib/rpmte.c -@@ -423,6 +423,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd) - return NULL; - } - -+FD_t rpmteFd(rpmte te) -+{ -+ return (te != NULL ? te->fd : NULL); -+} -+ - fnpyKey rpmteKey(rpmte te) - { - return (te != NULL ? te->key : NULL); -diff --git a/lib/rpmte.h b/lib/rpmte.h -index 81acf7a19..6fc0a9f91 100644 ---- a/lib/rpmte.h -+++ b/lib/rpmte.h -@@ -209,6 +209,8 @@ const char * rpmteNEVR(rpmte te); - */ - const char * rpmteNEVRA(rpmte te); - -+FD_t rpmteFd(rpmte te); -+ - /** \ingroup rpmte - * Retrieve key from transaction element. - * @param te transaction element -diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h -index e8e69b506..af2611e9e 100644 ---- a/lib/rpmtypes.h -+++ b/lib/rpmtypes.h -@@ -106,7 +106,8 @@ typedef enum rpmRC_e { - RPMRC_NOTFOUND = 1, /*!< Generic not found code. */ - RPMRC_FAIL = 2, /*!< Generic failure code. */ - RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */ -- RPMRC_NOKEY = 4 /*!< Public key is unavailable. */ -+ RPMRC_NOKEY = 4, /*!< Public key is unavailable. */ -+ RPMRC_PLUGIN_CONTENTS = 5 /*!< fsm_file_pre plugin is handling content */ - } rpmRC; - - #ifdef __cplusplus -diff --git a/macros.in b/macros.in -index e90cefa9a..363252b0f 100644 ---- a/macros.in -+++ b/macros.in -@@ -1143,6 +1143,7 @@ package or when debugging this package.\ - - # Transaction plugin macros - %__plugindir %{_libdir}/rpm-plugins -+%__transaction_reflink %{__plugindir}/reflink.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 3a929d0ce..ad0d3bce7 100644 ---- a/plugins/Makefile.am -+++ b/plugins/Makefile.am -@@ -42,6 +42,10 @@ prioreset_la_SOURCES = prioreset.c - prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la - plugins_LTLIBRARIES += prioreset.la - -+reflink_la_SOURCES = reflink.c -+reflink_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la -+plugins_LTLIBRARIES += reflink.la -+ - syslog_la_SOURCES = syslog.c - syslog_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la - plugins_LTLIBRARIES += syslog.la -diff --git a/plugins/reflink.c b/plugins/reflink.c -new file mode 100644 -index 000000000..d7f19acd9 ---- /dev/null -+++ b/plugins/reflink.c -@@ -0,0 +1,340 @@ -+#include "system.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#if defined(__linux__) -+#include /* For FICLONE */ -+#endif -+ -+#include -+#include "lib/rpmlib.h" -+#include "lib/rpmplugin.h" -+#include "lib/rpmte_internal.h" -+#include -+#include "rpmio/rpmio_internal.h" -+ -+ -+#include "debug.h" -+ -+#include -+ -+/* use hash table to remember inode -> ix (for rpmfilesFN(ix)) lookups */ -+#undef HASHTYPE -+#undef HTKEYTYPE -+#undef HTDATATYPE -+#define HASHTYPE inodeIndexHash -+#define HTKEYTYPE rpm_ino_t -+#define HTDATATYPE int -+#include "lib/rpmhash.H" -+#include "lib/rpmhash.C" -+ -+/* -+We use this in find to indicate a key wasn't found. This is an unrecoverable -+error, but we can at least show a decent error. 0 is never a valid offset -+because it's the offset of the start of the file. -+*/ -+#define NOT_FOUND 0 -+ -+#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; -+ char *buffer; -+ -+ /* stuff that's used/updated per psm */ -+ uint32_t keys, keysize; -+ -+ // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) -+ unsigned char *table; -+ FD_t fd; -+ rpmfiles files; -+ inodeIndexHash inodeIndexes; -+}; -+ -+typedef struct reflink_state_s * reflink_state; -+ -+static int inodeCmp(rpm_ino_t a, rpm_ino_t b) -+{ -+ return (a != b); -+} -+ -+static unsigned int inodeId(rpm_ino_t a) -+{ -+ /* rpm_ino_t is uint32_t so maps safely to unsigned int */ -+ return (unsigned int)a; -+} -+ -+static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { -+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); -+ -+ /* -+ IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and -+ length arguments to be aligned to the fundamental block size. -+ -+ The value of "fundamental block size" is directly related to the system's -+ page size, so we should use that. -+ */ -+ state->fundamental_block_size = sysconf(_SC_PAGESIZE); -+ state->buffer = rcalloc(1, BUFFER_SIZE); -+ rpmPluginSetData(plugin, state); -+ -+ return RPMRC_OK; -+} -+ -+static void reflink_cleanup(rpmPlugin plugin) { -+ reflink_state state = rpmPluginGetData(plugin); -+ free(state->buffer); -+ free(state); -+} -+ -+static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { -+ 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")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; -+ } -+ rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); -+ Header h = rpmteHeader(te); -+ -+ /* 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(magic)), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); -+ return RPMRC_FAIL; -+ } -+ rpm_loff_t table_start; -+ len = sizeof(table_start); -+ if (Fread(&table_start, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -+ return RPMRC_FAIL; -+ } -+ if (Fseek(state->fd, table_start, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -+ return RPMRC_FAIL; -+ } -+ len = sizeof(state->keys); -+ if (Fread(&state->keys, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -+ return RPMRC_FAIL; -+ } -+ len = sizeof(state->keysize); -+ if (Fread(&state->keysize, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -+ return RPMRC_FAIL; -+ } -+ rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); -+ // now get digest table if there is a reason to have one. -+ if (state->keys == 0 || state->keysize == 0) { -+ // no files (or no digests(!)) -+ state->table = NULL; -+ } else { -+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -+ state->table = rcalloc(1, table_size); -+ if (Fread(state->table, table_size, 1, state->fd) != table_size) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -+ return RPMRC_FAIL; -+ } -+ state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); -+ } -+ -+ // seek back to original location -+ // might not be needed if we seek to offset immediately -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; -+} -+ -+static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) -+{ -+ reflink_state state = rpmPluginGetData(plugin); -+ state->files = rpmfilesFree(state->files); -+ if (state->table) { -+ free(state->table); -+ state->table = NULL; -+ } -+ if (state->inodeIndexes) { -+ inodeIndexHashFree(state->inodeIndexes); -+ state->inodeIndexes = NULL; -+ } -+ return RPMRC_OK; -+} -+ -+ -+// have a prototype, warnings system -+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"), 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); -+ if (entry == NULL) { -+ return NOT_FOUND; -+ } -+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -+ return offset; -+} -+ -+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) -+{ -+ struct file_clone_range fcr; -+ rpm_loff_t size; -+ int dst, rc; -+ int *hlix; -+ -+ reflink_state state = rpmPluginGetData(plugin); -+ if (state->table == NULL) { -+ // no table means rpm is not in reflink format, so leave. Now. -+ return RPMRC_OK; -+ } -+ if (op == FA_TOUCH) { -+ // we're not overwriting an existing file -+ return RPMRC_OK; -+ } -+ fcr.dest_offset = 0; -+ if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { -+ rpm_ino_t inode = rpmfiFInode(fi); -+ /* 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)) { -+ // entry is in table, use hard link -+ char *fn = rpmfilesFN(state->files, hlix[0]); -+ if (link(fn, path) != 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); -+ free(fn); -+ return RPMRC_FAIL; -+ } -+ free(fn); -+ return RPMRC_PLUGIN_CONTENTS; -+ } -+ /* if we didn't hard link, then we'll track this inode as being created soon */ -+ if (rpmfiFNlink(fi) > 1) { -+ /* minor optimization: only store files with more than one link */ -+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -+ } -+ /* derived from wfd_open in fsm.c */ -+ mode_t old_umask = umask(0577); -+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -+ umask(old_umask); -+ if (dst == -1) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); -+ return RPMRC_FAIL; -+ } -+ size = rpmfiFSize(fi); -+ if (size > 0) { -+ /* round src_length down to fundamental_block_size multiple */ -+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -+ if ((size % state->fundamental_block_size) > 0) { -+ /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ -+ fcr.src_length += state->fundamental_block_size; -+ } -+ fcr.src_fd = Fileno(state->fd); -+ if (fcr.src_fd == -1) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -+ return RPMRC_FAIL; -+ } -+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -+ if (fcr.src_offset == NOT_FOUND) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -+ return RPMRC_FAIL; -+ } -+ rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -+ rc = ioctl(dst, FICLONERANGE, &fcr); -+ if (rc) { -+ rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); -+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ rpm_loff_t left = size; -+ size_t len, read, written; -+ while (left) { -+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -+ read = Fread(state->buffer, len, 1, state->fd); -+ if (read != len) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ written = write(dst, state->buffer, len); -+ if (read != written) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ left -= len; -+ } -+ } else { -+ /* reflink worked, so truncate */ -+ rc = ftruncate(dst, size); -+ if (rc) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); -+ return RPMRC_FAIL; -+ } -+ } -+ } -+ close(dst); -+ 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_pre = reflink_fsm_file_pre, -+}; -diff --git a/rpm2extents.c b/rpm2extents.c -new file mode 100644 -index 000000000..5662b86a6 ---- /dev/null -+++ b/rpm2extents.c -@@ -0,0 +1,519 @@ -+/* rpm2extents: convert payload to inline extents */ -+ -+#include "system.h" -+ -+#include /* rpmReadPackageFile .. */ -+#include -+#include -+#include -+#include -+ -+#include -+#include "lib/rpmlead.h" -+#include "lib/signature.h" -+#include "lib/header_internal.h" -+#include "rpmio/rpmio_internal.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "debug.h" -+ -+/* hash of void * (pointers) to file digests to offsets within output. -+ The length of the key depends on what the FILEDIGESTALGO is. -+ */ -+#undef HASHTYPE -+#undef HTKEYTYPE -+#undef HTDATATYPE -+#define HASHTYPE digestSet -+#define HTKEYTYPE const unsigned char * -+#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; -+}; -+ -+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit); -+ -+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit) -+{ -+ return (unit - (pos % unit)) % unit; -+} -+ -+static int digestor( -+ FD_t fdi, -+ FD_t fdo, -+ FD_t validationo, -+ uint8_t algos[], -+ 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; -+ } -+ -+ len = sizeof(fdilength); -+ if (Fwrite(&fdilength, len, 1, validationo) != 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")); -+ goto exit; -+ } -+ for (algo = 0; algo < algos_len; algo++) -+ { -+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -+ -+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -+ algo_name_len = (uint32_t)strlen(algo_name); -+ algo_digest_len = (uint32_t)filedigest_len; -+ -+ len = sizeof(algo_name_len); -+ if (Fwrite(&algo_name_len, len, 1, validationo) != len) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write validation algo name length\n") -+ ); -+ goto exit; -+ } -+ len = sizeof(algo_digest_len); -+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write number of bytes for validation 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")); -+ goto exit; -+ } -+ if ( -+ Fwrite( -+ filedigest, -+ algo_digest_len, -+ 1, -+ validationo -+ ) != algo_digest_len -+ ) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write validation digest value %u, %zu\n"), -+ algo_digest_len, -+ filedigest_len -+ ); -+ goto exit; -+ } -+ } -+ rc = RPMRC_OK; -+exit: -+ return rc; -+} -+ -+static rpmRC process_package(FD_t fdi, FD_t validationi) -+{ -+ uint32_t diglen; -+ /* GNU C extension: can use diglen from outer context */ -+ int digestSetCmp(const unsigned char * a, const unsigned char * b) -+ { -+ return memcmp(a, b, diglen); -+ } -+ -+ unsigned int digestSetHash(const unsigned char * digest) -+ { -+ /* assumes sizeof(unsigned int) < diglen */ -+ return *(unsigned int *)digest; -+ } -+ -+ int digestoffsetCmp(const void * a, const void * b) -+ { -+ return digestSetCmp( -+ ((struct digestoffset *)a)->digest, -+ ((struct digestoffset *)b)->digest -+ ); -+ } -+ -+ FD_t fdo; -+ FD_t gzdi; -+ Header h, sigh; -+ long fundamental_block_size = sysconf(_SC_PAGESIZE); -+ rpmRC rc = RPMRC_OK; -+ rpm_mode_t mode; -+ char *rpmio_flags = NULL, *zeros; -+ const unsigned char *digest; -+ rpm_loff_t pos, size, pad, validation_pos; -+ uint32_t offset_ix = 0; -+ size_t len; -+ int next = 0; -+ -+ fdo = fdDup(STDOUT_FILENO); -+ -+ if (rpmReadPackageRaw(fdi, &sigh, &h)) -+ { -+ fprintf(stderr, _("Error reading package\n")); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (rpmLeadWrite(fdo, h)) -+ { -+ fprintf( -+ stderr, -+ _("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)); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) -+ { -+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -+ 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); -+ } -+ -+ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ -+ free(rpmio_flags); -+ -+ if (gzdi == NULL) -+ { -+ fprintf(stderr, _("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 -+ ); -+ -+ /* 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); -+ -+ zeros = xcalloc(fundamental_block_size, 1); -+ -+ 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) -+ { -+ fprintf(stderr, _("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) -+ { -+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -+ goto exit; -+ } -+ pos += size; -+ } -+ Fclose(gzdi); /* XXX gzdi == fdi */ -+ -+ qsort( -+ offsets, -+ (size_t)offset_ix, -+ sizeof(struct digestoffset), -+ digestoffsetCmp -+ ); -+ -+ len = sizeof(offset_ix); -+ if (Fwrite(&offset_ix, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("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")); -+ 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")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write offset\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ } -+ validation_pos = ( -+ pos + sizeof(offset_ix) + sizeof(diglen) + -+ offset_ix * (diglen + sizeof(rpm_loff_t)) -+ ); -+ -+ ssize_t validation_len = ufdCopy(validationi, fdo); -+ if (validation_len == -1) -+ { -+ fprintf(stderr, _("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) -+ { -+ fprintf(stderr, _("Unable to write final padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ zeros = _free(zeros); -+ if (Fwrite(&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 table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ uint64_t magic = MAGIC; -+ len = sizeof(magic); -+ if (Fwrite(&magic, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+exit: -+ rpmfilesFree(files); -+ rpmfiFree(fi); -+ headerFree(h); -+ return rc; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ rpmRC rc; -+ int cprc = 0; -+ uint8_t algos[argc - 1]; -+ int mainpipefd[2]; -+ int metapipefd[2]; -+ pid_t cpid, w; -+ int wstatus; -+ -+ xsetprogname(argv[0]); /* Portability call -- see system.h */ -+ rpmReadConfigFiles(NULL, NULL); -+ -+ 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) -+ { -+ fprintf( -+ stderr, -+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") -+ ); -+ exit(EXIT_FAILURE); -+ } -+ -+ for (int x = 0; x < (argc - 1); x++) -+ { -+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -+ { -+ fprintf( -+ stderr, -+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -+ argv[x + 1] -+ ); -+ exit(EXIT_FAILURE); -+ } -+ } -+ -+ -+ 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, argc - 1); -+ Fclose(validationo); -+ Fclose(fdo); -+ Fclose(fdi); -+ } else { -+ /* parent: main program */ -+ 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. */ -+ 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 failed\n")); -+ 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; -+ } -+ } -+ if (rc != RPMRC_OK) -+ { -+ /* translate rpmRC into generic failure return code. */ -+ return EXIT_FAILURE; -+ } -+ return EXIT_SUCCESS; -+} -diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index 015c15a5c..7b972b4a6 100644 ---- a/rpmio/rpmpgp.c -+++ b/rpmio/rpmpgp.c -@@ -283,6 +283,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se) - return vs->val; - } - -+int pgpStringVal(pgpValType type, const char *str, uint8_t *val) -+{ -+ pgpValTbl tbl = pgpValTable(type); -+ if (tbl == NULL) return -1; -+ int v = pgpValTok(tbl, str, str + strlen(str)); -+ if (v == -1) return -1; -+ *val = (uint8_t)v; -+ return 0; -+} -+ - /** \ingroup rpmpgp - * Decode length from 1, 2, or 5 octet body length encoding, used in - * new format packet headers and V4 signature subpackets. -diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h -index c53e29b01..2b57318ba 100644 ---- a/rpmio/rpmpgp.h -+++ b/rpmio/rpmpgp.h -@@ -973,6 +973,15 @@ typedef rpmFlags rpmDigestFlags; - */ - const char * pgpValString(pgpValType type, uint8_t val); - -+/** \ingroup rpmpgp -+ * Return OpenPGP value for a string. -+ * @param type type of value -+ * @param str string to lookup -+ * @param[out] val byte value associated with string -+ * @return 0 on success else -1 -+ */ -+int pgpStringVal(pgpValType type, const char *str, uint8_t *val); -+ - /** \ingroup rpmpgp - * Return (native-endian) integer from big-endian representation. - * @param s pointer to big-endian integer --- -2.35.1 - diff --git a/SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch b/SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch deleted file mode 100644 index e91db6f..0000000 --- a/SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch +++ /dev/null @@ -1,41 +0,0 @@ -From aea53a4aead8bd71f519df35fcffd9eec76fbc01 Mon Sep 17 00:00:00 2001 -Message-Id: -From: Panu Matilainen -Date: Tue, 26 Feb 2019 11:27:51 +0200 -Subject: [PATCH] Return NULL string as None from utf8FromString() - -Commit 84920f898315d09a57a3f1067433eaeb7de5e830 regressed dnf install -to segfault at the end due to some NULL string passed to strlen(). -Check for NULL and return it as None, make it an inline function -to make this saner. ---- - python/rpmsystem-py.h | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h -index 87c750571..25938464a 100644 ---- a/python/rpmsystem-py.h -+++ b/python/rpmsystem-py.h -@@ -19,11 +19,17 @@ - #define PyInt_AsSsize_t PyLong_AsSsize_t - #endif - -+static inline PyObject * utf8FromString(const char *s) -+{ - /* In Python 3, we return all strings as surrogate-escaped utf-8 */ - #if PY_MAJOR_VERSION >= 3 --#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape") -+ if (s != NULL) -+ return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape"); - #else --#define utf8FromString(_s) PyBytes_FromString(_s) -+ if (s != NULL) -+ return PyBytes_FromString(s); - #endif -+ Py_RETURN_NONE; -+} - - #endif /* H_SYSTEM_PYTHON */ --- -2.20.1 - diff --git a/SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch b/SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch deleted file mode 100644 index fb1e8d4..0000000 --- a/SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch +++ /dev/null @@ -1,37 +0,0 @@ -From cb6aa82dbc10d554f8d234e934ae7c77e39a3ce2 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Tue, 12 Jan 2021 13:35:23 +0200 -Subject: [PATCH] Unblock signals in forked scriptlets - -Since commit c5f82d3f6223ebd0c5cc0a07ea60393ae7284929 we've blocked -most signals during transactions, which makes sense to rpm itself but -the signal mask is inherited to childs and carried even across exec(), -so all scriptlets are executing with those signals blocked as well. -Which in turn does not make sense, the scriptlets could run stuff that -actually depends on signal delivery (such as SIGALARM in RhBug:1913765). - -Unblock all signals for forked scriptlet execution (Lua scriptlets are -totally different as they execute in-process for now) ---- - lib/rpmscript.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/lib/rpmscript.c b/lib/rpmscript.c -index 2ae3378f7..c69d29554 100644 ---- a/lib/rpmscript.c -+++ b/lib/rpmscript.c -@@ -152,6 +152,11 @@ static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes, - FD_t scriptFd, FD_t out) - { - int xx; -+ sigset_t set; -+ -+ /* Unmask all signals, the scripts may need them */ -+ sigfillset(&set); -+ sigprocmask(SIG_UNBLOCK, &set, NULL); - - /* SIGPIPE is ignored in rpm, reset to default for the scriptlet */ - (void) signal(SIGPIPE, SIG_DFL); --- -2.29.2 - diff --git a/SOURCES/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch b/SOURCES/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch deleted file mode 100644 index 2863a98..0000000 --- a/SOURCES/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch +++ /dev/null @@ -1,58 +0,0 @@ -From fc2c986d8f5e4174885ae377750185339636f062 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Mon, 15 Apr 2019 15:46:09 +0200 -Subject: [PATCH] Use RPM_BUILD_NCPUS in brp-strip-static-archive - -to speed the script up for large number of files to be looked at. -Use xargs -P instead of find -exec. - -Add xargs to the test environment - -Resolves rhbz1691822 ---- - scripts/brp-strip-static-archive | 8 +++++--- - tests/Makefile.am | 2 +- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive -index ddd3b2422..4dc449061 100755 ---- a/scripts/brp-strip-static-archive -+++ b/scripts/brp-strip-static-archive -@@ -5,6 +5,7 @@ if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then - fi - - STRIP=${1:-strip} -+NCPUS=${RPM_BUILD_NCPUS:-1} - - case `uname -a` in - Darwin*) exit 0 ;; -@@ -12,9 +13,10 @@ Darwin*) exit 0 ;; - esac - - # Strip static libraries. --for f in `find "$RPM_BUILD_ROOT" -type f -a -exec file {} \; | \ -- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -+for f in `find "$RPM_BUILD_ROOT" -type f | \ -+ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -+ xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \ - grep 'current ar archive' | \ -- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do -+ sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do - $STRIP -g "$f" - done -diff --git a/tests/Makefile.am b/tests/Makefile.am -index e2d759d82..ad9549a68 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -144,7 +144,7 @@ populate_testing: - for d in dev etc magic tmp var; do if [ ! -d testing/$${d} ]; then mkdir testing/$${d}; fi; done - for node in urandom stdin stderr stdout null full; do ln -s /dev/$${node} testing/dev/$${node}; done - for cf in hosts resolv.conf passwd shadow group gshadow mtab ; do [ -f /etc/$${cf} ] && ln -s /etc/$${cf} testing/etc/$${cf}; done -- for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done -+ for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils xargs; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done - for d in /proc /sys /selinux /etc/selinux; do if [ -d $${d} ]; then ln -s $${d} testing/$${d}; fi; done - (cd testing/magic && file -C) - HOME=$(abs_builddir)/testing gpg2 --import ${abs_srcdir}/data/keys/*.secret --- -2.21.0 - diff --git a/SOURCES/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch b/SOURCES/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch deleted file mode 100644 index 6053ca2..0000000 --- a/SOURCES/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 9aae21d7610a7e8067ae932f36d1c8bb8583fe59 Mon Sep 17 00:00:00 2001 -From: Pavlina Moravcova Varekova -Date: Wed, 5 Jun 2019 06:07:00 +0200 -Subject: [PATCH] Use [ ] in condition to avoid sub processes in - find-debuginfo.sh (#735) - -Introduced in commit 1da9e83, spotted by covscan. - -Modified to fix another covscan warning ---- - scripts/find-debuginfo.sh | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/find-debuginfo.sh b/scripts/find-debuginfo.sh -index 23286139e..d75da1108 100755 ---- a/scripts/find-debuginfo.sh -+++ b/scripts/find-debuginfo.sh -@@ -213,7 +213,7 @@ if test -n "$build_id_seed" -a "$no_recompute_build_id" = "true"; then - exit 2 - fi - --if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then -+if [ "$strip_g" = "true" ] && [ "$strip_glibs" = "true" ]; then - echo >&2 "*** ERROR: -g and --g-libs cannot be used together" - exit 2 - fi --- -2.21.0 - diff --git a/SOURCES/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch b/SOURCES/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch deleted file mode 100644 index 14cf5d2..0000000 --- a/SOURCES/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 09d181d78c16e1751779586c606e85c11f360407 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Tue, 25 Jun 2019 18:04:20 +0200 -Subject: [PATCH] Use newline as a delimiter to avoid xargs messing up file - names with quotes - -which is the default behaviour otherwise. - -Fixes rhbz#1721348 ---- - scripts/brp-strip-static-archive | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive -index 13d9a098b..f7fb26b87 100755 ---- a/scripts/brp-strip-static-archive -+++ b/scripts/brp-strip-static-archive -@@ -15,4 +15,4 @@ esac - # Strip static libraries. - find "$RPM_BUILD_ROOT" -type f | \ - grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -- xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0 -+ xargs -d '\n' -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -d '\n' -I\{\} $STRIP -g \{\}" ARG0 --- -2.21.0 - diff --git a/SOURCES/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch b/SOURCES/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch deleted file mode 100644 index 9e9ee45..0000000 --- a/SOURCES/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 9cbc1fe444b048c3f7cf5ea09ab650d1c146d54a Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 20 Feb 2019 14:49:19 +0200 -Subject: [PATCH] When doing the same thing more than once, use a loop... - -No functional changes but this'll simplify the next commit quite a bit. ---- - build/spec.c | 12 +++++------- - 1 file changed, 5 insertions(+), 7 deletions(-) - -diff --git a/build/spec.c b/build/spec.c -index e414e4102..80eaca611 100644 ---- a/build/spec.c -+++ b/build/spec.c -@@ -303,15 +303,13 @@ rpmSpec newSpec(void) - spec->pool = rpmstrPoolCreate(); - - #ifdef WITH_LUA -- { - /* make sure patches and sources tables always exist */ - rpmlua lua = NULL; /* global state */ -- rpmluaDelVar(lua, "patches"); -- rpmluaDelVar(lua, "sources"); -- rpmluaPushTable(lua, "patches"); -- rpmluaPushTable(lua, "sources"); -- rpmluaPop(lua); -- rpmluaPop(lua); -+ const char * luavars[] = { "patches", "sources", NULL, }; -+ for (const char **vp = luavars; vp && *vp; vp++) { -+ rpmluaDelVar(lua, *vp); -+ rpmluaPushTable(lua, *vp); -+ rpmluaPop(lua); - } - #endif - return spec; --- -2.26.2 - diff --git a/SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch b/SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch deleted file mode 100644 index 54dd45f..0000000 --- a/SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 8fefd2bd21b30996ad0748eab6baadf915610642 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Thu, 13 Aug 2020 13:29:10 +0300 -Subject: [PATCH] Work around buggy signature region preventing resigning - (RhBug:1851508) - -Various proprietary packages in the wild have subtly malformed data -in the signature header, in particular wrt the immutable region size, -presumably from using some in-house/3rd party signing tools which do -not understand the immutable region business at all. This can prevent -resigning and signature deletion on such packages due to the more -thorough checking that rpmsign does. - -As the old wisdom goes, be liberal in what you accept... we can easily -work around the crud by just taking a fresh copy of the contents that -are legit as such (otherwise the package would be uninstallable). - - -Adjusted for 4.14.3 - ---- rpm-4.14.3/sign/rpmgensig.c.orig 2020-10-29 16:00:38.785229048 +0100 -+++ rpm-4.14.3/sign/rpmgensig.c 2020-10-29 16:08:55.997791345 +0100 -@@ -401,12 +401,19 @@ - - if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) { - oh = headerCopyLoad(utd->data); -- nh = headerCopy(oh); -- headerFree(oh); - rpmtdFreeData(utd); -+ } else { -+ /* XXX should we warn if the immutable region is corrupt/missing? */ -+ oh = headerLink(*hdrp); -+ } -+ -+ if (oh) { -+ /* Perform a copy to eliminate crud from buggy signing tools etc */ -+ nh = headerCopy(oh); - headerFree(*hdrp); - *hdrp = headerLink(nh); - headerFree(nh); -+ headerFree(oh); - } - } - diff --git a/SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch b/SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch deleted file mode 100644 index ac45734..0000000 --- a/SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch +++ /dev/null @@ -1,490 +0,0 @@ -From ce6e8556a8f93327d6de0446f21ac5e549861d82 Mon Sep 17 00:00:00 2001 -Message-Id: -From: Mark Wielaard -Date: Mon, 17 Jun 2019 11:23:24 +0200 -Subject: [PATCH 1/3] debugedit: Refactor reading/writing of relocated values. - -This refactors the reading and writing of relocated values into seperate -helper functions (setup_relbuf and update_rela_data). It will be easier -to reuse this code in case we want to read/write relocated values in other -sections than DEBUG_INFO. The only functional change is that we explicitly -track whether the relocation data is updated, and only explicitly update -and write out the relocation data if so. In the case there were no strp -or stmt updates, there will also not be any relocation updates, even if -there is relocation data available. - -All new debugedit testcases pass before and after this refactoring. ---- - tools/debugedit.c | 395 +++++++++++++++++++++++++--------------------- - 1 file changed, 216 insertions(+), 179 deletions(-) - -diff --git a/tools/debugedit.c b/tools/debugedit.c -index 4be85b979..cf9cc3ca9 100644 ---- a/tools/debugedit.c -+++ b/tools/debugedit.c -@@ -401,13 +401,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v) - relend). Might just update the addend. So relocations need to be - updated at the end. */ - -+static bool rel_updated; -+ - #define do_write_32_relocated(ptr,val) ({ \ - if (relptr && relptr < relend && relptr->ptr == ptr) \ - { \ - if (reltype == SHT_REL) \ - do_write_32 (ptr, val - relptr->addend); \ - else \ -- relptr->addend = val; \ -+ { \ -+ relptr->addend = val; \ -+ rel_updated = true; \ -+ } \ - } \ - else \ - do_write_32 (ptr,val); \ -@@ -418,14 +423,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v) - ptr += 4; \ - }) - --static struct -+typedef struct debug_section - { - const char *name; - unsigned char *data; - Elf_Data *elf_data; - size_t size; - int sec, relsec; -- } debug_sections[] = -+ REL *relbuf; -+ REL *relend; -+ } debug_section; -+ -+static debug_section debug_sections[] = - { - #define DEBUG_INFO 0 - #define DEBUG_ABBREV 1 -@@ -458,6 +467,201 @@ static struct - { NULL, NULL, NULL, 0, 0, 0 } - }; - -+static int -+rel_cmp (const void *a, const void *b) -+{ -+ REL *rela = (REL *) a, *relb = (REL *) b; -+ -+ if (rela->ptr < relb->ptr) -+ return -1; -+ -+ if (rela->ptr > relb->ptr) -+ return 1; -+ -+ return 0; -+} -+ -+/* Returns a malloced REL array, or NULL when there are no relocations -+ for this section. When there are relocations, will setup relend, -+ as the last REL, and reltype, as SHT_REL or SHT_RELA. */ -+static void -+setup_relbuf (DSO *dso, debug_section *sec, int *reltype) -+{ -+ int ndx, maxndx; -+ GElf_Rel rel; -+ GElf_Rela rela; -+ GElf_Sym sym; -+ GElf_Addr base = dso->shdr[sec->sec].sh_addr; -+ Elf_Data *symdata = NULL; -+ int rtype; -+ REL *relbuf; -+ Elf_Scn *scn; -+ Elf_Data *data; -+ int i = sec->relsec; -+ -+ /* No relocations, or did we do this already? */ -+ if (i == 0 || sec->relbuf != NULL) -+ { -+ relptr = sec->relbuf; -+ relend = sec->relend; -+ return; -+ } -+ -+ scn = dso->scn[i]; -+ data = elf_getdata (scn, NULL); -+ assert (data != NULL && data->d_buf != NULL); -+ assert (elf_getdata (scn, data) == NULL); -+ assert (data->d_off == 0); -+ assert (data->d_size == dso->shdr[i].sh_size); -+ maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize; -+ relbuf = malloc (maxndx * sizeof (REL)); -+ *reltype = dso->shdr[i].sh_type; -+ if (relbuf == NULL) -+ error (1, errno, "%s: Could not allocate memory", dso->filename); -+ -+ symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL); -+ assert (symdata != NULL && symdata->d_buf != NULL); -+ assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) == NULL); -+ assert (symdata->d_off == 0); -+ assert (symdata->d_size == dso->shdr[dso->shdr[i].sh_link].sh_size); -+ -+ for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) -+ { -+ if (dso->shdr[i].sh_type == SHT_REL) -+ { -+ gelf_getrel (data, ndx, &rel); -+ rela.r_offset = rel.r_offset; -+ rela.r_info = rel.r_info; -+ rela.r_addend = 0; -+ } -+ else -+ gelf_getrela (data, ndx, &rela); -+ gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); -+ /* Relocations against section symbols are uninteresting in REL. */ -+ if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) -+ continue; -+ /* Only consider relocations against .debug_str, .debug_line -+ and .debug_abbrev. */ -+ if (sym.st_shndx != debug_sections[DEBUG_STR].sec -+ && sym.st_shndx != debug_sections[DEBUG_LINE].sec -+ && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) -+ continue; -+ rela.r_addend += sym.st_value; -+ rtype = ELF64_R_TYPE (rela.r_info); -+ switch (dso->ehdr.e_machine) -+ { -+ case EM_SPARC: -+ case EM_SPARC32PLUS: -+ case EM_SPARCV9: -+ if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) -+ goto fail; -+ break; -+ case EM_386: -+ if (rtype != R_386_32) -+ goto fail; -+ break; -+ case EM_PPC: -+ case EM_PPC64: -+ if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) -+ goto fail; -+ break; -+ case EM_S390: -+ if (rtype != R_390_32) -+ goto fail; -+ break; -+ case EM_IA_64: -+ if (rtype != R_IA64_SECREL32LSB) -+ goto fail; -+ break; -+ case EM_X86_64: -+ if (rtype != R_X86_64_32) -+ goto fail; -+ break; -+ case EM_ALPHA: -+ if (rtype != R_ALPHA_REFLONG) -+ goto fail; -+ break; -+#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32) -+ case EM_AARCH64: -+ if (rtype != R_AARCH64_ABS32) -+ goto fail; -+ break; -+#endif -+ case EM_68K: -+ if (rtype != R_68K_32) -+ goto fail; -+ break; -+#if defined(EM_RISCV) && defined(R_RISCV_32) -+ case EM_RISCV: -+ if (rtype != R_RISCV_32) -+ goto fail; -+ break; -+#endif -+ default: -+ fail: -+ error (1, 0, "%s: Unhandled relocation %d in %s section", -+ dso->filename, rtype, sec->name); -+ } -+ relend->ptr = sec->data -+ + (rela.r_offset - base); -+ relend->addend = rela.r_addend; -+ relend->ndx = ndx; -+ ++(relend); -+ } -+ if (relbuf == relend) -+ { -+ free (relbuf); -+ relbuf = NULL; -+ relend = NULL; -+ } -+ else -+ qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); -+ -+ sec->relbuf = relbuf; -+ sec->relend = relend; -+ relptr = relbuf; -+} -+ -+/* Updates SHT_RELA section associated with the given section based on -+ the relbuf data. The relbuf data is freed at the end. */ -+static void -+update_rela_data (DSO *dso, struct debug_section *sec) -+{ -+ Elf_Data *symdata; -+ int relsec_ndx = sec->relsec; -+ Elf_Data *data = elf_getdata (dso->scn[relsec_ndx], NULL); -+ symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link], -+ NULL); -+ -+ relptr = sec->relbuf; -+ relend = sec->relend; -+ while (relptr < relend) -+ { -+ GElf_Sym sym; -+ GElf_Rela rela; -+ int ndx = relptr->ndx; -+ -+ if (gelf_getrela (data, ndx, &rela) == NULL) -+ error (1, 0, "Couldn't get relocation: %s", -+ elf_errmsg (-1)); -+ -+ if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info), -+ &sym) == NULL) -+ error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1)); -+ -+ rela.r_addend = relptr->addend - sym.st_value; -+ -+ if (gelf_update_rela (data, ndx, &rela) == 0) -+ error (1, 0, "Couldn't update relocations: %s", -+ elf_errmsg (-1)); -+ -+ ++relptr; -+ } -+ elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); -+ -+ free (sec->relbuf); -+} -+ - struct abbrev_attr - { - unsigned int attr; -@@ -1743,20 +1947,6 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) - return ptr; - } - --static int --rel_cmp (const void *a, const void *b) --{ -- REL *rela = (REL *) a, *relb = (REL *) b; -- -- if (rela->ptr < relb->ptr) -- return -1; -- -- if (rela->ptr > relb->ptr) -- return 1; -- -- return 0; --} -- - static int - line_rel_cmp (const void *a, const void *b) - { -@@ -1871,132 +2061,7 @@ edit_dwarf2 (DSO *dso) - htab_t abbrev; - struct abbrev_tag tag, *t; - int phase; -- REL *relbuf = NULL; -- -- if (debug_sections[DEBUG_INFO].relsec) -- { -- int ndx, maxndx; -- GElf_Rel rel; -- GElf_Rela rela; -- GElf_Sym sym; -- GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr; -- Elf_Data *symdata = NULL; -- int rtype; -- -- i = debug_sections[DEBUG_INFO].relsec; -- scn = dso->scn[i]; -- data = elf_getdata (scn, NULL); -- assert (data != NULL && data->d_buf != NULL); -- assert (elf_getdata (scn, data) == NULL); -- assert (data->d_off == 0); -- assert (data->d_size == dso->shdr[i].sh_size); -- maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize; -- relbuf = malloc (maxndx * sizeof (REL)); -- reltype = dso->shdr[i].sh_type; -- if (relbuf == NULL) -- error (1, errno, "%s: Could not allocate memory", dso->filename); -- -- symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL); -- assert (symdata != NULL && symdata->d_buf != NULL); -- assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) -- == NULL); -- assert (symdata->d_off == 0); -- assert (symdata->d_size -- == dso->shdr[dso->shdr[i].sh_link].sh_size); -- -- for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) -- { -- if (dso->shdr[i].sh_type == SHT_REL) -- { -- gelf_getrel (data, ndx, &rel); -- rela.r_offset = rel.r_offset; -- rela.r_info = rel.r_info; -- rela.r_addend = 0; -- } -- else -- gelf_getrela (data, ndx, &rela); -- gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); -- /* Relocations against section symbols are uninteresting -- in REL. */ -- if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) -- continue; -- /* Only consider relocations against .debug_str, .debug_line -- and .debug_abbrev. */ -- if (sym.st_shndx != debug_sections[DEBUG_STR].sec -- && sym.st_shndx != debug_sections[DEBUG_LINE].sec -- && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) -- continue; -- rela.r_addend += sym.st_value; -- rtype = ELF64_R_TYPE (rela.r_info); -- switch (dso->ehdr.e_machine) -- { -- case EM_SPARC: -- case EM_SPARC32PLUS: -- case EM_SPARCV9: -- if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) -- goto fail; -- break; -- case EM_386: -- if (rtype != R_386_32) -- goto fail; -- break; -- case EM_PPC: -- case EM_PPC64: -- if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) -- goto fail; -- break; -- case EM_S390: -- if (rtype != R_390_32) -- goto fail; -- break; -- case EM_IA_64: -- if (rtype != R_IA64_SECREL32LSB) -- goto fail; -- break; -- case EM_X86_64: -- if (rtype != R_X86_64_32) -- goto fail; -- break; -- case EM_ALPHA: -- if (rtype != R_ALPHA_REFLONG) -- goto fail; -- break; --#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32) -- case EM_AARCH64: -- if (rtype != R_AARCH64_ABS32) -- goto fail; -- break; --#endif -- case EM_68K: -- if (rtype != R_68K_32) -- goto fail; -- break; --#if defined(EM_RISCV) && defined(R_RISCV_32) -- case EM_RISCV: -- if (rtype != R_RISCV_32) -- goto fail; -- break; --#endif -- default: -- fail: -- error (1, 0, "%s: Unhandled relocation %d in .debug_info section", -- dso->filename, rtype); -- } -- relend->ptr = debug_sections[DEBUG_INFO].data -- + (rela.r_offset - base); -- relend->addend = rela.r_addend; -- relend->ndx = ndx; -- ++relend; -- } -- if (relbuf == relend) -- { -- free (relbuf); -- relbuf = NULL; -- relend = NULL; -- } -- else -- qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); -- } -+ bool info_rel_updated = false; - - for (phase = 0; phase < 2; phase++) - { -@@ -2008,7 +2073,8 @@ edit_dwarf2 (DSO *dso) - break; - - ptr = debug_sections[DEBUG_INFO].data; -- relptr = relbuf; -+ setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype); -+ rel_updated = false; - endsec = ptr + debug_sections[DEBUG_INFO].size; - while (ptr < endsec) - { -@@ -2096,6 +2162,10 @@ edit_dwarf2 (DSO *dso) - htab_delete (abbrev); - } - -+ /* Remember whether any .debug_info relocations might need -+ to be updated. */ -+ info_rel_updated = rel_updated; -+ - /* We might have to recalculate/rewrite the debug_line - section. We need to do that before going into phase one - so we have all new offsets. We do this separately from -@@ -2240,41 +2310,8 @@ edit_dwarf2 (DSO *dso) - dirty_section (DEBUG_INFO); - - /* Update any debug_info relocations addends we might have touched. */ -- if (relbuf != NULL && reltype == SHT_RELA) -- { -- Elf_Data *symdata; -- int relsec_ndx = debug_sections[DEBUG_INFO].relsec; -- data = elf_getdata (dso->scn[relsec_ndx], NULL); -- symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link], -- NULL); -- -- relptr = relbuf; -- while (relptr < relend) -- { -- GElf_Sym sym; -- GElf_Rela rela; -- int ndx = relptr->ndx; -- -- if (gelf_getrela (data, ndx, &rela) == NULL) -- error (1, 0, "Couldn't get relocation: %s", -- elf_errmsg (-1)); -- -- if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info), -- &sym) == NULL) -- error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1)); -- -- rela.r_addend = relptr->addend - sym.st_value; -- -- if (gelf_update_rela (data, ndx, &rela) == 0) -- error (1, 0, "Couldn't update relocations: %s", -- elf_errmsg (-1)); -- -- ++relptr; -- } -- elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); -- } -- -- free (relbuf); -+ if (info_rel_updated) -+ update_rela_data (dso, &debug_sections[DEBUG_INFO]); - } - - return 0; --- -2.23.0 - diff --git a/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch b/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch deleted file mode 100644 index 9dca222..0000000 --- a/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a74ea72cb47dcdc1006ffbdd23643964bd40f580 Mon Sep 17 00:00:00 2001 -From: "Vladimir D. Seleznev" -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 ---- - 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 - diff --git a/SOURCES/0002-Handle-.debug_macro-in-debugedit.patch b/SOURCES/0002-Handle-.debug_macro-in-debugedit.patch deleted file mode 100644 index 368beb8..0000000 --- a/SOURCES/0002-Handle-.debug_macro-in-debugedit.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 201a71ce18734b1cebc337225f345fd754a6414f Mon Sep 17 00:00:00 2001 -Message-Id: <201a71ce18734b1cebc337225f345fd754a6414f.1573552234.git.pmatilai@redhat.com> -In-Reply-To: -References: -From: Mark Wielaard -Date: Mon, 17 Jun 2019 11:23:25 +0200 -Subject: [PATCH 2/3] Handle .debug_macro in debugedit. - -When compiling with -g3 gcc will generate a .debug_macro section -which has pointers to the .debug_str section. Since we might rewrite -the .debug_str section, we also need to update any .debug_macro -pointers. - -Updated the debugedit.at testcase by building everything with -g -and add various checks to see the .debug_macro section looks OK -after running debugedit. Added a new rpmbuild.at testcase to check -handing of .debug_macro in the whole rpmbuild debuginfo pipeline -to double check the separate .debug file also contains the macros. - -Original patch by Michael Schroeder . Extended by -Mark Wielaard to deal with relocations and possible -multiple COMDAT .debug_macro sections. ---- - tests/Makefile.am | 1 + - tests/data/SPECS/hello-g3.spec | 60 ++++++++++ - tests/debugedit.at | 79 ++++++++++++- - tests/rpmbuild.at | 33 ++++++ - tools/debugedit.c | 196 +++++++++++++++++++++++++++++++-- - 5 files changed, 356 insertions(+), 13 deletions(-) - create mode 100644 tests/data/SPECS/hello-g3.spec - -[ test-suite part edited out, too painful to backport ] - -diff --git a/tools/debugedit.c b/tools/debugedit.c -index cf9cc3ca9..84483ef5e 100644 ---- a/tools/debugedit.c -+++ b/tools/debugedit.c -@@ -41,6 +41,7 @@ - #include - #include - -+ - /* Unfortunately strtab manipulation functions were only officially added - to elfutils libdw in 0.167. Before that there were internal unsupported - ebl variants. While libebl.h isn't supported we'll try to use it anyway -@@ -432,6 +433,7 @@ typedef struct debug_section - int sec, relsec; - REL *relbuf; - REL *relend; -+ struct debug_section *next; /* Only happens for COMDAT .debug_macro. */ - } debug_section; - - static debug_section debug_sections[] = -@@ -1989,11 +1991,35 @@ edit_dwarf2 (DSO *dso) - for (j = 0; debug_sections[j].name; ++j) - if (strcmp (name, debug_sections[j].name) == 0) - { -+ struct debug_section *debug_sec = &debug_sections[j]; - if (debug_sections[j].data) - { -- error (0, 0, "%s: Found two copies of %s section", -- dso->filename, name); -- return 1; -+ if (j != DEBUG_MACRO) -+ { -+ error (0, 0, "%s: Found two copies of %s section", -+ dso->filename, name); -+ return 1; -+ } -+ else -+ { -+ /* In relocatable files .debug_macro might -+ appear multiple times as COMDAT -+ section. */ -+ struct debug_section *sec; -+ sec = calloc (sizeof (struct debug_section), 1); -+ if (sec == NULL) -+ error (1, errno, -+ "%s: Could not allocate more macro sections", -+ dso->filename); -+ sec->name = ".debug_macro"; -+ -+ struct debug_section *macro_sec = debug_sec; -+ while (macro_sec->next != NULL) -+ macro_sec = macro_sec->next; -+ -+ macro_sec->next = sec; -+ debug_sec = sec; -+ } - } - - scn = dso->scn[i]; -@@ -2002,10 +2028,10 @@ edit_dwarf2 (DSO *dso) - assert (elf_getdata (scn, data) == NULL); - assert (data->d_off == 0); - assert (data->d_size == dso->shdr[i].sh_size); -- debug_sections[j].data = data->d_buf; -- debug_sections[j].elf_data = data; -- debug_sections[j].size = data->d_size; -- debug_sections[j].sec = i; -+ debug_sec->data = data->d_buf; -+ debug_sec->elf_data = data; -+ debug_sec->size = data->d_size; -+ debug_sec->sec = i; - break; - } - -@@ -2028,7 +2054,26 @@ edit_dwarf2 (DSO *dso) - + (dso->shdr[i].sh_type == SHT_RELA), - debug_sections[j].name) == 0) - { -- debug_sections[j].relsec = i; -+ if (j == DEBUG_MACRO) -+ { -+ /* Pick the correct one. */ -+ int rel_target = dso->shdr[i].sh_info; -+ struct debug_section *macro_sec = &debug_sections[j]; -+ while (macro_sec != NULL) -+ { -+ if (macro_sec->sec == rel_target) -+ { -+ macro_sec->relsec = i; -+ break; -+ } -+ macro_sec = macro_sec->next; -+ } -+ if (macro_sec == NULL) -+ error (0, 1, "No .debug_macro reloc section: %s", -+ dso->filename); -+ } -+ else -+ debug_sections[j].relsec = i; - break; - } - } -@@ -2062,6 +2107,7 @@ edit_dwarf2 (DSO *dso) - struct abbrev_tag tag, *t; - int phase; - bool info_rel_updated = false; -+ bool macro_rel_updated = false; - - for (phase = 0; phase < 2; phase++) - { -@@ -2279,6 +2325,113 @@ edit_dwarf2 (DSO *dso) - } - } - -+ /* The .debug_macro section also contains offsets into the -+ .debug_str section and references to the .debug_line -+ tables, so we need to update those as well if we update -+ the strings or the stmts. */ -+ if ((need_strp_update || need_stmt_update) -+ && debug_sections[DEBUG_MACRO].data) -+ { -+ /* There might be multiple (COMDAT) .debug_macro sections. */ -+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; -+ while (macro_sec != NULL) -+ { -+ setup_relbuf(dso, macro_sec, &reltype); -+ rel_updated = false; -+ -+ ptr = macro_sec->data; -+ endsec = ptr + macro_sec->size; -+ int op = 0, macro_version, macro_flags; -+ int offset_len = 4, line_offset = 0; -+ -+ while (ptr < endsec) -+ { -+ if (!op) -+ { -+ macro_version = read_16 (ptr); -+ macro_flags = read_8 (ptr); -+ if (macro_version < 4 || macro_version > 5) -+ error (1, 0, "unhandled .debug_macro version: %d", -+ macro_version); -+ if ((macro_flags & ~2) != 0) -+ error (1, 0, "unhandled .debug_macro flags: 0x%x", -+ macro_flags); -+ -+ offset_len = (macro_flags & 0x01) ? 8 : 4; -+ line_offset = (macro_flags & 0x02) ? 1 : 0; -+ -+ if (offset_len != 4) -+ error (0, 1, -+ "Cannot handle 8 byte macro offsets: %s", -+ dso->filename); -+ -+ /* Update the line_offset if it is there. */ -+ if (line_offset) -+ { -+ if (phase == 0) -+ ptr += offset_len; -+ else -+ { -+ size_t idx, new_idx; -+ idx = do_read_32_relocated (ptr); -+ new_idx = find_new_list_offs (&dso->lines, -+ idx); -+ write_32_relocated (ptr, new_idx); -+ } -+ } -+ } -+ -+ op = read_8 (ptr); -+ if (!op) -+ continue; -+ switch(op) -+ { -+ case DW_MACRO_GNU_define: -+ case DW_MACRO_GNU_undef: -+ read_uleb128 (ptr); -+ ptr = ((unsigned char *) strchr ((char *) ptr, '\0') -+ + 1); -+ break; -+ case DW_MACRO_GNU_start_file: -+ read_uleb128 (ptr); -+ read_uleb128 (ptr); -+ break; -+ case DW_MACRO_GNU_end_file: -+ break; -+ case DW_MACRO_GNU_define_indirect: -+ case DW_MACRO_GNU_undef_indirect: -+ read_uleb128 (ptr); -+ if (phase == 0) -+ { -+ size_t idx = read_32_relocated (ptr); -+ record_existing_string_entry_idx (&dso->strings, -+ idx); -+ } -+ else -+ { -+ struct stridxentry *entry; -+ size_t idx, new_idx; -+ idx = do_read_32_relocated (ptr); -+ entry = string_find_entry (&dso->strings, idx); -+ new_idx = strent_offset (entry->entry); -+ write_32_relocated (ptr, new_idx); -+ } -+ break; -+ case DW_MACRO_GNU_transparent_include: -+ ptr += offset_len; -+ break; -+ default: -+ error (1, 0, "Unhandled DW_MACRO op 0x%x", op); -+ break; -+ } -+ } -+ -+ if (rel_updated) -+ macro_rel_updated = true; -+ macro_sec = macro_sec->next; -+ } -+ } -+ - /* Same for the debug_str section. Make sure everything is - in place for phase 1 updating of debug_info - references. */ -@@ -2308,10 +2461,24 @@ edit_dwarf2 (DSO *dso) - new strp, strings and/or linep offsets. */ - if (need_strp_update || need_string_replacement || need_stmt_update) - dirty_section (DEBUG_INFO); -+ if (need_strp_update || need_stmt_update) -+ dirty_section (DEBUG_MACRO); -+ if (need_stmt_update) -+ dirty_section (DEBUG_LINE); - -- /* Update any debug_info relocations addends we might have touched. */ -+ /* Update any relocations addends we might have touched. */ - if (info_rel_updated) - update_rela_data (dso, &debug_sections[DEBUG_INFO]); -+ -+ if (macro_rel_updated) -+ { -+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; -+ while (macro_sec != NULL) -+ { -+ update_rela_data (dso, macro_sec); -+ macro_sec = macro_sec->next; -+ } -+ } - } - - return 0; -@@ -2843,6 +3010,17 @@ main (int argc, char *argv[]) - destroy_lines (&dso->lines); - free (dso); - -+ /* In case there were multiple (COMDAT) .debug_macro sections, -+ free them. */ -+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; -+ macro_sec = macro_sec->next; -+ while (macro_sec != NULL) -+ { -+ struct debug_section *next = macro_sec->next; -+ free (macro_sec); -+ macro_sec = next; -+ } -+ - poptFreeContext (optCon); - - return 0; --- -2.23.0 - diff --git a/SOURCES/0002-Remove-use-of-bool-type-for-consistency.patch b/SOURCES/0002-Remove-use-of-bool-type-for-consistency.patch deleted file mode 100644 index 332b002..0000000 --- a/SOURCES/0002-Remove-use-of-bool-type-for-consistency.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 845b5c3882b1eecb31d712b61a4e91fe0eb70712 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -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 - #include --#include - #if WITH_CAP - #include - #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 - diff --git a/SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch b/SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch deleted file mode 100644 index 5b08ce7..0000000 --- a/SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 172e1f5ec0e37c8aab91a2ae35bd73ea594432cb Mon Sep 17 00:00:00 2001 -Message-Id: <172e1f5ec0e37c8aab91a2ae35bd73ea594432cb.1571920849.git.pmatilai@redhat.com> -In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Thu, 4 Oct 2018 13:36:09 +0300 -Subject: [PATCH 2/5] Use Python 3 -compatible exception syntax in tests - -Makes a few tests pass that failed before, and others now fail -a little bit later... - -(cherry picked from commit 511eef19298765e3639bccbe98bc3a50023f45b2) ---- - tests/rpmpython.at | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/tests/rpmpython.at b/tests/rpmpython.at -index 3a7c251f1..1daaf1216 100644 ---- a/tests/rpmpython.at -+++ b/tests/rpmpython.at -@@ -96,7 +96,7 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]: - try: - x = getattr(h, a) - myprint(x) -- except AttributeError, exc: -+ except AttributeError as exc: - myprint(exc) - ], - [testpkg-5:1.0-1.noarch -@@ -119,7 +119,7 @@ h2['dirindexes'] = [ 0, 0, 1 ] - for h in [h1, h2]: - try: - myprint(','.join(h['filenames'])) -- except rpm.error, exc: -+ except rpm.error as exc: - myprint(exc) - ], - [invalid header data -@@ -164,7 +164,7 @@ rpm.setLogFile(sink) - try: - h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm') - myprint(h['arch']) --except rpm.error, e: -+except rpm.error as e: - myprint(e) - ], - [public key not available -@@ -183,7 +183,7 @@ ts.setKeyring(keyring) - try: - h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm') - myprint(h['arch']) --except rpm.error, e: -+except rpm.error as e: - myprint(e) - ], - [x86_64] -@@ -207,7 +207,7 @@ h = rpm.hdr() - h['name'] = "foo" - try: - ts.addInstall(h, 'foo', 'u') --except rpm.error, err: -+except rpm.error as err: - myprint(err) - for e in ts: - myprint(e.NEVRA()) -@@ -228,7 +228,7 @@ h['dirnames'] = ['/opt' '/flopt'] - h['dirindexes'] = [ 1, 2, 3 ] - try: - ts.addInstall(h, 'foo', 'u') --except rpm.error, err: -+except rpm.error as err: - myprint(err) - for e in ts: - myprint(e.NEVRA()) --- -2.21.0 - diff --git a/SOURCES/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch b/SOURCES/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch deleted file mode 100644 index 713d336..0000000 --- a/SOURCES/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 6525a9bf1529944741f273cb9fde5619f006a673 Mon Sep 17 00:00:00 2001 -Message-Id: <6525a9bf1529944741f273cb9fde5619f006a673.1571920849.git.pmatilai@redhat.com> -In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Thu, 4 Oct 2018 17:41:19 +0300 -Subject: [PATCH 3/5] Fix couple of bytes vs strings issues in Python tests - -For the purposes of rpmio testing and importing public key, we're -dealing with bytes rather than encoded strings. In the carefree days -of Python 2 such details didn't matter, in Python 3 they cause failures. -The signed package test still fails after this one but it's due to -a more general issue. - -(cherry picked from commit 86f7898dd6a7fa8718c02675f5a7ee04ff987422) ---- - tests/rpmpython.at | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tests/rpmpython.at b/tests/rpmpython.at -index 1daaf1216..ae020ae95 100644 ---- a/tests/rpmpython.at -+++ b/tests/rpmpython.at -@@ -33,7 +33,7 @@ prexp(mname) - []) - - RPMPY_TEST([basic rpmio],[ --msg = 'Killroy was here\n' -+msg = b'Killroy was here\n' - data = msg * 10 - # TODO: test other compression types too if built in - for iot in [ 'fpio', 'fdio', 'ufdio', 'gzdio' ]: -@@ -173,7 +173,7 @@ except rpm.error as e: - - RPMPY_TEST([reading a signed package file 2],[ - --keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub').read() -+keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub', 'rb').read() - pubkey = rpm.pubkey(keydata) - keyring = rpm.keyring() - keyring.addKey(pubkey) --- -2.21.0 - diff --git a/SOURCES/0003-Match-formatting-style-of-existing-code.patch b/SOURCES/0003-Match-formatting-style-of-existing-code.patch deleted file mode 100644 index aae1035..0000000 --- a/SOURCES/0003-Match-formatting-style-of-existing-code.patch +++ /dev/null @@ -1,1249 +0,0 @@ -From aa31421bfe835dadd29da3aa46ee446038f80d02 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -Date: Sun, 31 Jan 2021 13:51:16 -0800 -Subject: [PATCH 03/30] Match formatting/style of existing code - -The existing code contains some variability in formatting. I'm not sure -if { is meant to be on the end of the line, or on a new line, but I've -standardized on the former. - -The indentation is intended to match the existing convention: 4 column -indent, but 8 column wide tab characters. This is easy to follow/use in -vim, but is surprisingly difficult to get right in vscode. I am doing -this reformat here and now, and future changes will be after this. - -I'm keen to fold the patches together, but for now, I'm trying to keep -the history of #1470 linear so everyone can follow along. ---- - lib/rpmplugins.c | 6 +- - plugins/reflink.c | 407 ++++++++++++++++++--------------- - rpm2extents.c | 562 ++++++++++++++++++++-------------------------- - 3 files changed, 462 insertions(+), 513 deletions(-) - -diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index c5084d398..3da3097af 100644 ---- a/lib/rpmplugins.c -+++ b/lib/rpmplugins.c -@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, - 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. -+ /* 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 { -diff --git a/plugins/reflink.c b/plugins/reflink.c -index d7f19acd9..9eaa87094 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -32,31 +32,32 @@ - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - --/* --We use this in find to indicate a key wasn't found. This is an unrecoverable --error, but we can at least show a decent error. 0 is never a valid offset --because it's the offset of the start of the file. --*/ -+/* We use this in find to indicate a key wasn't found. This is an -+ * unrecoverable error, but we can at least show a decent error. 0 is never a -+ * valid offset because it's the offset of the start of the file. -+ */ - #define NOT_FOUND 0 - - #define BUFFER_SIZE (1024 * 128) - --/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+/* 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; -- char *buffer; -+ /* Stuff that's used across rpms */ -+ long fundamental_block_size; -+ char *buffer; - -- /* stuff that's used/updated per psm */ -- uint32_t keys, keysize; -+ /* stuff that's used/updated per psm */ -+ uint32_t keys, keysize; - -- // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) -- unsigned char *table; -- FD_t fd; -- rpmfiles files; -- inodeIndexHash inodeIndexes; -+ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */ -+ unsigned char *table; -+ FD_t fd; -+ rpmfiles files; -+ inodeIndexHash inodeIndexes; - }; - - typedef struct reflink_state_s * reflink_state; -@@ -73,60 +74,62 @@ static unsigned int inodeId(rpm_ino_t a) - } - - static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { -- reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); -+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); - -- /* -- IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and -- length arguments to be aligned to the fundamental block size. -+ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset -+ * and length arguments to be aligned to the fundamental block size. -+ * -+ * The value of "fundamental block size" is directly related to the -+ * system's page size, so we should use that. -+ */ -+ state->fundamental_block_size = sysconf(_SC_PAGESIZE); -+ state->buffer = rcalloc(1, BUFFER_SIZE); -+ rpmPluginSetData(plugin, state); - -- The value of "fundamental block size" is directly related to the system's -- page size, so we should use that. -- */ -- state->fundamental_block_size = sysconf(_SC_PAGESIZE); -- state->buffer = rcalloc(1, BUFFER_SIZE); -- rpmPluginSetData(plugin, state); -- -- return RPMRC_OK; -+ return RPMRC_OK; - } - - static void reflink_cleanup(rpmPlugin plugin) { -- reflink_state state = rpmPluginGetData(plugin); -- free(state->buffer); -- free(state); -+ reflink_state state = rpmPluginGetData(plugin); -+ free(state->buffer); -+ free(state); - } - - static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - 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; -+ 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; -+ 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; -+ 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")); -- return RPMRC_FAIL; -- } -- return RPMRC_OK; -+ 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")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; - } - rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); - Header h = rpmteHeader(te); -@@ -136,53 +139,60 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon"); - headerFree(h); - state->files = rpmteFiles(te); -- /* tail of file contains offset_table, offset_checksums -- then magic -- */ -+ /* tail of file contains offset_table, offset_checksums then magic */ - if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), -+ state->fd); -+ return RPMRC_FAIL; - } - rpm_loff_t table_start; - len = sizeof(table_start); - if (Fread(&table_start, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -+ return RPMRC_FAIL; - } - if (Fseek(state->fd, table_start, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -+ return RPMRC_FAIL; - } - len = sizeof(state->keys); - if (Fread(&state->keys, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -+ return RPMRC_FAIL; - } - len = sizeof(state->keysize); - if (Fread(&state->keysize, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -+ return RPMRC_FAIL; - } -- rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); -- // now get digest table if there is a reason to have one. -+ rpmlog( -+ RPMLOG_DEBUG, -+ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), -+ table_start, state->keys, state->keysize -+ ); -+ /* now get digest table if there is a reason to have one. */ - if (state->keys == 0 || state->keysize == 0) { -- // no files (or no digests(!)) -- state->table = NULL; -+ /* no files (or no digests(!)) */ -+ state->table = NULL; - } else { -- int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -- state->table = rcalloc(1, table_size); -- if (Fread(state->table, table_size, 1, state->fd) != table_size) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -- return RPMRC_FAIL; -- } -- state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); -+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -+ state->table = rcalloc(1, table_size); -+ if (Fread(state->table, table_size, 1, state->fd) != table_size) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -+ return RPMRC_FAIL; -+ } -+ state->inodeIndexes = inodeIndexHashCreate( -+ state->keys, inodeId, inodeCmp, NULL, NULL -+ ); - } - -- // seek back to original location -- // might not be needed if we seek to offset immediately -+ /* Seek back to original location. -+ * Might not be needed if we seek to offset immediately -+ */ - if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; - } - return RPMRC_OK; - } -@@ -192,40 +202,45 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) - reflink_state state = rpmPluginGetData(plugin); - state->files = rpmfilesFree(state->files); - if (state->table) { -- free(state->table); -- state->table = NULL; -+ free(state->table); -+ state->table = NULL; - } - if (state->inodeIndexes) { -- inodeIndexHashFree(state->inodeIndexes); -- state->inodeIndexes = NULL; -+ inodeIndexHashFree(state->inodeIndexes); -+ state->inodeIndexes = NULL; - } - return RPMRC_OK; - } - - --// have a prototype, warnings system -+/* have a prototype, warnings system */ - 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); -- } -+ /* 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"), 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); -- if (entry == NULL) { -- return NOT_FOUND; -- } -- rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -- return offset; -+ rpmlog(RPMLOG_DEBUG, -+ _("reflink: bsearch(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); -+ if (entry == NULL) { -+ return NOT_FOUND; -+ } -+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -+ return offset; - } - --static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) -+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, -+ mode_t file_mode, rpmFsmOp op) - { - struct file_clone_range fcr; - rpm_loff_t size; -@@ -234,99 +249,119 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, - - reflink_state state = rpmPluginGetData(plugin); - if (state->table == NULL) { -- // no table means rpm is not in reflink format, so leave. Now. -- return RPMRC_OK; -+ /* no table means rpm is not in reflink format, so leave. Now. */ -+ return RPMRC_OK; - } - if (op == FA_TOUCH) { -- // we're not overwriting an existing file -- return RPMRC_OK; -+ /* we're not overwriting an existing file. */ -+ return RPMRC_OK; - } - fcr.dest_offset = 0; - if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { -- rpm_ino_t inode = rpmfiFInode(fi); -- /* 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)) { -- // entry is in table, use hard link -- char *fn = rpmfilesFN(state->files, hlix[0]); -- if (link(fn, path) != 0) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); -- free(fn); -- return RPMRC_FAIL; -- } -- free(fn); -- return RPMRC_PLUGIN_CONTENTS; -- } -- /* if we didn't hard link, then we'll track this inode as being created soon */ -- if (rpmfiFNlink(fi) > 1) { -- /* minor optimization: only store files with more than one link */ -- inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -- } -- /* derived from wfd_open in fsm.c */ -- mode_t old_umask = umask(0577); -- dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -- umask(old_umask); -- if (dst == -1) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); -- return RPMRC_FAIL; -- } -- size = rpmfiFSize(fi); -- if (size > 0) { -- /* round src_length down to fundamental_block_size multiple */ -- fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -- if ((size % state->fundamental_block_size) > 0) { -- /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ -- fcr.src_length += state->fundamental_block_size; -- } -- fcr.src_fd = Fileno(state->fd); -- if (fcr.src_fd == -1) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -- return RPMRC_FAIL; -- } -- fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -- if (fcr.src_offset == NOT_FOUND) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -- return RPMRC_FAIL; -- } -- rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -- rc = ioctl(dst, FICLONERANGE, &fcr); -- if (rc) { -- rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); -- if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); -- return RPMRC_FAIL; -- } -- rpm_loff_t left = size; -- size_t len, read, written; -- while (left) { -- len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -- read = Fread(state->buffer, len, 1, state->fd); -- if (read != len) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); -- return RPMRC_FAIL; -- } -- written = write(dst, state->buffer, len); -- if (read != written) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); -- return RPMRC_FAIL; -- } -- left -= len; -- } -- } else { -- /* reflink worked, so truncate */ -- rc = ftruncate(dst, size); -- if (rc) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); -- return RPMRC_FAIL; -- } -- } -- } -- close(dst); -- return RPMRC_PLUGIN_CONTENTS; -+ rpm_ino_t inode = rpmfiFInode(fi); -+ /* 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)) { -+ /* entry is in table, use hard link */ -+ char *fn = rpmfilesFN(state->files, hlix[0]); -+ if (link(fn, path) != 0) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to hard link %s -> %s due to %s\n"), -+ fn, path, strerror(errno)); -+ free(fn); -+ return RPMRC_FAIL; -+ } -+ free(fn); -+ return RPMRC_PLUGIN_CONTENTS; -+ } -+ /* if we didn't hard link, then we'll track this inode as being -+ * created soon -+ */ -+ if (rpmfiFNlink(fi) > 1) { -+ /* minor optimization: only store files with more than one link */ -+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -+ } -+ /* derived from wfd_open in fsm.c */ -+ mode_t old_umask = umask(0577); -+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -+ umask(old_umask); -+ if (dst == -1) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), -+ path, strerror(errno), rpmfiFFlags(fi)); -+ return RPMRC_FAIL; -+ } -+ size = rpmfiFSize(fi); -+ if (size > 0) { -+ /* round src_length down to fundamental_block_size multiple */ -+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -+ if ((size % state->fundamental_block_size) > 0) { -+ /* round up to next fundamental_block_size. We expect the data -+ * in the rpm to be similarly padded. -+ */ -+ fcr.src_length += state->fundamental_block_size; -+ } -+ fcr.src_fd = Fileno(state->fd); -+ if (fcr.src_fd == -1) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -+ return RPMRC_FAIL; -+ } -+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -+ if (fcr.src_offset == NOT_FOUND) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -+ return RPMRC_FAIL; -+ } -+ rpmlog(RPMLOG_DEBUG, -+ _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), -+ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -+ rc = ioctl(dst, FICLONERANGE, &fcr); -+ if (rc) { -+ rpmlog(RPMLOG_WARNING, -+ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), -+ path, rc, errno, strerror(errno)); -+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ rpm_loff_t left = size; -+ size_t len, read, written; -+ while (left) { -+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -+ read = Fread(state->buffer, len, 1, state->fd); -+ if (read != len) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: short read on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ written = write(dst, state->buffer, len); -+ if (read != written) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: short write on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ left -= len; -+ } -+ } else { -+ /* reflink worked, so truncate */ -+ rc = ftruncate(dst, size); -+ if (rc) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to truncate %s to %ld due to %s\n"), -+ path, size, strerror(errno)); -+ return RPMRC_FAIL; -+ } -+ } -+ } -+ close(dst); -+ return RPMRC_PLUGIN_CONTENTS; - } - return RPMRC_OK; - } -diff --git a/rpm2extents.c b/rpm2extents.c -index 5662b86a6..c111be0a2 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -24,7 +24,7 @@ - #include "debug.h" - - /* hash of void * (pointers) to file digests to offsets within output. -- The length of the key depends on what the FILEDIGESTALGO is. -+ * The length of the key depends on what the FILEDIGESTALGO is. - */ - #undef HASHTYPE - #undef HTKEYTYPE -@@ -34,7 +34,9 @@ - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - --/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+/* magic value at end of file (64 bits) that indicates this is a transcoded -+ * rpm. -+ */ - #define MAGIC 3472329499408095051 - - struct digestoffset { -@@ -64,77 +66,54 @@ static int digestor( - int algo; - rpmRC rc = RPMRC_FAIL; - -- for (algo = 0; algo < algos_len; algo++) -- { -- fdInitDigest(fdi, algos[algo], 0); -+ 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; -+ if (fdilength == -1) { -+ fprintf(stderr, _("digest cat failed\n")); -+ goto exit; - } - - len = sizeof(fdilength); -- if (Fwrite(&fdilength, len, 1, validationo) != len) -- { -- fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); -- goto exit; -+ if (Fwrite(&fdilength, len, 1, validationo) != 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")); -- goto exit; -+ if (Fwrite(&algos_len, len, 1, validationo) != len) { -+ fprintf(stderr, _("Unable to write number of validation digests\n")); -+ goto exit; - } -- for (algo = 0; algo < algos_len; algo++) -- { -- fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -- -- algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -- algo_name_len = (uint32_t)strlen(algo_name); -- algo_digest_len = (uint32_t)filedigest_len; -- -- len = sizeof(algo_name_len); -- if (Fwrite(&algo_name_len, len, 1, validationo) != len) -- { -- fprintf( -- stderr, -- _("Unable to write validation algo name length\n") -- ); -- goto exit; -- } -- len = sizeof(algo_digest_len); -- if (Fwrite(&algo_digest_len, len, 1, validationo) != len) -- { -- fprintf( -- stderr, -- _("Unable to write number of bytes for validation 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")); -- goto exit; -- } -- if ( -- Fwrite( -- filedigest, -- algo_digest_len, -- 1, -- validationo -- ) != algo_digest_len -- ) -- { -- fprintf( -- stderr, -- _("Unable to write validation digest value %u, %zu\n"), -- algo_digest_len, -- filedigest_len -- ); -- goto exit; -- } -+ for (algo = 0; algo < algos_len; algo++) { -+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -+ -+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -+ algo_name_len = (uint32_t)strlen(algo_name); -+ algo_digest_len = (uint32_t)filedigest_len; -+ -+ len = sizeof(algo_name_len); -+ if (Fwrite(&algo_name_len, len, 1, validationo) != len) { -+ fprintf(stderr, -+ _("Unable to write validation algo name length\n")); -+ goto exit; -+ } -+ len = sizeof(algo_digest_len); -+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) { -+ fprintf(stderr, -+ _("Unable to write number of bytes for validation 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")); -+ goto exit; -+ } -+ if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) { -+ fprintf(stderr, -+ _("Unable to write validation digest value %u, %zu\n"), -+ algo_digest_len, filedigest_len); -+ goto exit; -+ } - } - rc = RPMRC_OK; - exit: -@@ -145,23 +124,20 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - { - uint32_t diglen; - /* GNU C extension: can use diglen from outer context */ -- int digestSetCmp(const unsigned char * a, const unsigned char * b) -- { -- return memcmp(a, b, diglen); -+ int digestSetCmp(const unsigned char * a, const unsigned char * b) { -+ return memcmp(a, b, diglen); - } - -- unsigned int digestSetHash(const unsigned char * digest) -- { -+ unsigned int digestSetHash(const unsigned char * digest) { - /* assumes sizeof(unsigned int) < diglen */ - return *(unsigned int *)digest; - } - -- int digestoffsetCmp(const void * a, const void * b) -- { -- return digestSetCmp( -- ((struct digestoffset *)a)->digest, -- ((struct digestoffset *)b)->digest -- ); -+ int digestoffsetCmp(const void * a, const void * b) { -+ return digestSetCmp( -+ ((struct digestoffset *)a)->digest, -+ ((struct digestoffset *)b)->digest -+ ); - } - - FD_t fdo; -@@ -179,65 +155,52 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - - fdo = fdDup(STDOUT_FILENO); - -- if (rpmReadPackageRaw(fdi, &sigh, &h)) -- { -- fprintf(stderr, _("Error reading package\n")); -- exit(EXIT_FAILURE); -+ if (rpmReadPackageRaw(fdi, &sigh, &h)) { -+ fprintf(stderr, _("Error reading package\n")); -+ exit(EXIT_FAILURE); - } - - if (rpmLeadWrite(fdo, h)) - { -- fprintf( -- stderr, -- _("Unable to write package lead: %s\n"), -- Fstrerror(fdo) -- ); -- exit(EXIT_FAILURE); -+ fprintf(stderr, _("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)); -- exit(EXIT_FAILURE); -+ if (rpmWriteSignature(fdo, sigh)) { -+ fprintf(stderr, _("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)); -- exit(EXIT_FAILURE); -+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { -+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -+ 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); -+ { -+ 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); - -- if (gzdi == NULL) -- { -- fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -- exit(EXIT_FAILURE); -+ if (gzdi == NULL) { -+ fprintf(stderr, _("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 -- ); -+ rpmfi 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?) -- */ -+ * now?) -+ */ - diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi)); -- digestSet ds = digestSetCreate( -- rpmfiFC(fi), -- digestSetHash, -- digestSetCmp, -- NULL -- ); -+ digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, -+ NULL); - struct digestoffset offsets[rpmfiFC(fi)]; - pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); - -@@ -247,139 +210,114 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - - zeros = xcalloc(fundamental_block_size, 1); - -- 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) -- { -- fprintf(stderr, _("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) -- { -- fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -- goto exit; -- } -- pos += size; -+ 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) { -+ fprintf(stderr, _("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) { -+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -+ goto exit; -+ } -+ pos += size; - } - 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); - - len = sizeof(offset_ix); -- if (Fwrite(&offset_ix, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write length of table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&offset_ix, len, 1, fdo) != len) { -+ fprintf(stderr, _("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")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&diglen, len, 1, fdo) != len) { -+ fprintf(stderr, _("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")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write offset\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -+ for (int x = 0; x < offset_ix; x++) { -+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { -+ fprintf(stderr, _("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")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } - } - validation_pos = ( -- pos + sizeof(offset_ix) + sizeof(diglen) + -- offset_ix * (diglen + sizeof(rpm_loff_t)) -+ pos + sizeof(offset_ix) + sizeof(diglen) + -+ offset_ix * (diglen + sizeof(rpm_loff_t)) - ); - - ssize_t validation_len = ufdCopy(validationi, fdo); -- if (validation_len == -1) -- { -- fprintf(stderr, _("digest table ufdCopy failed\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (validation_len == -1) { -+ fprintf(stderr, _("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 -+ * 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) -- { -- fprintf(stderr, _("Unable to write final padding\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ 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")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - zeros = _free(zeros); -- if (Fwrite(&pos, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write offset of digest table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&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 table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&validation_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of validation table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - uint64_t magic = MAGIC; - len = sizeof(magic); -- if (Fwrite(&magic, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write magic\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&magic, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - - exit: -@@ -389,8 +327,7 @@ exit: - return rc; - } - --int main(int argc, char *argv[]) --{ -+int main(int argc, char *argv[]) { - rpmRC rc; - int cprc = 0; - uint8_t algos[argc - 1]; -@@ -402,118 +339,95 @@ int main(int argc, char *argv[]) - xsetprogname(argv[0]); /* Portability call -- see system.h */ - rpmReadConfigFiles(NULL, NULL); - -- 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 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { -+ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); -+ exit(EXIT_FAILURE); - } - -- if (argc == 1) -- { -- fprintf( -- stderr, -- _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") -- ); -- exit(EXIT_FAILURE); -+ if (argc == 1) { -+ fprintf(stderr, -+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); -+ exit(EXIT_FAILURE); - } - -- for (int x = 0; x < (argc - 1); x++) -- { -- if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -- { -- fprintf( -- stderr, -- _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -- argv[x + 1] -- ); -- exit(EXIT_FAILURE); -- } -+ for (int x = 0; x < (argc - 1); x++) { -+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -+ { -+ fprintf(stderr, -+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -+ argv[x + 1]); -+ exit(EXIT_FAILURE); -+ } - } - - -- if (pipe(mainpipefd) == -1) -- { -- fprintf(stderr, _("Main pipe failure\n")); -- exit(EXIT_FAILURE); -+ 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); -+ 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, argc - 1); -- Fclose(validationo); -- Fclose(fdo); -- Fclose(fdi); -+ 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, argc - 1); -+ Fclose(validationo); -+ Fclose(fdo); -+ Fclose(fdi); - } else { -- /* parent: main program */ -- 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. */ -- 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 failed\n")); -- 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; -- } -+ /* parent: main program */ -+ 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. -+ */ -+ 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 failed\n")); -+ 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; -+ } - } -- if (rc != RPMRC_OK) -- { -- /* translate rpmRC into generic failure return code. */ -- return EXIT_FAILURE; -+ if (rc != RPMRC_OK) { -+ /* translate rpmRC into generic failure return code. */ -+ return EXIT_FAILURE; - } - return EXIT_SUCCESS; - } --- -2.35.1 - diff --git a/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch b/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch deleted file mode 100644 index 129f420..0000000 --- a/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 492823ca53f5666b82e94fcfdd422bdcd67005cb Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch b/SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch deleted file mode 100644 index c950748..0000000 --- a/SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch +++ /dev/null @@ -1,114 +0,0 @@ -From df089e178da0918dc74a8572a99324b0987bce30 Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com> -References: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Mon, 18 Mar 2019 15:56:34 +0200 -Subject: [PATCH 3/3] Verify packages before signing (RhBug:1646388) - -Permitting corrupted packages to be signed is bad business for everybody -involved, this is something we should've always done. Besides being an -actual security risk, it can lead to odd results with verification -especially with the payload digest on signed packages. - -One point worth noting is that this means that pre 4.14-packages cannot -be signed in FIPS mode now because there's no way to validate the package -payload range due to MD5 being disabled. This seems like a feature and -not a limitation, so disabler for the verify step intentionally left out. - -Optimally we'd verify the package on the same read that's passed -to gpg but for simplicitys sake that's left as an future exercise, -now we simply read the package twice. ---- - sign/rpmgensig.c | 32 ++++++++++++++++++++++++++++++++ - tests/rpmsigdig.at | 20 ++++++++++++++++++++ - 2 files changed, 52 insertions(+) - -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index 2bcbab768..5be542001 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -21,6 +21,7 @@ - - #include "lib/rpmlead.h" - #include "lib/signature.h" -+#include "lib/rpmvs.h" - #include "sign/rpmsignfiles.h" - - #include "debug.h" -@@ -489,6 +490,31 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) - #endif - } - -+static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata) -+{ -+ char **msg = cbdata; -+ if (sinfo->rc && *msg == NULL) -+ *msg = rpmsinfoMsg(sinfo); -+ return (sinfo->rc != RPMRC_FAIL); -+} -+ -+/* Require valid digests on entire package for signing. */ -+static int checkPkg(FD_t fd, char **msg) -+{ -+ int rc; -+ struct rpmvs_s *vs = rpmvsCreate(RPMSIG_DIGEST_TYPE, 0, NULL); -+ off_t offset = Ftell(fd); -+ -+ Fseek(fd, 0, SEEK_SET); -+ rc = rpmpkgRead(vs, fd, NULL, NULL, msg); -+ if (!rc) -+ rc = rpmvsVerify(vs, RPMSIG_DIGEST_TYPE, msgCb, msg); -+ Fseek(fd, offset, SEEK_SET); -+ -+ rpmvsFree(vs); -+ return rc; -+} -+ - /** \ingroup rpmcli - * Create/modify elements in signature header. - * @param rpm path to package -@@ -519,6 +545,12 @@ static int rpmSign(const char *rpm, int deleting, int signfiles) - if (manageFile(&fd, rpm, O_RDWR)) - goto exit; - -+ /* Ensure package is intact before attempting to sign */ -+ if ((rc = checkPkg(fd, &msg))) { -+ rpmlog(RPMLOG_ERR, "not signing corrupt package %s: %s\n", rpm, msg); -+ goto exit; -+ } -+ - if ((rc = rpmLeadRead(fd, &msg)) != RPMRC_OK) { - rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg); - goto exit; -diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at -index 413c3d2c8..e93420306 100644 ---- a/tests/rpmsigdig.at -+++ b/tests/rpmsigdig.at -@@ -472,3 +472,23 @@ run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64-sign - [], - []) - AT_CLEANUP -+ -+AT_SETUP([rpmsign --addsign ]) -+AT_KEYWORDS([rpmsign signature]) -+AT_CHECK([ -+RPMDB_CLEAR -+RPMDB_INIT -+rm -rf "${TOPDIR}" -+ -+pkg="hello-2.0-1.x86_64.rpm" -+cp "${RPMTEST}"/data/RPMS/${pkg} "${RPMTEST}"/tmp/${pkg} -+dd if=/dev/zero of="${RPMTEST}"/tmp/${pkg} \ -+ conv=notrunc bs=1 seek=333 count=4 2> /dev/null -+run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}/tmp/${pkg}" -+], -+[1], -+[/home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm: -+], -+[error: not signing corrupt package /home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm: MD5 digest: BAD (Expected 007ca1d8b35cca02a1854ba301c5432e != 137ca1d8b35cca02a1854ba301c5432e) -+]) -+AT_CLEANUP --- -2.20.1 - diff --git a/SOURCES/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch b/SOURCES/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch deleted file mode 100644 index 5bdc8f0..0000000 --- a/SOURCES/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 00a0afd5e079a73ef6871f1538f34fa4e67892e6 Mon Sep 17 00:00:00 2001 -Message-Id: <00a0afd5e079a73ef6871f1538f34fa4e67892e6.1573552234.git.pmatilai@redhat.com> -In-Reply-To: -References: -From: Mark Wielaard -Date: Mon, 17 Jun 2019 11:23:26 +0200 -Subject: [PATCH 3/3] debugedit: Make sure .debug_line old/new idx start equal. - -Found by running the debugedit tests under valgrind. -If the old and new .debug_line offset isn't changed then we might -write out an uninitialized new_idx. ---- - tools/debugedit.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/tools/debugedit.c b/tools/debugedit.c -index 84483ef5e..9f8dcd0fb 100644 ---- a/tools/debugedit.c -+++ b/tools/debugedit.c -@@ -1177,6 +1177,7 @@ get_line_table (DSO *dso, size_t off, struct line_table **table) - *table = NULL; - - t->old_idx = off; -+ t->new_idx = off; - t->size_diff = 0; - t->replace_dirs = false; - t->replace_files = false; --- -2.23.0 - diff --git a/SOURCES/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch b/SOURCES/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch deleted file mode 100644 index 7e31e41..0000000 --- a/SOURCES/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0b1456ed4c00a021389acea4b6b10d475986b660 Mon Sep 17 00:00:00 2001 -Message-Id: <0b1456ed4c00a021389acea4b6b10d475986b660.1571920849.git.pmatilai@redhat.com> -In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Thu, 4 Oct 2018 18:05:37 +0300 -Subject: [PATCH 4/5] Bump the minimum Python version requirement to 2.7 - -Older Python versions are long since past their EOL, we don't need to -support them either. Python 2.7 is also the least incompatible version -compared to Python 3, going forward. Nuke the now unnecessary compat -macros. - -(cherry picked from commit 3f3cb3eabf7bb49dcc6e691601f89500b3487e06) ---- - configure.ac | 2 +- - python/header-py.c | 4 ++-- - python/rpmsystem-py.h | 33 --------------------------------- - python/spec-py.c | 2 +- - 4 files changed, 4 insertions(+), 37 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 34ea85f9f..4d1a48e5f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -800,7 +800,7 @@ esac], - - WITH_PYTHON_SUBPACKAGE=0 - AS_IF([test "$enable_python" = yes],[ -- AM_PATH_PYTHON([2.6],[ -+ AM_PATH_PYTHON([2.7],[ - PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}], [WITH_PYTHON_SUBPACKAGE=1]) - AC_SUBST(PYTHON_CFLAGS) - AC_SUBST(PYTHON_LIB) -diff --git a/python/header-py.c b/python/header-py.c -index 628b48534..c9d54e869 100644 ---- a/python/header-py.c -+++ b/python/header-py.c -@@ -376,8 +376,8 @@ static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) - - if (obj == NULL) { - h = headerNew(); -- } else if (CAPSULE_CHECK(obj)) { -- h = CAPSULE_EXTRACT(obj, "rpm._C_Header"); -+ } else if (PyCapsule_CheckExact(obj)) { -+ h = PyCapsule_GetPointer(obj, "rpm._C_Header"); - headerLink(h); - } else if (hdrObject_Check(obj)) { - h = headerCopy(((hdrObject*) obj)->h); -diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h -index c8423e3dc..955d60cd3 100644 ---- a/python/rpmsystem-py.h -+++ b/python/rpmsystem-py.h -@@ -9,39 +9,6 @@ - #include - #include - --#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0205 --typedef ssize_t Py_ssize_t; --typedef Py_ssize_t (*lenfunc)(PyObject *); --#endif -- --/* Compatibility macros for Python < 2.6 */ --#ifndef PyVarObject_HEAD_INIT --#define PyVarObject_HEAD_INIT(type, size) \ -- PyObject_HEAD_INIT(type) size, --#endif -- --#ifndef Py_TYPE --#define Py_TYPE(o) ((o)->ob_type) --#endif -- --#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0206 --#define PyBytes_Check PyString_Check --#define PyBytes_FromString PyString_FromString --#define PyBytes_FromStringAndSize PyString_FromStringAndSize --#define PyBytes_Size PyString_Size --#define PyBytes_AsString PyString_AsString --#endif -- --#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) >= 0x0207 --#define CAPSULE_BUILD(ptr,name) PyCapsule_New(ptr, name, NULL) --#define CAPSULE_CHECK(obj) PyCapsule_CheckExact(obj) --#define CAPSULE_EXTRACT(obj,name) PyCapsule_GetPointer(obj, name) --#else --#define CAPSULE_BUILD(ptr,name) PyCObject_FromVoidPtr(ptr, NULL) --#define CAPSULE_CHECK(obj) PyCObject_Check(obj) --#define CAPSULE_EXTRACT(obj,name) PyCObject_AsVoidPtr(obj) --#endif -- - /* For Python 3, use the PyLong type throughout in place of PyInt */ - #if PY_MAJOR_VERSION >= 3 - #define PyInt_Check PyLong_Check -diff --git a/python/spec-py.c b/python/spec-py.c -index fa7e58928..4efdbf4bf 100644 ---- a/python/spec-py.c -+++ b/python/spec-py.c -@@ -34,7 +34,7 @@ static PyObject *makeHeader(Header h) - PyObject *rpmmod = PyImport_ImportModuleNoBlock("rpm"); - if (rpmmod == NULL) return NULL; - -- PyObject *ptr = CAPSULE_BUILD(h, "rpm._C_Header"); -+ PyObject *ptr = PyCapsule_New(h, "rpm._C_Header", NULL); - PyObject *hdr = PyObject_CallMethod(rpmmod, "hdr", "(O)", ptr); - Py_XDECREF(ptr); - Py_XDECREF(rpmmod); --- -2.21.0 - diff --git a/SOURCES/0004-Fix-printf-formatting-in-reflink.c.patch b/SOURCES/0004-Fix-printf-formatting-in-reflink.c.patch deleted file mode 100644 index c33f3d5..0000000 --- a/SOURCES/0004-Fix-printf-formatting-in-reflink.c.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 15127592f8cc3221129f61b79319d88c7727bec3 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -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 - diff --git a/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch b/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch deleted file mode 100644 index 12f8d8b..0000000 --- a/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch +++ /dev/null @@ -1,329 +0,0 @@ -From f354c5a4265ddad758ad41abfb2f5fe174a54c69 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch b/SOURCES/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch deleted file mode 100644 index fe0ffef..0000000 --- a/SOURCES/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 98470eccf09b80ed11528ac893852d649c50be72 Mon Sep 17 00:00:00 2001 -Message-Id: <98470eccf09b80ed11528ac893852d649c50be72.1571920849.git.pmatilai@redhat.com> -In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Fri, 5 Oct 2018 14:05:27 +0300 -Subject: [PATCH 5/5] Drop an unnecessary Python 2 vs 3 incompatibility from - the test - -Python 2 speaks about 'type' whereas 3 speaks about 'class', which from -our perspective is just unnecessary pain with no gain. - -(cherry picked from commit ff3d8ac2e5cb4456ad1355f227f3ccef08e01972) ---- - tests/rpmpython.at | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/tests/rpmpython.at b/tests/rpmpython.at -index ae020ae95..bc42e49e4 100644 ---- a/tests/rpmpython.at -+++ b/tests/rpmpython.at -@@ -92,7 +92,7 @@ h['arch'] = 'noarch' - myprint(h['nevra']) - del h['epoch'] - myprint(h['nevra']) --for a in ['name', 'bugurl', '__class__', '__foo__', ]: -+for a in ['name', 'bugurl', '__foo__', ]: - try: - x = getattr(h, a) - myprint(x) -@@ -103,7 +103,6 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]: - testpkg-1.0-1.noarch - testpkg - None -- - 'rpm.hdr' object has no attribute '__foo__'] - ) - --- -2.21.0 - diff --git a/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch b/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch deleted file mode 100644 index ce68ba5..0000000 --- a/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: Panu Matilainen -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 - diff --git a/SOURCES/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch b/SOURCES/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch deleted file mode 100644 index 282dff0..0000000 --- a/SOURCES/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch +++ /dev/null @@ -1,73 +0,0 @@ -From fd4060dcfbe4127fb0d19f1878d0d8b9f34c7b9a Mon Sep 17 00:00:00 2001 -From: chantra -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 -+# -+# 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 - diff --git a/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch b/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch deleted file mode 100644 index 1b987f5..0000000 --- a/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch +++ /dev/null @@ -1,71 +0,0 @@ -From bcdd8505e792fd67c1480d43d987b92a61710e53 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0006-rpm2extents-verify-package-signature-during-transcod.patch b/SOURCES/0006-rpm2extents-verify-package-signature-during-transcod.patch deleted file mode 100644 index c2eb42c..0000000 --- a/SOURCES/0006-rpm2extents-verify-package-signature-during-transcod.patch +++ /dev/null @@ -1,431 +0,0 @@ -From ea1177fcef609519f0c2377ebee236001d2a8fae Mon Sep 17 00:00:00 2001 -From: chantra -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 - #include /* rpmReadPackageFile .. */ -+#include - #include - #include - #include -@@ -10,6 +12,7 @@ - - #include - #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]* "); - -- 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 - diff --git a/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch b/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch deleted file mode 100644 index b70d845..0000000 --- a/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0a7318ab4467d3156723c7a265dbd3456b8d1e20 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 /* rpmlog */ --#include /* rnibble */ -+#include - #include /* 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 - diff --git a/SOURCES/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch b/SOURCES/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch deleted file mode 100644 index 07c84fd..0000000 --- a/SOURCES/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch +++ /dev/null @@ -1,282 +0,0 @@ -From a4755a5ed793ca439bb23b804ba7a8ab080ff110 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch b/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch deleted file mode 100644 index 1d7daa4..0000000 --- a/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch +++ /dev/null @@ -1,105 +0,0 @@ -From ff2fb80469e9aa478ea4de3eae5d9c13ca411382 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch b/SOURCES/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch deleted file mode 100644 index ddbf31d..0000000 --- a/SOURCES/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch +++ /dev/null @@ -1,116 +0,0 @@ -From c705a6287f8c7fb5e37dad0ac87257731a41fa69 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch b/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch deleted file mode 100644 index 627511c..0000000 --- a/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch +++ /dev/null @@ -1,29 +0,0 @@ -From efd41edd0c9ba848814a5434d986338c1691418e Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch b/SOURCES/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch deleted file mode 100644 index a0e9757..0000000 --- a/SOURCES/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 44b86112136e4804eb606636cbcb4ae847cad773 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch b/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch deleted file mode 100644 index e619007..0000000 --- a/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 3461bd52ef2d403de1c420962aac52834f6e4b34 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch b/SOURCES/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch deleted file mode 100644 index 98987d6..0000000 --- a/SOURCES/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 7da1e826ccb08fdd404524146736b3f12a473e31 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch b/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch deleted file mode 100644 index d86b96b..0000000 --- a/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 9e1a49197a6ddd0e984c12c9dc15fe7af435b611 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 "), -@@ -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 - diff --git a/SOURCES/0011-rpm2extents-Perform-digest-computation-within-the-va.patch b/SOURCES/0011-rpm2extents-Perform-digest-computation-within-the-va.patch deleted file mode 100644 index ea98bed..0000000 --- a/SOURCES/0011-rpm2extents-Perform-digest-computation-within-the-va.patch +++ /dev/null @@ -1,389 +0,0 @@ -From 86776bf17f1644c76fdf8b87042645cf77bd3873 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch b/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch deleted file mode 100644 index f287e92..0000000 --- a/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 031b8481a0dfe875e9cf0f5d440b9379a62651a6 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 ]) -+AT_SETUP([rpmsign --addsign --rpmv3 ]) - 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 ]) -+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 ]) --- -2.27.0 - diff --git a/SOURCES/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch b/SOURCES/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch deleted file mode 100644 index 6a48dc8..0000000 --- a/SOURCES/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch +++ /dev/null @@ -1,299 +0,0 @@ -From ecab80b80e3917d3acf0f909c9cc84691a207fc0 Mon Sep 17 00:00:00 2001 -From: chantra -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 -+#include -+ -+#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 -+ -+/* 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 - #include "lib/rpmlib.h" - #include "lib/rpmplugin.h" -+#include "lib/rpmextents_internal.h" - #include "lib/rpmte_internal.h" - #include - #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 -@@ -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 - diff --git a/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch b/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch deleted file mode 100644 index 70975fa..0000000 --- a/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 5e11a52627882efe6a15622ec256835a821e3eff Mon Sep 17 00:00:00 2001 -From: Igor Kanyuka -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 - diff --git a/SOURCES/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch b/SOURCES/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch deleted file mode 100644 index 56bb554..0000000 --- a/SOURCES/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 5c97d7f83f56015d6a37934cee4e55ed8d747890 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0014-Drop-support-for-dmalloc.patch b/SOURCES/0014-Drop-support-for-dmalloc.patch deleted file mode 100644 index 55dd7d4..0000000 --- a/SOURCES/0014-Drop-support-for-dmalloc.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 6398807623ca24eafac0607b3d09b244cc5dfd5d Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - --#ifdef DMALLOC --#include --#endif -- - #define RPMDBG_TOSTR(a) RPMDBG_TOSTR_ARG(a) - #define RPMDBG_TOSTR_ARG(a) #a - --- -2.27.0 - diff --git a/SOURCES/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch b/SOURCES/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch deleted file mode 100644 index 737368d..0000000 --- a/SOURCES/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch +++ /dev/null @@ -1,79 +0,0 @@ -From ad46eb4132cbd2c4ee23686a1c52f2fc57afffc5 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch b/SOURCES/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch deleted file mode 100644 index 8183898..0000000 --- a/SOURCES/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch +++ /dev/null @@ -1,33 +0,0 @@ -From b2fc576828af873a1993bdaa2fcb7c860b94df3e Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch deleted file mode 100644 index e6dae81..0000000 --- a/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch deleted file mode 100644 index 89845cb..0000000 --- a/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch +++ /dev/null @@ -1,136 +0,0 @@ -From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 ]], -+ [[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 "), - N_("") }, -@@ -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 - diff --git a/SOURCES/0016-test-new-runroot_plugins-function-to-run-command-in-.patch b/SOURCES/0016-test-new-runroot_plugins-function-to-run-command-in-.patch deleted file mode 100644 index 1bd2253..0000000 --- a/SOURCES/0016-test-new-runroot_plugins-function-to-run-command-in-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From e04b5d20a6d8c64dba7416edba8e435145a5d7d3 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch deleted file mode 100644 index ae64146..0000000 --- a/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch +++ /dev/null @@ -1,51 +0,0 @@ -From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch b/SOURCES/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch deleted file mode 100644 index 20e572f..0000000 --- a/SOURCES/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e86207d3395e0963f19363b047551100569900df Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch b/SOURCES/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch deleted file mode 100644 index 7a5c5fd..0000000 --- a/SOURCES/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 048db395b6de8544dc88231f0afebee8570daee6 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch deleted file mode 100644 index 77a8b31..0000000 --- a/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 "), -+ N_("") }, - #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 - diff --git a/SOURCES/0019-Implement-rpmSignVerity.patch b/SOURCES/0019-Implement-rpmSignVerity.patch deleted file mode 100644 index 70e873a..0000000 --- a/SOURCES/0019-Implement-rpmSignVerity.patch +++ /dev/null @@ -1,243 +0,0 @@ -From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 -+ */ -+ -+#include "system.h" -+ -+#include /* RPMSIGTAG & related */ -+#include /* rpmlog */ -+#include -+#include /* rpmDigestLength */ -+#include "lib/header.h" /* HEADERGET_MINMEM */ -+#include "lib/header_internal.h" -+#include "lib/rpmtypes.h" /* rpmRC */ -+#include -+#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(¶ms, 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, -+ ¶ms, &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 -+#include -+ -+#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 - diff --git a/SOURCES/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch b/SOURCES/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch deleted file mode 100644 index 1e98fd1..0000000 --- a/SOURCES/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 5f762af17c6e72e86e4710975dcdfd71fc5d1b07 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch deleted file mode 100644 index b099eaf..0000000 --- a/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch +++ /dev/null @@ -1,95 +0,0 @@ -From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch b/SOURCES/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch deleted file mode 100644 index 24f0711..0000000 --- a/SOURCES/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 13aea986ada3ed7d26182d81d8878bcc807a6ab5 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch deleted file mode 100644 index 6caee37..0000000 --- a/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch +++ /dev/null @@ -1,210 +0,0 @@ -From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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(¶ms, 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, ¶ms, &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(¶ms, 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, -- ¶ms, &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 - diff --git a/SOURCES/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch b/SOURCES/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch deleted file mode 100644 index 250aa6b..0000000 --- a/SOURCES/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 3e363f853a4379e0199db81f777f4b610e158eae Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0022-reflink-fix-support-for-hardlinks.patch b/SOURCES/0022-reflink-fix-support-for-hardlinks.patch deleted file mode 100644 index e4d6558..0000000 --- a/SOURCES/0022-reflink-fix-support-for-hardlinks.patch +++ /dev/null @@ -1,132 +0,0 @@ -From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch deleted file mode 100644 index dba0ca6..0000000 --- a/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0023-Process-verity-tag-on-package-read.patch b/SOURCES/0023-Process-verity-tag-on-package-read.patch deleted file mode 100644 index 4f682c7..0000000 --- a/SOURCES/0023-Process-verity-tag-on-package-read.patch +++ /dev/null @@ -1,189 +0,0 @@ -From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - #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 - diff --git a/SOURCES/0023-rpm2extents-Improve-logging.patch b/SOURCES/0023-rpm2extents-Improve-logging.patch deleted file mode 100644 index 8ac52f7..0000000 --- a/SOURCES/0023-rpm2extents-Improve-logging.patch +++ /dev/null @@ -1,393 +0,0 @@ -From a2c959085250d186c54130b78af076095c3d3cd3 Mon Sep 17 00:00:00 2001 -From: chantra -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]* "); - - 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 - diff --git a/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch b/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch deleted file mode 100644 index 2fc3f5a..0000000 --- a/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); - params.version = 1; --- -2.27.0 - diff --git a/SOURCES/0024-rpm2extents-create-footer-struct-and-helpers.patch b/SOURCES/0024-rpm2extents-create-footer-struct-and-helpers.patch deleted file mode 100644 index baabce0..0000000 --- a/SOURCES/0024-rpm2extents-create-footer-struct-and-helpers.patch +++ /dev/null @@ -1,200 +0,0 @@ -From aabaa6c6587c37b84a1b9cfd98bff31f1b69345e Mon Sep 17 00:00:00 2001 -From: chantra -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 - #include -+#include -+#include -+ - - #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 - -+/** \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 - diff --git a/SOURCES/0025-extents-move-more-functions-helpers-behind-rpmextent.patch b/SOURCES/0025-extents-move-more-functions-helpers-behind-rpmextent.patch deleted file mode 100644 index 71a54e6..0000000 --- a/SOURCES/0025-extents-move-more-functions-helpers-behind-rpmextent.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 8235711d92d8783abe63d6e4f29afd495fc4b22e Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch deleted file mode 100644 index bb6e4f3..0000000 --- a/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0026-fix-integer-underflow-in-vfyFDCb.patch b/SOURCES/0026-fix-integer-underflow-in-vfyFDCb.patch deleted file mode 100644 index 5fe1900..0000000 --- a/SOURCES/0026-fix-integer-underflow-in-vfyFDCb.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 3372e6c917e54b3a84c04ca4274000da04a98e86 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch deleted file mode 100644 index d1c12c9..0000000 --- a/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch +++ /dev/null @@ -1,161 +0,0 @@ -From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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(¶ms, 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 - diff --git a/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch b/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch deleted file mode 100644 index aa78311..0000000 --- a/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch +++ /dev/null @@ -1,281 +0,0 @@ -From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 -+ */ -+ -+#include "system.h" -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 - diff --git a/SOURCES/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch b/SOURCES/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch deleted file mode 100644 index 7bb79b2..0000000 --- a/SOURCES/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 1e0850cf7649578e1d7da815751efaa8101773e7 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch deleted file mode 100644 index 0b9bb41..0000000 --- a/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0028-reflink-remove-requirement-for-executable-stack-flag.patch b/SOURCES/0028-reflink-remove-requirement-for-executable-stack-flag.patch deleted file mode 100644 index a3158f6..0000000 --- a/SOURCES/0028-reflink-remove-requirement-for-executable-stack-flag.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch deleted file mode 100644 index 6575b99..0000000 --- a/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch b/SOURCES/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch deleted file mode 100644 index f4bf8e3..0000000 --- a/SOURCES/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 5753b178a08043316e6f3556754741cdd9cd19c5 Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch deleted file mode 100644 index d872d5e..0000000 --- a/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch b/SOURCES/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch deleted file mode 100644 index 3e64a30..0000000 --- a/SOURCES/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch +++ /dev/null @@ -1,91 +0,0 @@ -From dc53b002bd3d03a21e9af406a9aff5e588710b5b Mon Sep 17 00:00:00 2001 -From: chantra -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 - diff --git a/SOURCES/0031-Update-man-page-for-rpmsign.patch b/SOURCES/0031-Update-man-page-for-rpmsign.patch deleted file mode 100644 index 938e0f1..0000000 --- a/SOURCES/0031-Update-man-page-for-rpmsign.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - Erik Troan - Panu Matilainen - Fionnuala Gunter -+Jes Sorensen - .fi --- -2.27.0 - diff --git a/SOURCES/0031-rpmcow-denylist.patch b/SOURCES/0031-rpmcow-denylist.patch deleted file mode 100644 index da7aee3..0000000 --- a/SOURCES/0031-rpmcow-denylist.patch +++ /dev/null @@ -1,386 +0,0 @@ -From: Richard Phibel - -Subject: RPM with Copy on Write: add deny list mechanism - -commit 3431550e6c92ba4bc6d091cb244f70c158dfbbaa -Author: Richard Phibel -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 - -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]) diff --git a/SOURCES/0032-rpmcow-workaround.patch b/SOURCES/0032-rpmcow-workaround.patch deleted file mode 100644 index 69d5178..0000000 --- a/SOURCES/0032-rpmcow-workaround.patch +++ /dev/null @@ -1,385 +0,0 @@ -From: Richard Phibel - -Subject: RPM with Copy on Write: workaround for corrupt signature header - -commit 7976c921f60ec5d20c50c4c702ec5636b39210ba -Author: Richard Phibel -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 - -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); diff --git a/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch deleted file mode 100644 index c3f56e8..0000000 --- a/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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_("") }, - { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, - N_("use file signing cert "), - N_("") }, -@@ -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 - #include - #include -+#include -+#ifdef WITH_FSVERITY -+#include -+#endif - - #include /* RPMSIGTAG & related */ - #include -@@ -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 - diff --git a/SOURCES/0033-Enable-fsverity-in-CI.patch b/SOURCES/0033-Enable-fsverity-in-CI.patch deleted file mode 100644 index 55a209f..0000000 --- a/SOURCES/0033-Enable-fsverity-in-CI.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -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 ---- - 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 - diff --git a/SOURCES/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch b/SOURCES/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch deleted file mode 100644 index 2ea2066..0000000 --- a/SOURCES/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 937f9bc67b905851c78719d8397926eaa97b174a Mon Sep 17 00:00:00 2001 -From: Richard Phibel -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 - diff --git a/SOURCES/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch b/SOURCES/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch deleted file mode 100644 index 709472d..0000000 --- a/SOURCES/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a3b6102b4d2e79a8b74b036c6a29272a7f6e5c6a Mon Sep 17 00:00:00 2001 -From: Richard Phibel -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 - diff --git a/SOURCES/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch b/SOURCES/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch deleted file mode 100644 index 692ab33..0000000 --- a/SOURCES/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch +++ /dev/null @@ -1,257 +0,0 @@ -From aee5af8e4fe7908df90649eb699c3a1decf06b0c Mon Sep 17 00:00:00 2001 -From: Yu Wu -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 "), - N_("") }, -+ { "pkcs11_engine", '\0', POPT_ARG_STRING, &pkcs11Engine, 0, -+ N_("use pkcs#11 token for fsverity signing key with openssl engine "), -+ N_("") }, -+ { "pkcs11_module", '\0', POPT_ARG_STRING, &pkcs11Module, 0, -+ N_("use pkcs#11 token for fsverity signing key with openssl module "), -+ N_("") }, -+ { "pkcs11_keyid", '\0', POPT_ARG_STRING, &pkcs11KeyId, 0, -+ N_("use pkcs#11 token for fsverity signing key with keyid "), -+ N_("") }, - #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 - } diff --git a/SOURCES/0035-fix-IMA-signature-lengths-assumed-constant.patch b/SOURCES/0035-fix-IMA-signature-lengths-assumed-constant.patch deleted file mode 100644 index bed129d..0000000 --- a/SOURCES/0035-fix-IMA-signature-lengths-assumed-constant.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 07f1d3132f0c7b7ecb69a47a9930edb534a9250e Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -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 - diff --git a/SOURCES/1381.patch b/SOURCES/1381.patch deleted file mode 100644 index dd1a649..0000000 --- a/SOURCES/1381.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 7ae16d6bd37abdcc0430fbb1b25a0f821a60c234 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -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) diff --git a/SOURCES/1534.patch b/SOURCES/1534.patch deleted file mode 100644 index d5acd42..0000000 --- a/SOURCES/1534.patch +++ /dev/null @@ -1,1359 +0,0 @@ -From 3a5d2ee0f56d049927c4dcdd03e8e275ac03e20d Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Mon, 8 Feb 2021 10:45:59 +0200 -Subject: [PATCH 01/10] Clean up file unpack iteration logic a bit - -Handle rpmfiNext() in the while-condition directly to make it more like -similar other constructs elsewhere, adjust for the end of iteration -code after the loop. Also take the file index from rpmfiNext() so -we don't need multiple calls to rpmfiFX() later. ---- - lib/fsm.c | 19 +++++++------------ - 1 file changed, 7 insertions(+), 12 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 432bcbd90..f71b9bc1e 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -865,6 +865,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct stat sb; - int saveerrno = errno; - int rc = 0; -+ int fx = -1; - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; - int firsthardlink = -1; -@@ -886,17 +887,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Detect and create directories not explicitly in package. */ - rc = fsmMkdirs(files, fs, plugins); - -- while (!rc) { -- /* Read next payload header. */ -- rc = rpmfiNext(fi); -- -- if (rc < 0) { -- if (rc == RPMERR_ITER_END) -- rc = 0; -- break; -- } -- -- action = rpmfsGetAction(fs, rpmfiFX(fi)); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ action = rpmfsGetAction(fs, fx); - skip = XFA_SKIPPING(action); - if (action != FA_TOUCH) { - suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -@@ -920,7 +912,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (rc) { - skip = 1; - } else { -- setFileState(fs, rpmfiFX(fi)); -+ setFileState(fs, fx); - } - - if (!skip) { -@@ -1022,6 +1014,9 @@ touch: - fpath = _free(fpath); - } - -+ if (!rc && fx != RPMERR_ITER_END) -+ rc = fx; -+ - rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); - --- -2.34.1 - - -From 3096acbddc57eb2b65c96aad1ed3524ea9d0cead Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 08:25:28 +0200 -Subject: [PATCH 02/10] Drop unused filename variable - ---- - lib/fsm.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index f71b9bc1e..8e6a6c08b 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -976,11 +976,9 @@ touch: - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ - /* write the content to the first used instead */ -- char *fn = rpmfilesFN(files, firsthardlink); - rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); - wfd_close(&firstlinkfile); - firsthardlink = -1; -- free(fn); - } - - if (rc) { --- -2.34.1 - - -From 9561315538f1fc4a5b207a43ac39805134e7153f Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 09:57:17 +0200 -Subject: [PATCH 03/10] Don't update path info if rename failed on file commit - ---- - lib/fsm.c | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 8e6a6c08b..138b55297 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -797,14 +797,16 @@ static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *su - /* Rename temporary to final file name if needed. */ - if (dest != *path) { - rc = fsmRename(*path, dest); -- if (!rc && nsuffix) { -- char * opath = fsmFsPath(fi, NULL); -- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), -- opath, dest); -- free(opath); -+ if (!rc) { -+ if (nsuffix) { -+ char * opath = fsmFsPath(fi, NULL); -+ rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), -+ opath, dest); -+ free(opath); -+ } -+ free(*path); -+ *path = dest; - } -- free(*path); -- *path = dest; - } - } - --- -2.34.1 - - -From 73d090166a60c57484e4be40e46fcb07f026cbf8 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Thu, 27 Aug 2020 10:31:07 +0300 -Subject: [PATCH 04/10] Upgrade FA_TOUCH to FA_CREATE if the file went away - (RhBug:1872141) - -When %_minimize_writes is enabled, we determine unchanged files during -fingerprinting and only update their metadata (FA_TOUCH) instead of -always recreating from scratch (FA_CREATE) during install. However -package scriptlets (and administrators) can and will do arbitrary stuff -in the meanwhile, such as rm -f their own files in %pre, hoping to -get a fresh copy of contents no matter what. Or something. -Now, if the file was determined to not need changing by rpm, this will -just fail with chown & friends trying to touch non-existent file. -One can consider this a case of package shooting itself in the foot, but -when a package update fails or succeeds depending on %_minimize_writes this -to me suggests the feature is at fault as much as the package. - -Do fsmVerify() on all files to be FA_TOUCH'ed to detect files whose -type changed or were removed since fingerprinting. This still doesn't -ensure correctness if something tampers with the contents in the meanwhile, -(for that we'd need to run the file through the whole machinery again, -checksumming and all) but covers the most glaring cases. ---- - lib/fsm.c | 15 ++++++--- - tests/Makefile.am | 1 + - tests/data/SPECS/suicidal.spec | 19 ++++++++++++ - tests/rpmi.at | 56 ++++++++++++++++++++++++++++++++++ - 4 files changed, 87 insertions(+), 4 deletions(-) - create mode 100644 tests/data/SPECS/suicidal.spec - -diff --git a/lib/fsm.c b/lib/fsm.c -index 138b55297..8a4ecaf05 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -920,10 +920,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (!skip) { - int setmeta = 1; - -- /* When touching we don't need any of this... */ -- if (action == FA_TOUCH) -- goto touch; -- - /* Directories replacing something need early backup */ - if (!suffix) { - rc = fsmBackup(fi, action); -@@ -935,6 +931,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = RPMERR_ENOENT; - } - -+ /* See if the file was removed while our attention was elsewhere */ -+ if (rc == RPMERR_ENOENT && action == FA_TOUCH) { -+ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); -+ action = FA_CREATE; -+ fsmDebug(fpath, action, &sb); -+ } -+ -+ /* When touching we don't need any of this... */ -+ if (action == FA_TOUCH) -+ goto touch; -+ - if (S_ISREG(sb.st_mode)) { - if (rc == RPMERR_ENOENT) { - rc = fsmMkfile(fi, fpath, files, psm, nodigest, -diff --git a/tests/Makefile.am b/tests/Makefile.am -index 7a6641d4f..d540e2a7b 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -59,6 +59,7 @@ EXTRA_DIST += data/SPECS/verifyscript.spec - EXTRA_DIST += data/SPECS/fakeshell.spec - EXTRA_DIST += data/SPECS/scripts.spec - EXTRA_DIST += data/SPECS/selfconflict.spec -+EXTRA_DIST += data/SPECS/suicidal.spec - EXTRA_DIST += data/SPECS/replacetest.spec - EXTRA_DIST += data/SPECS/triggers.spec - EXTRA_DIST += data/SPECS/filetriggers.spec -diff --git a/tests/data/SPECS/suicidal.spec b/tests/data/SPECS/suicidal.spec -new file mode 100644 -index 000000000..77d17d8c9 ---- /dev/null -+++ b/tests/data/SPECS/suicidal.spec -@@ -0,0 +1,19 @@ -+Name: suicidal -+Version: 1 -+Release: %{rel} -+License: GPL -+Group: Testing -+Summary: Testing suicidal package behavior -+BuildArch: noarch -+ -+%description -+ -+%build -+mkdir -p %{buildroot}/opt -+echo shoot > %{buildroot}/opt/foot -+ -+%pre -p -+os.remove('/opt/foot') -+ -+%files -+/opt/foot -diff --git a/tests/rpmi.at b/tests/rpmi.at -index e8d6e9b7a..71e17821b 100644 ---- a/tests/rpmi.at -+++ b/tests/rpmi.at -@@ -711,3 +711,59 @@ runroot rpm -e testdoc - []) - AT_CLEANUP - -+AT_SETUP([rpm -i --excludeartifacts]) -+AT_KEYWORDS([install]) -+RPMDB_INIT -+runroot rpmbuild --quiet -bb /data/SPECS/vattrtest.spec -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --excludeartifacts /build/RPMS/noarch/vattrtest-1.0-1.noarch.rpm -+test -e ${RPMTEST}/opt/vattrtest/a && exit 1 -+runroot rpm -e vattrtest -+runroot rpm -i /build/RPMS/noarch/vattrtest-1.0-1.noarch.rpm -+test -e ${RPMTEST}/opt/vattrtest/a || exit 1 -+], -+[0], -+[], -+[]) -+AT_CLEANUP -+ -+AT_SETUP([rpm -U ]) -+AT_KEYWORDS([install]) -+RPMDB_INIT -+ -+for r in 1 2; do -+ runroot rpmbuild -bb --quiet \ -+ --define "rel ${r}" \ -+ /data/SPECS/suicidal.spec -+done -+ -+AT_CHECK([ -+RPMDB_INIT -+ -+for r in 1 2; do -+ runroot rpm -U \ -+ --define "_minimize_writes 0" \ -+ /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm -+done -+runroot rpm -V --nouser --nogroup suicidal -+], -+[0], -+[], -+[]) -+ -+AT_CHECK([ -+RPMDB_INIT -+ -+for r in 1 2; do -+ runroot rpm -U \ -+ --define "_minimize_writes 1" \ -+ /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm -+done -+runroot rpm -V --nouser --nogroup suicidal -+], -+[0], -+[], -+[]) -+AT_CLEANUP --- -2.34.1 - - -From e78ea489eeed84cdee9f5cedcbbf35cfcf1a70b6 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 09:47:19 +0200 -Subject: [PATCH 05/10] Refactor file install and remove around a common struct - -Collect the common state info into a struct shared by both file install -and remove, update code accordingly. The change looks much more drastic -than it is - it's just adding fp-> prefix to a lot of places. -While we're at it, remember the state data throughout the operation. - -No functional changes here, just paving way for the next steps which -will look clearer with these pre-requisites in place. ---- - lib/fsm.c | 158 +++++++++++++++++++++++++++++------------------------- - 1 file changed, 85 insertions(+), 73 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 8a4ecaf05..ab15c2bf3 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -38,6 +38,14 @@ static int strict_erasures = 0; - #define _dirPerms 0755 - #define _filePerms 0644 - -+struct filedata_s { -+ int skip; -+ rpmFileAction action; -+ const char *suffix; -+ char *fpath; -+ struct stat sb; -+}; -+ - /* - * XXX Forward declarations for previously exported functions to avoid moving - * things around needlessly -@@ -864,19 +872,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- struct stat sb; - int saveerrno = errno; - int rc = 0; - int fx = -1; -+ int fc = rpmfilesFC(files); - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; - int firsthardlink = -1; - FD_t firstlinkfile = NULL; -- int skip; -- rpmFileAction action; - char *tid = NULL; -- const char *suffix; -- char *fpath = NULL; -+ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - - if (fi == NULL) { - rc = RPMERR_BAD_MAGIC; -@@ -890,96 +895,99 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = fsmMkdirs(files, fs, plugins); - - while (!rc && (fx = rpmfiNext(fi)) >= 0) { -- action = rpmfsGetAction(fs, fx); -- skip = XFA_SKIPPING(action); -- if (action != FA_TOUCH) { -- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -+ struct filedata_s *fp = &fdata[fx]; -+ fp->action = rpmfsGetAction(fs, fx); -+ fp->skip = XFA_SKIPPING(fp->action); -+ if (fp->action != FA_TOUCH) { -+ fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - } else { -- suffix = NULL; -+ fp->suffix = NULL; - } -- fpath = fsmFsPath(fi, suffix); -+ fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ -- rc = rpmfiStat(fi, 1, &sb); -+ rc = rpmfiStat(fi, 1, &fp->sb); - -- fsmDebug(fpath, action, &sb); -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Exit on error. */ - if (rc) - break; - - /* Run fsm file pre hook for all plugins */ -- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, -- sb.st_mode, action); -+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action); - if (rc) { -- skip = 1; -+ fp->skip = 1; - } else { - setFileState(fs, fx); - } - -- if (!skip) { -+ if (!fp->skip) { - int setmeta = 1; - - /* Directories replacing something need early backup */ -- if (!suffix) { -- rc = fsmBackup(fi, action); -+ if (!fp->suffix) { -+ rc = fsmBackup(fi, fp->action); - } - /* Assume file does't exist when tmp suffix is in use */ -- if (!suffix) { -- rc = fsmVerify(fpath, fi); -+ if (!fp->suffix) { -+ rc = fsmVerify(fp->fpath, fi); - } else { - rc = RPMERR_ENOENT; - } - - /* See if the file was removed while our attention was elsewhere */ -- if (rc == RPMERR_ENOENT && action == FA_TOUCH) { -- rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); -- action = FA_CREATE; -- fsmDebug(fpath, action, &sb); -+ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { -+ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", -+ fp->fpath); -+ fp->action = FA_CREATE; -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - } - - /* When touching we don't need any of this... */ -- if (action == FA_TOUCH) -+ if (fp->action == FA_TOUCH) - goto touch; - -- if (S_ISREG(sb.st_mode)) { -+ if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fpath, files, psm, nodigest, -+ rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, - &setmeta, &firsthardlink, &firstlinkfile); - } -- } else if (S_ISDIR(sb.st_mode)) { -+ } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- mode_t mode = sb.st_mode; -+ mode_t mode = fp->sb.st_mode; - mode &= ~07777; - mode |= 00700; -- rc = fsmMkdir(fpath, mode); -+ rc = fsmMkdir(fp->fpath, mode); - } -- } else if (S_ISLNK(sb.st_mode)) { -+ } else if (S_ISLNK(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmSymlink(rpmfiFLink(fi), fpath); -+ rc = fsmSymlink(rpmfiFLink(fi), fp->fpath); - } -- } else if (S_ISFIFO(sb.st_mode)) { -+ } else if (S_ISFIFO(fp->sb.st_mode)) { - /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfifo(fpath, 0000); -+ rc = fsmMkfifo(fp->fpath, 0000); - } -- } else if (S_ISCHR(sb.st_mode) || -- S_ISBLK(sb.st_mode) || -- S_ISSOCK(sb.st_mode)) -+ } else if (S_ISCHR(fp->sb.st_mode) || -+ S_ISBLK(fp->sb.st_mode) || -+ S_ISSOCK(fp->sb.st_mode)) - { - if (rc == RPMERR_ENOENT) { -- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); -+ rc = fsmMknod(fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); - } - } else { - /* XXX Special case /dev/log, which shouldn't be packaged anyways */ -- if (!IS_DEV_LOG(fpath)) -+ if (!IS_DEV_LOG(fp->fpath)) - rc = RPMERR_UNKNOWN_FILETYPE; - } - - touch: - /* Set permissions, timestamps etc for non-hardlink entries */ - if (!rc && setmeta) { -- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); -+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -+ &fp->sb, nofcaps); - } - } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ -@@ -991,10 +999,10 @@ touch: - } - - if (rc) { -- if (!skip) { -+ if (!fp->skip) { - /* XXX only erase if temp fn w suffix is in use */ -- if (suffix) { -- (void) fsmRemove(fpath, sb.st_mode); -+ if (fp->suffix) { -+ (void) fsmRemove(fp->fpath, fp->sb.st_mode); - } - errno = saveerrno; - } -@@ -1002,23 +1010,22 @@ touch: - /* Notify on success. */ - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); - -- if (!skip) { -+ if (!fp->skip) { - /* Backup file if needed. Directories are handled earlier */ -- if (suffix) -- rc = fsmBackup(fi, action); -+ if (fp->suffix) -+ rc = fsmBackup(fi, fp->action); - - if (!rc) -- rc = fsmCommit(&fpath, fi, action, suffix); -+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); - } - } - - if (rc) -- *failedFile = xstrdup(fpath); -+ *failedFile = xstrdup(fp->fpath); - - /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fpath, -- sb.st_mode, action, rc); -- fpath = _free(fpath); -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); - } - - if (!rc && fx != RPMERR_ITER_END) -@@ -1034,7 +1041,9 @@ exit: - rpmfiFree(fi); - Fclose(payload); - free(tid); -- free(fpath); -+ for (int i = 0; i < fc; i++) -+ free(fdata[i].fpath); -+ free(fdata); - - return rc; - } -@@ -1046,29 +1055,31 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, - rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- struct stat sb; -+ int fc = rpmfilesFC(files); -+ int fx = -1; -+ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - int rc = 0; -- char *fpath = NULL; - -- while (!rc && rpmfiNext(fi) >= 0) { -- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); -- fpath = fsmFsPath(fi, NULL); -- rc = fsmStat(fpath, 1, &sb); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); -+ fp->fpath = fsmFsPath(fi, NULL); -+ rc = fsmStat(fp->fpath, 1, &fp->sb); - -- fsmDebug(fpath, action, &sb); -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Run fsm file pre hook for all plugins */ -- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, -- sb.st_mode, action); -+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action); - -- if (!XFA_SKIPPING(action)) -- rc = fsmBackup(fi, action); -+ if (!XFA_SKIPPING(fp->action)) -+ rc = fsmBackup(fi, fp->action); - - /* Remove erased files. */ -- if (action == FA_ERASE) { -+ if (fp->action == FA_ERASE) { - int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); - -- rc = fsmRemove(fpath, sb.st_mode); -+ rc = fsmRemove(fp->fpath, fp->sb.st_mode); - - /* - * Missing %ghost or %missingok entries are not errors. -@@ -1093,20 +1104,20 @@ 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"), -- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), -- fpath, strerror(errno)); -+ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), -+ fp->fpath, strerror(errno)); - } - } - - /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fpath, -- sb.st_mode, action, rc); -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); - - /* XXX Failure to remove is not (yet) cause for failure. */ - if (!strict_erasures) rc = 0; - - if (rc) -- *failedFile = xstrdup(fpath); -+ *failedFile = xstrdup(fp->fpath); - - if (rc == 0) { - /* Notify on success. */ -@@ -1114,10 +1125,11 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, - rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); - rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); - } -- fpath = _free(fpath); - } - -- free(fpath); -+ for (int i = 0; i < fc; i++) -+ free(fdata[i].fpath); -+ free(fdata); - rpmfiFree(fi); - - return rc; --- -2.34.1 - - -From 215525131b0e4e015d83c25828700d7531fec6dd Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:08:27 +0200 -Subject: [PATCH 06/10] Refactor fsmMkfile() to take advantage of the new state - struct - -Move setmeta into the struct too (we'll want this later anyhow), -and now we only need to pass the struct to fsmMkfile(). One less -argument to pass around, it has way too many still. - -No functional changes. ---- - lib/fsm.c | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index ab15c2bf3..6c873206c 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -39,6 +39,7 @@ static int strict_erasures = 0; - #define _filePerms 0644 - - struct filedata_s { -+ int setmeta; - int skip; - rpmFileAction action; - const char *suffix; -@@ -279,8 +280,8 @@ exit: - return rc; - } - --static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, -- rpmpsm psm, int nodigest, int *setmeta, -+static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, -+ rpmpsm psm, int nodigest, - int * firsthardlink, FD_t *firstlinkfile) - { - int rc = 0; -@@ -290,11 +291,11 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, - /* Create first hardlinked file empty */ - if (*firsthardlink < 0) { - *firsthardlink = rpmfiFX(fi); -- rc = wfd_open(firstlinkfile, dest); -+ rc = wfd_open(firstlinkfile, fp->fpath); - } else { - /* Create hard links for others */ - char *fn = rpmfilesFN(files, *firsthardlink); -- rc = link(fn, dest); -+ rc = link(fn, fp->fpath); - if (rc < 0) { - rc = RPMERR_LINK_FAILED; - } -@@ -305,14 +306,14 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, - existing) file with content */ - if (numHardlinks<=1) { - if (!rc) -- rc = expandRegular(fi, dest, psm, nodigest); -+ rc = expandRegular(fi, fp->fpath, psm, nodigest); - } else if (rpmfiArchiveHasContent(fi)) { - if (!rc) - rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); - wfd_close(firstlinkfile); - *firsthardlink = -1; - } else { -- *setmeta = 0; -+ fp->setmeta = 0; - } - - return rc; -@@ -898,6 +899,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct filedata_s *fp = &fdata[fx]; - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); -+ fp->setmeta = 1; - if (fp->action != FA_TOUCH) { - fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - } else { -@@ -924,8 +926,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - } - - if (!fp->skip) { -- int setmeta = 1; -- - /* Directories replacing something need early backup */ - if (!fp->suffix) { - rc = fsmBackup(fi, fp->action); -@@ -951,8 +951,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, -- &setmeta, &firsthardlink, &firstlinkfile); -+ rc = fsmMkfile(fi, fp, files, psm, nodigest, -+ &firsthardlink, &firstlinkfile); - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -985,7 +985,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - touch: - /* Set permissions, timestamps etc for non-hardlink entries */ -- if (!rc && setmeta) { -+ if (!rc && fp->setmeta) { - rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, - &fp->sb, nofcaps); - } --- -2.34.1 - - -From 062167c2532a066301b15a0e85a1ac6cb6c07472 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:24:22 +0200 -Subject: [PATCH 07/10] Clarify file installation temporary suffix rule - -We only use a temporary suffix for regular files that we are actually -creating, skipped and touched files should not have it. Add XFA_CREATING() -macro to accomppany XFA_SKIPPING() to easily check whether the file -is being created or something else. - -No functional changes but makes the logic clearer. ---- - lib/fsm.c | 5 +---- - lib/rpmfiles.h | 3 +++ - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 6c873206c..e4842a200 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -900,11 +900,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; -- if (fp->action != FA_TOUCH) { -+ if (XFA_CREATING(fp->action)) - fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -- } else { -- fp->suffix = NULL; -- } - fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ -diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h -index 64b33281a..7f3f82662 100644 ---- a/lib/rpmfiles.h -+++ b/lib/rpmfiles.h -@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e { - #define XFA_SKIPPING(_a) \ - ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) - -+#define XFA_CREATING(_a) \ -+ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) -+ - /** - * We pass these around as an array with a sentinel. - */ --- -2.34.1 - - -From b3c6a3358dc4ec72fda0a229c22a5b79ac392848 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:24:22 +0200 -Subject: [PATCH 08/10] Clarify file installation temporary suffix rule - -We only use a temporary suffix for regular files that we are actually -creating, skipped and touched files should not have it. Add XFA_CREATING() -macro to accomppany XFA_SKIPPING() to easily check whether the file -is being created or something else. - -No functional changes but makes the logic clearer. ---- - lib/fsm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index e4842a200..4d7c03895 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -900,8 +900,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; -- if (XFA_CREATING(fp->action)) -- fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -+ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) -+ fp->suffix = tid; - fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ --- -2.34.1 - - -From 9097021b19c658ff55f7515878bae0592fd86377 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 11:25:10 +0200 -Subject: [PATCH 09/10] Handle hardlink tracking with a file state pointer - -No functional changes, just makes it a little cleaner as firstlink now -points to the actual file data instead of a index number somewhere. ---- - lib/fsm.c | 20 +++++++++----------- - 1 file changed, 9 insertions(+), 11 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 4d7c03895..cef17e669 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -282,24 +282,22 @@ exit: - - static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, - rpmpsm psm, int nodigest, -- int * firsthardlink, FD_t *firstlinkfile) -+ struct filedata_s ** firstlink, FD_t *firstlinkfile) - { - int rc = 0; - int numHardlinks = rpmfiFNlink(fi); - - if (numHardlinks > 1) { - /* Create first hardlinked file empty */ -- if (*firsthardlink < 0) { -- *firsthardlink = rpmfiFX(fi); -+ if (*firstlink == NULL) { -+ *firstlink = fp; - rc = wfd_open(firstlinkfile, fp->fpath); - } else { - /* Create hard links for others */ -- char *fn = rpmfilesFN(files, *firsthardlink); -- rc = link(fn, fp->fpath); -+ rc = link((*firstlink)->fpath, fp->fpath); - if (rc < 0) { - rc = RPMERR_LINK_FAILED; - } -- free(fn); - } - } - /* Write normal files or fill the last hardlinked (already -@@ -311,7 +309,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, - if (!rc) - rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); - wfd_close(firstlinkfile); -- *firsthardlink = -1; -+ *firstlink = NULL; - } else { - fp->setmeta = 0; - } -@@ -879,10 +877,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - int fc = rpmfilesFC(files); - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; -- int firsthardlink = -1; - FD_t firstlinkfile = NULL; - char *tid = NULL; - struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); -+ struct filedata_s *firstlink = NULL; - - if (fi == NULL) { - rc = RPMERR_BAD_MAGIC; -@@ -949,7 +947,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { - rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firsthardlink, &firstlinkfile); -+ &firstlink, &firstlinkfile); - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -986,13 +984,13 @@ touch: - rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, - &fp->sb, nofcaps); - } -- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { -+ } else if (firstlink && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ - /* write the content to the first used instead */ - rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); - wfd_close(&firstlinkfile); -- firsthardlink = -1; -+ firstlink = NULL; - } - - if (rc) { --- -2.34.1 - - -From 357afe98316cb643a0757163ddbc276a071f1a18 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 14:15:33 +0200 -Subject: [PATCH 10/10] Handle file install failures more gracefully - -Run the file installation in multiple stages: -1) gather intel -2) unpack the archive to temporary files -3) set file metadatas -4) commit files to final location -5) mop up leftovers on failure - -This means we no longer leave behind a trail of untracked, potentially -harmful junk on installation failure. - -If commit step fails the package can still be left in an inconsistent stage, -this could be further improved by first backing up old files to temporary -location to allow undo on failure, but leaving that for some other day. -Also unowned directories will still be left behind. - -And yes, this is a somewhat scary change as it's the biggest ever change -to how rpm lays down files on install. Adopt the hardlink test spec -over to install tests and add some more tests for the new behavior. - -Fixes: #967 (+ multiple reports over the years) ---- - lib/fsm.c | 147 ++++++++++++++++++++------------ - tests/data/SPECS/hlinktest.spec | 4 + - tests/rpmbuild.at | 33 ------- - tests/rpmi.at | 92 ++++++++++++++++++++ - 4 files changed, 189 insertions(+), 87 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index cef17e669..82af6f39f 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -38,7 +38,17 @@ static int strict_erasures = 0; - #define _dirPerms 0755 - #define _filePerms 0644 - -+enum filestage_e { -+ FILE_COMMIT = -1, -+ FILE_NONE = 0, -+ FILE_PRE = 1, -+ FILE_UNPACK = 2, -+ FILE_PREP = 3, -+ FILE_POST = 4, -+}; -+ - struct filedata_s { -+ int stage; - int setmeta; - int skip; - rpmFileAction action; -@@ -868,10 +878,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmpsm psm, char ** failedFile) - { - FD_t payload = rpmtePayload(te); -- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ rpmfi fi = NULL; - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- int saveerrno = errno; - int rc = 0; - int fx = -1; - int fc = rpmfilesFC(files); -@@ -882,20 +891,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - struct filedata_s *firstlink = NULL; - -- if (fi == NULL) { -- rc = RPMERR_BAD_MAGIC; -- goto exit; -- } -- - /* transaction id used for temporary path suffix while installing */ - rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); - -- /* Detect and create directories not explicitly in package. */ -- rc = fsmMkdirs(files, fs, plugins); -- -+ /* Collect state data for the whole operation */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); - while (!rc && (fx = rpmfiNext(fi)) >= 0) { - struct filedata_s *fp = &fdata[fx]; -- fp->action = rpmfsGetAction(fs, fx); -+ if (rpmfiFFlags(fi) & RPMFILE_GHOST) -+ fp->action = FA_SKIP; -+ else -+ fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; - if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) -@@ -905,20 +911,32 @@ 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); - -- /* Exit on error. */ -- if (rc) -- break; -- - /* Run fsm file pre hook for all plugins */ - rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, - fp->sb.st_mode, fp->action); -- if (rc) { -- fp->skip = 1; -- } else { -- setFileState(fs, fx); -- } -+ fp->stage = FILE_PRE; -+ } -+ fi = rpmfiFree(fi); -+ -+ if (rc) -+ goto exit; -+ -+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ if (fi == NULL) { -+ rc = RPMERR_BAD_MAGIC; -+ goto exit; -+ } -+ -+ /* Detect and create directories not explicitly in package. */ -+ if (!rc) -+ rc = fsmMkdirs(files, fs, plugins); -+ -+ /* Process the payload */ -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; - - if (!fp->skip) { - /* Directories replacing something need early backup */ -@@ -942,7 +960,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - /* When touching we don't need any of this... */ - if (fp->action == FA_TOUCH) -- goto touch; -+ continue; - - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -978,12 +996,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = RPMERR_UNKNOWN_FILETYPE; - } - --touch: -- /* Set permissions, timestamps etc for non-hardlink entries */ -- if (!rc && fp->setmeta) { -- rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -- &fp->sb, nofcaps); -- } - } else if (firstlink && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ -@@ -993,47 +1005,74 @@ touch: - firstlink = NULL; - } - -- if (rc) { -- if (!fp->skip) { -- /* XXX only erase if temp fn w suffix is in use */ -- if (fp->suffix) { -- (void) fsmRemove(fp->fpath, fp->sb.st_mode); -- } -- errno = saveerrno; -- } -- } else { -- /* Notify on success. */ -+ /* Notify on success. */ -+ if (rc) -+ *failedFile = xstrdup(fp->fpath); -+ else - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); -+ fp->stage = FILE_UNPACK; -+ } -+ fi = rpmfiFree(fi); - -- if (!fp->skip) { -- /* Backup file if needed. Directories are handled earlier */ -- if (fp->suffix) -- rc = fsmBackup(fi, fp->action); -+ if (!rc && fx < 0 && fx != RPMERR_ITER_END) -+ rc = fx; - -- if (!rc) -- rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); -- } -+ /* Set permissions, timestamps etc for non-hardlink entries */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ if (!fp->skip && fp->setmeta) { -+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -+ &fp->sb, nofcaps); - } -- - if (rc) - *failedFile = xstrdup(fp->fpath); -+ fp->stage = FILE_PREP; -+ } -+ fi = rpmfiFree(fi); - -- /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -- fp->sb.st_mode, fp->action, rc); -+ /* If all went well, commit files to final destination */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ -+ if (!fp->skip) { -+ /* Backup file if needed. Directories are handled earlier */ -+ if (!rc && fp->suffix) -+ rc = fsmBackup(fi, fp->action); -+ -+ if (!rc) -+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); -+ -+ if (!rc) -+ fp->stage = FILE_COMMIT; -+ else -+ *failedFile = xstrdup(fp->fpath); -+ } - } -+ fi = rpmfiFree(fi); - -- if (!rc && fx != RPMERR_ITER_END) -- rc = fx; -+ /* Walk backwards in case we need to erase */ -+ fi = rpmfilesIter(files, RPMFI_ITER_BACK); -+ while ((fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ /* Run fsm file post hook for all plugins for all processed files */ -+ if (fp->stage) { -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); -+ } -+ -+ /* On failure, erase non-committed files */ -+ if (rc && fp->stage > FILE_NONE && !fp->skip) { -+ (void) fsmRemove(fp->fpath, fp->sb.st_mode); -+ } -+ } - - rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); - - exit: -- -- /* No need to bother with close errors on read */ -- rpmfiArchiveClose(fi); -- rpmfiFree(fi); -+ fi = rpmfiFree(fi); - Fclose(payload); - free(tid); - for (int i = 0; i < fc; i++) -diff --git a/tests/data/SPECS/hlinktest.spec b/tests/data/SPECS/hlinktest.spec -index b3b8866fc..1f453524e 100644 ---- a/tests/data/SPECS/hlinktest.spec -+++ b/tests/data/SPECS/hlinktest.spec -@@ -1,5 +1,6 @@ - %bcond_with unpackaged_dirs - %bcond_with unpackaged_files -+%bcond_with owned_dir - - Summary: Testing hard link behavior - Name: hlinktest -@@ -38,4 +39,7 @@ touch $RPM_BUILD_ROOT/toot - - %files - %defattr(-,root,root) -+%if %{with owned_dir} -+%dir /foo -+%endif - /foo/* -diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at -index 4294fd97c..c99fa7a63 100644 ---- a/tests/rpmbuild.at -+++ b/tests/rpmbuild.at -@@ -139,39 +139,6 @@ drwxrwxrwx zoot zoot /j/dir - []) - AT_CLEANUP - --# ------------------------------ --# hardlink tests --AT_SETUP([rpmbuild hardlink]) --AT_KEYWORDS([build]) --AT_CHECK([ --RPMDB_CLEAR --RPMDB_INIT --rm -rf ${TOPDIR} -- --runroot rpmbuild \ -- -bb --quiet /data/SPECS/hlinktest.spec -- --runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm -- --runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest --runroot rpm -V --nouser --nogroup hlinktest --ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l -- --], --[0], --[2 /foo/aaaa --1 /foo/copyllo --4 /foo/hello --4 /foo/hello-bar --4 /foo/hello-foo --4 /foo/hello-world --2 /foo/zzzz --87 --1 --], --[]) --AT_CLEANUP -- - AT_SETUP([rpmbuild unpackaged files]) - AT_KEYWORDS([build]) - AT_CHECK([ -diff --git a/tests/rpmi.at b/tests/rpmi.at -index 71e17821b..bf1606b6d 100644 ---- a/tests/rpmi.at -+++ b/tests/rpmi.at -@@ -767,3 +767,95 @@ runroot rpm -V --nouser --nogroup suicidal - [], - []) - AT_CLEANUP -+ -+# ------------------------------ -+# hardlink tests -+AT_SETUP([rpm -i hardlinks]) -+AT_KEYWORDS([build install]) -+RPMDB_INIT -+ -+# Need a reproducable test package -+runroot rpmbuild \ -+ --define "%optflags -O2 -g" \ -+ --define "%_target_platform noarch-linux" \ -+ --define "%_binary_payload w.ufdio" \ -+ --define "%_buildhost localhost" \ -+ --define "%use_source_date_epoch_as_buildtime 1" \ -+ --define "%source_date_epoch_from_changelog 1" \ -+ --define "%clamp_mtime_to_source_date_epoch 1" \ -+ --with owned_dir \ -+ -bb --quiet /data/SPECS/hlinktest.spec -+ -+pkg="/build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm" -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/1.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/1.rpm" \ -+ conv=notrunc bs=1 seek=8180 count=6 2> /dev/null -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/2.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/2.rpm" \ -+ conv=notrunc bs=1 seek=8150 count=6 2> /dev/null -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/3.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/3.rpm" \ -+ conv=notrunc bs=1 seek=8050 count=6 2> /dev/null -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/1.rpm -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[], -+[error: unpacking of archive failed: cpio: Archive file not in header -+error: hlinktest-1.0-1.noarch: install failed -+]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/2.rpm -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[], -+[error: unpacking of archive failed: cpio: Bad/unreadable header -+error: hlinktest-1.0-1.noarch: install failed -+]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/3.rpm 2>&1| sed 's/;.*:/:/g' -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[error: unpacking of archive failed on file /foo/hello-world: Digest mismatch -+error: hlinktest-1.0-1.noarch: install failed -+], -+[]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm -+runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest -+ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l -+runroot rpm -e hlinktest -+ -+], -+[0], -+[1 /foo -+2 /foo/aaaa -+1 /foo/copyllo -+4 /foo/hello -+4 /foo/hello-bar -+4 /foo/hello-foo -+4 /foo/hello-world -+2 /foo/zzzz -+87 -+1 -+], -+[]) -+AT_CLEANUP -+ --- -2.34.1 - diff --git a/SOURCES/compile-with-Platform-Python-binary-where-relevant.patch b/SOURCES/compile-with-Platform-Python-binary-where-relevant.patch deleted file mode 100644 index 7b0da28..0000000 --- a/SOURCES/compile-with-Platform-Python-binary-where-relevant.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 682397a8e2758058f780cccd51b570d39415b9b2 Mon Sep 17 00:00:00 2001 -From: Tomas Orsava -Date: Tue, 3 Jul 2018 14:58:32 +0200 -Subject: [PATCH] Compile with Platform-Python binary where relevant - ---- - scripts/brp-python-bytecompile | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile -index 7ed1d7f..9d0a421 100644 ---- a/scripts/brp-python-bytecompile -+++ b/scripts/brp-python-bytecompile -@@ -60,6 +60,9 @@ shopt -s nullglob - 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 -+ python_binary=/usr/libexec/platform-python -+ fi - real_libdir=${python_libdir/$RPM_BUILD_ROOT/} - echo "Bytecompiling .py files below $python_libdir using $python_binary" - --- -2.14.4 - diff --git a/SOURCES/disable-python-extra.patch b/SOURCES/disable-python-extra.patch deleted file mode 100644 index 8cb7595..0000000 --- a/SOURCES/disable-python-extra.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/platform.in 2018-07-19 17:24:58.737922904 +0200 -+++ b/platform.in 2018-07-19 17:25:25.480028741 +0200 -@@ -65,7 +65,7 @@ - - %__arch_install_post @ARCH_INSTALL_POST@ - %_python_bytecompile_errors_terminate_build 0 --%_python_bytecompile_extra 1 -+%_python_bytecompile_extra 0 - - # Standard brp-macro naming: - # convert all '-' in basename to '_', add two leading underscores. diff --git a/SOURCES/measure.patch b/SOURCES/measure.patch deleted file mode 100644 index b0c580f..0000000 --- a/SOURCES/measure.patch +++ /dev/null @@ -1,279 +0,0 @@ -From 517a37ae7beeb77e2b4870be11611f82c1200b3c Mon Sep 17 00:00:00 2001 -From: Matthew Almond -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 -+#include -+#include -+#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 - diff --git a/SOURCES/ndb_query_ro_media.patch b/SOURCES/ndb_query_ro_media.patch deleted file mode 100644 index 92393eb..0000000 --- a/SOURCES/ndb_query_ro_media.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 93e482be29ee683011c71f23b3b0096889e50331 Mon Sep 17 00:00:00 2001 -From: Michael Schroeder -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; diff --git a/SOURCES/rpm-4-14.3-selinux-log-error.patch b/SOURCES/rpm-4-14.3-selinux-log-error.patch deleted file mode 100644 index f16a908..0000000 --- a/SOURCES/rpm-4-14.3-selinux-log-error.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- rpm-4.14.3/plugins/selinux.c.orig 2020-05-11 16:07:22.873791795 +0200 -+++ rpm-4.14.3/plugins/selinux.c 2020-05-11 16:10:11.701771157 +0200 -@@ -47,7 +47,7 @@ - - sehandle = selabel_open(SELABEL_CTX_FILE, opts, 1); - -- rpmlog(RPMLOG_DEBUG, "selabel_open: (%s) %s\n", -+ rpmlog((sehandle == NULL) ? RPMLOG_ERR : RPMLOG_DEBUG, "selabel_open: (%s) %s\n", - path, (sehandle == NULL ? strerror(errno) : "")); - - return (sehandle != NULL) ? RPMRC_OK : RPMRC_FAIL; diff --git a/SOURCES/rpm-4.11.x-siteconfig.patch b/SOURCES/rpm-4.11.x-siteconfig.patch deleted file mode 100644 index f32f859..0000000 --- a/SOURCES/rpm-4.11.x-siteconfig.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.11.1-rc1/macros.in.siteconfig rpm-4.11.1-rc1/macros.in ---- rpm-4.11.1-rc1/macros.in.siteconfig 2013-06-07 13:19:21.000000000 +0300 -+++ rpm-4.11.1-rc1/macros.in 2013-06-11 15:06:59.525747503 +0300 -@@ -647,6 +647,8 @@ package or when debugging this package.\ - export CLASSPATH}\ - PKG_CONFIG_PATH=\"${PKG_CONFIG_PATH}:%{_libdir}/pkgconfig:%{_datadir}/pkgconfig\"\ - export PKG_CONFIG_PATH\ -+ CONFIG_SITE=${CONFIG_SITE:-NONE}\ -+ export CONFIG_SITE\ - \ - %{verbose:set -x}%{!verbose:exec > /dev/null}\ - umask 022\ diff --git a/SOURCES/rpm-4.12.0-rpm2cpio-hack.patch b/SOURCES/rpm-4.12.0-rpm2cpio-hack.patch deleted file mode 100644 index 38c7dbd..0000000 --- a/SOURCES/rpm-4.12.0-rpm2cpio-hack.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/rpm2cpio.c b/rpm2cpio.c -index 89ebdfa..ae999ff 100644 ---- a/rpm2cpio.c -+++ b/rpm2cpio.c -@@ -84,7 +84,12 @@ int main(int argc, char *argv[]) - exit(EXIT_FAILURE); - } - -- rc = (ufdCopy(gzdi, fdo) == payload_size) ? EXIT_SUCCESS : EXIT_FAILURE; -+ /* -+ * XXX HACK for #1142949: should be equality test, but archive size -+ * short by cpio trailer size in packages built with rpm 4.12.0 -+ * and its pre-releases. -+ */ -+ rc = (ufdCopy(gzdi, fdo) >= payload_size) ? EXIT_SUCCESS : EXIT_FAILURE; - - Fclose(fdo); - diff --git a/SOURCES/rpm-4.13.0-fedora-specspo.patch b/SOURCES/rpm-4.13.0-fedora-specspo.patch deleted file mode 100644 index 64416c7..0000000 --- a/SOURCES/rpm-4.13.0-fedora-specspo.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/lib/tagexts.c b/lib/tagexts.c -index f72ff60..2c0b179 100644 ---- a/lib/tagexts.c -+++ b/lib/tagexts.c -@@ -535,15 +535,6 @@ static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags) - return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags); - } - --/* I18N look aside diversions */ -- --#if defined(ENABLE_NLS) --extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ --#endif --static const char * const language = "LANGUAGE"; -- --static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; -- - /** - * Retrieve i18n text. - * @param h header -@@ -554,59 +545,30 @@ static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; - */ - static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags) - { -- int rc; -+ int rc = headerGet(h, tag, td, HEADERGET_ALLOC); - #if defined(ENABLE_NLS) -- char * dstring = rpmExpand(_macro_i18ndomains, NULL); -- -- td->type = RPM_STRING_TYPE; -- td->data = NULL; -- td->count = 0; -- -- if (dstring && *dstring) { -- char *domain, *de; -- const char * langval; -- char * msgkey; -- const char * msgid; -+ if (rc) { -+ static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; -+ char *de, *dstring = rpmExpand(_macro_i18ndomains, NULL); -+ const char *domain; - -- rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME), -- rpmTagGetName(tag)); -- -- /* change to en_US for msgkey -> msgid resolution */ -- langval = getenv(language); -- (void) setenv(language, "en_US", 1); -- ++_nl_msg_cat_cntr; -- -- msgid = NULL; - for (domain = dstring; domain != NULL; domain = de) { -+ const char *msgid = td->data; -+ const char *msg = NULL; -+ - de = strchr(domain, ':'); - if (de) *de++ = '\0'; -- msgid = dgettext(domain, msgkey); -- if (msgid != msgkey) break; -- } -- -- /* restore previous environment for msgid -> msgstr resolution */ -- if (langval) -- (void) setenv(language, langval, 1); -- else -- unsetenv(language); -- ++_nl_msg_cat_cntr; -- -- if (domain && msgid) { -- td->data = dgettext(domain, msgid); -- td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */ -- td->count = 1; -- td->flags = RPMTD_ALLOCED; -+ msg = dgettext(domain, td->data); -+ if (msg != msgid) { -+ free(td->data); -+ td->data = xstrdup(msg); -+ break; -+ } - } -- dstring = _free(dstring); -- free(msgkey); -- if (td->data) -- return 1; -+ free(dstring); - } -- -- free(dstring); - #endif - -- rc = headerGet(h, tag, td, HEADERGET_ALLOC); - return rc; - } - diff --git a/SOURCES/rpm-4.13.90-ldflags.patch b/SOURCES/rpm-4.13.90-ldflags.patch deleted file mode 100644 index 99152e8..0000000 --- a/SOURCES/rpm-4.13.90-ldflags.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -up rpm-4.9.1.1/macros.in.jx rpm-4.9.1.1/macros.in ---- rpm-4.9.1.1/macros.in.jx 2011-08-03 16:19:05.000000000 -0400 -+++ rpm-4.9.1.1/macros.in 2011-08-08 09:41:52.981064316 -0400 -@@ -674,10 +674,11 @@ print (t)\ - RPM_SOURCE_DIR=\"%{u2p:%{_sourcedir}}\"\ - RPM_BUILD_DIR=\"%{u2p:%{_builddir}}\"\ - RPM_OPT_FLAGS=\"%{optflags}\"\ -+ RPM_LD_FLAGS=\"%{?__global_ldflags}\"\ - RPM_ARCH=\"%{_arch}\"\ - RPM_OS=\"%{_os}\"\ - RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\ -- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ -+ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_LD_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ - RPM_DOC_DIR=\"%{_docdir}\"\ - export RPM_DOC_DIR\ - RPM_PACKAGE_NAME=\"%{NAME}\"\ diff --git a/SOURCES/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch b/SOURCES/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch deleted file mode 100644 index 361e1a4..0000000 --- a/SOURCES/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch +++ /dev/null @@ -1,28 +0,0 @@ -From bf636421120aa2c97f9e0fdcee3c211b4241bd86 Mon Sep 17 00:00:00 2001 -From: Tomas Orsava -Date: Mon, 29 Jan 2018 16:13:18 +0100 -Subject: [PATCH] Add envvar that will be present during RPM build - -Part of a Fedora Change for F28: -"Avoid /usr/bin/python in RPM build" -https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build ---- - macros.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/macros.in b/macros.in -index dd6ef67..68449e3 100644 ---- a/macros.in -+++ b/macros.in -@@ -804,6 +804,8 @@ package or when debugging this package.\ - export PKG_CONFIG_PATH\ - CONFIG_SITE=${CONFIG_SITE:-NONE}\ - export CONFIG_SITE\ -+ PYTHON_DISALLOW_AMBIGUOUS_VERSION=warn\ -+ export PYTHON_DISALLOW_AMBIGUOUS_VERSION\ - \ - %{verbose:set -x}%{!verbose:exec > /dev/null}\ - umask 022\ --- -2.13.6 - diff --git a/SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch b/SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch deleted file mode 100644 index 4c7c52c..0000000 --- a/SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 8390fa8515f499994646cf3bd113423744dc7bd9 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Fri, 30 Nov 2018 11:02:52 +0100 -Subject: [PATCH] Add RPMTAG_MODULARITYLABEL to distinguish packages build for - modularity - -Tag can be set with a ModularityLabel: statement in the spec file preamble or -via the modularitylabel macro ---- - build/parsePreamble.c | 4 ++++ - build/parseSpec.c | 1 + - lib/rpmtag.h | 1 + - macros.in | 5 +++++ - tests/rpmgeneral.at | 1 + - 5 files changed, 12 insertions(+) - -diff --git a/build/parsePreamble.c b/build/parsePreamble.c -index f5e06bac8..e340e5c7a 100644 ---- a/build/parsePreamble.c -+++ b/build/parsePreamble.c -@@ -43,6 +43,7 @@ static const rpmTagVal copyTagsDuringParse[] = { - RPMTAG_DISTTAG, - RPMTAG_BUGURL, - RPMTAG_GROUP, -+ RPMTAG_MODULARITYLABEL, - 0 - }; - -@@ -526,6 +527,7 @@ static struct optionalTag { - { RPMTAG_DISTURL, "%{disturl}" }, - { RPMTAG_DISTTAG, "%{disttag}" }, - { RPMTAG_BUGURL, "%{bugurl}" }, -+ { RPMTAG_MODULARITYLABEL, "%{modularitylabel}"}, - { -1, NULL } - }; - -@@ -779,6 +781,7 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, - case RPMTAG_URL: - case RPMTAG_DISTTAG: - case RPMTAG_BUGURL: -+ case RPMTAG_MODULARITYLABEL: - /* XXX TODO: validate format somehow */ - case RPMTAG_VCS: - SINGLE_TOKEN_ONLY; -@@ -1018,6 +1021,7 @@ static struct PreambleRec_s const preambleList[] = { - {RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")}, - {RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")}, - {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")}, -+ {RPMTAG_MODULARITYLABEL, 0, 0, LEN_AND_STR("modularitylabel")}, - {0, 0, 0, 0} - }; - -diff --git a/build/parseSpec.c b/build/parseSpec.c -index bf4789942..c80802baf 100644 ---- a/build/parseSpec.c -+++ b/build/parseSpec.c -@@ -517,6 +517,7 @@ static const rpmTagVal sourceTags[] = { - RPMTAG_BUGURL, - RPMTAG_HEADERI18NTABLE, - RPMTAG_VCS, -+ RPMTAG_MODULARITYLABEL, - 0 - }; - -diff --git a/lib/rpmtag.h b/lib/rpmtag.h -index 973a6b69d..b9623ef24 100644 ---- a/lib/rpmtag.h -+++ b/lib/rpmtag.h -@@ -368,6 +368,7 @@ - RPMTAG_FILESIGNATURELENGTH = 5091, /* i */ - RPMTAG_PAYLOADDIGEST = 5092, /* s[] */ - RPMTAG_PAYLOADDIGESTALGO = 5093, /* i */ -+ RPMTAG_MODULARITYLABEL = 5096, /* s */ - - RPMTAG_FIRSTFREE_TAG /*!< internal */ - } rpmTag; -diff --git a/macros.in b/macros.in -index e0a1aea4e..cb4929c10 100644 ---- a/macros.in -+++ b/macros.in -@@ -357,6 +357,11 @@ package or when debugging this package.\ - %_javadir %{_datadir}/java - %_javadocdir %{_datadir}/javadoc - -+ -+# Set ModularityLabel: for packages being build -+# -+#%modularitylabel -+ - # A colon separated list of paths where files should *not* be installed. - # Usually, these are network file system mount points. - # -diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at -index 509277f2c..45d38698b 100644 ---- a/tests/rpmgeneral.at -+++ b/tests/rpmgeneral.at -@@ -150,6 +150,7 @@ LONGARCHIVESIZE - LONGFILESIZES - LONGSIGSIZE - LONGSIZE -+MODULARITYLABEL - N - NAME - NEVR --- -2.17.2 - diff --git a/SOURCES/rpm-4.14.2-audit-3.patch b/SOURCES/rpm-4.14.2-audit-3.patch deleted file mode 100644 index 65a2b3f..0000000 --- a/SOURCES/rpm-4.14.2-audit-3.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 820dcc1db9f2130a21fdaf721217034376eb8e38 Mon Sep 17 00:00:00 2001 -Message-Id: <820dcc1db9f2130a21fdaf721217034376eb8e38.1544785848.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Fri, 30 Nov 2018 13:10:44 +0200 -Subject: [PATCH] Add support for logging audit events for package installs as - per OSPP v4.2 - -If enabled at build-time, log audit events for package install, update -and remove. The log includes the operation, package nevra, signature -check result, whether signatures are being enforced enforced and overall -success result. Package install/update/remove are logged as such, -obsoletion is logged as install + remove (whereas the erasure element -on updates is silent) - -Loosely based on initial RHEL 7-8 implementations by Pavlina Moravcova -Varekova and Florian Festi (RhBug:1555326, RhBug:1607612) - -(cherry picked from commit cfc9dde70fe65e91c83e03e9a9441e627b741489) ---- - configure.ac | 21 +++++++++ - lib/Makefile.am | 1 + - lib/rpmte.c | 11 +++++ - lib/rpmte_internal.h | 6 +++ - lib/transaction.c | 104 +++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 143 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 34ea85f9f..ab8a368d3 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -312,6 +312,27 @@ fi - AC_SUBST(WITH_BEECRYPT_LIB) - AC_SUBST(WITH_BEECRYPT_INCLUDE) - -+ -+#================= -+# Check for audit library. -+AC_ARG_WITH(audit, -+AS_HELP_STRING([--with-audit],[log results using Linux Audit]), -+with_audit=$withval, -+with_audit=auto) -+ -+WITH_AUDIT_LIB= -+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]) -+ ], -+ [if test "x$with_audit" != xauto; then -+ AC_MSG_ERROR([missing audit library]) -+ fi -+ ]) -+]) -+AC_SUBST(WITH_AUDIT_LIB) -+ - #================= - # Check for OpenSSL library. - # We need evp.h from OpenSSL. -diff --git a/lib/Makefile.am b/lib/Makefile.am -index baf3238ee..c055962a3 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -51,6 +51,7 @@ librpm_la_LIBADD = \ - @WITH_POPT_LIB@ \ - @WITH_CAP_LIB@ \ - @WITH_ACL_LIB@ \ -+ @WITH_AUDIT_LIB@ \ - @LIBINTL@ - - if WITH_LUA -diff --git a/lib/rpmte.c b/lib/rpmte.c -index d980a37a4..bd5d53edc 100644 ---- a/lib/rpmte.c -+++ b/lib/rpmte.c -@@ -69,6 +69,7 @@ struct rpmte_s { - int nrelocs; /*!< (TR_ADDED) No. of relocations. */ - uint8_t *badrelocs; /*!< (TR_ADDED) Bad relocations (or NULL) */ - FD_t fd; /*!< (TR_ADDED) Payload file descriptor. */ -+ int verified; /*!< (TR_ADDED) Verification status */ - - #define RPMTE_HAVE_PRETRANS (1 << 0) - #define RPMTE_HAVE_POSTTRANS (1 << 1) -@@ -753,6 +754,16 @@ rpmfs rpmteGetFileStates(rpmte te) - return te->fs; - } - -+void rpmteSetVerified(rpmte te, int verified) -+{ -+ te->verified = verified; -+} -+ -+int rpmteGetVerified(rpmte te) -+{ -+ return te->verified; -+} -+ - int rpmteProcess(rpmte te, pkgGoal goal, int num) - { - /* Only install/erase resets pkg file info */ -diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h -index a5a991ec5..2895925ce 100644 ---- a/lib/rpmte_internal.h -+++ b/lib/rpmte_internal.h -@@ -86,6 +86,12 @@ int rpmteHaveTransScript(rpmte te, rpmTagVal tag); - /* XXX should be internal too but build code needs for now... */ - rpmfs rpmteGetFileStates(rpmte te); - -+RPM_GNUC_INTERNAL -+void rpmteSetVerified(rpmte te, int verified); -+ -+RPM_GNUC_INTERNAL -+int rpmteGetVerified(rpmte te); -+ - /** \ingroup rpmte - * Retrieve size in bytes of package header. - * @param te transaction element -diff --git a/lib/transaction.c b/lib/transaction.c -index 67b9db579..866e87fc2 100644 ---- a/lib/transaction.c -+++ b/lib/transaction.c -@@ -7,6 +7,10 @@ - #include - #include - -+#if WITH_AUDIT -+#include -+#endif -+ - #include /* rpmMachineScore, rpmReadPackageFile */ - #include /* XXX for rpmExpand */ - #include -@@ -1195,12 +1199,17 @@ static rpm_loff_t countPkgs(rpmts ts, rpmElementTypes types) - - struct vfydata_s { - char *msg; -+ int signature; - int vfylevel; - }; - - static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata) - { - struct vfydata_s *vd = cbdata; -+ -+ if (sinfo->type == RPMSIG_SIGNATURE_TYPE && sinfo->rc == RPMRC_OK) -+ vd->signature = RPMRC_OK; -+ - switch (sinfo->rc) { - case RPMRC_OK: - break; -@@ -1241,6 +1250,7 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) - struct rpmvs_s *vs = rpmvsCreate(vfylevel, vsflags, keyring); - struct vfydata_s vd = { - .msg = NULL, -+ .signature = RPMRC_NOTFOUND, - .vfylevel = vfylevel, - }; - rpmRC prc = RPMRC_FAIL; -@@ -1255,6 +1265,9 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) - if (prc == RPMRC_OK) - prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); - -+ /* Record verify result, signatures only for now */ -+ rpmteSetVerified(p, vd.signature == RPMRC_OK); -+ - if (prc) - rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0); - -@@ -1619,6 +1632,95 @@ rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes, - return rc; - } - -+#if WITH_AUDIT -+struct teop { -+ rpmte te; -+ const char *op; -+}; -+ -+/* -+ * Figure out the actual operations: -+ * Install and remove are straightforward. Updates need to discovered -+ * via their erasure element: locate the updating element, adjust it's -+ * op to update and silence the erasure part. Obsoletion is handled as -+ * as install + remove, which it technically is. -+ */ -+static void getAuditOps(rpmts ts, struct teop *ops, int nelem) -+{ -+ rpmtsi pi = rpmtsiInit(ts); -+ rpmte p; -+ int i = 0; -+ while ((p = rpmtsiNext(pi, 0)) != NULL) { -+ const char *op = NULL; -+ if (rpmteType(p) == TR_ADDED) { -+ op = "install"; -+ } else { -+ op = "remove"; -+ rpmte d = rpmteDependsOn(p); -+ /* Fixup op on updating elements, silence the cleanup stage */ -+ if (d != NULL && rstreq(rpmteN(d), rpmteN(p))) { -+ /* Linear lookup, but we're only dealing with a few thousand */ -+ for (int x = 0; x < i; x++) { -+ if (ops[x].te == d) { -+ ops[x].op = "update"; -+ op = NULL; -+ break; -+ } -+ } -+ } -+ } -+ ops[i].te = p; -+ ops[i].op = op; -+ i++; -+ } -+ rpmtsiFree(pi); -+} -+ -+/* -+ * If enabled, log audit events for the operations in this transaction. -+ * In the event values, 1 means true/success and 0 false/failure. Shockingly. -+ */ -+static void rpmtsAudit(rpmts ts) -+{ -+ int auditFd = audit_open(); -+ if (auditFd < 0) -+ return; -+ -+ int nelem = rpmtsNElements(ts); -+ struct teop *ops = xcalloc(nelem, sizeof(*ops)); -+ char *dir = audit_encode_nv_string("root_dir", rpmtsRootDir(ts), 0); -+ int enforce = (rpmtsVfyLevel(ts) & RPMSIG_SIGNATURE_TYPE) != 0; -+ -+ getAuditOps(ts, ops, nelem); -+ -+ for (int i = 0; i < nelem; i++) { -+ const char *op = ops[i].op; -+ if (op) { -+ rpmte p = ops[i].te; -+ char *nevra = audit_encode_nv_string("sw", rpmteNEVRA(p), 0); -+ char eventTxt[256]; -+ int verified = rpmteGetVerified(p); -+ int result = (rpmteFailed(p) == 0); -+ -+ snprintf(eventTxt, sizeof(eventTxt), -+ "op=%s %s sw_type=rpm key_enforce=%u gpg_res=%u %s", -+ op, nevra, enforce, verified, dir); -+ audit_log_user_comm_message(auditFd, AUDIT_SOFTWARE_UPDATE, -+ eventTxt, NULL, NULL, NULL, NULL, result); -+ free(nevra); -+ } -+ } -+ -+ free(dir); -+ free(ops); -+ audit_close(auditFd); -+} -+#else -+static void rpmtsAudit(rpmts ts) -+{ -+} -+#endif -+ - int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) - { - int rc = -1; /* assume failure */ -@@ -1732,6 +1834,8 @@ exit: - rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc); - - /* Finish up... */ -+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) -+ rpmtsAudit(ts); - (void) umask(oldmask); - (void) rpmtsFinish(ts); - rpmpsFree(tsprobs); --- -2.19.2 - diff --git a/SOURCES/rpm-4.14.2-unversioned-python.patch b/SOURCES/rpm-4.14.2-unversioned-python.patch deleted file mode 100644 index 7e9ba8d..0000000 --- a/SOURCES/rpm-4.14.2-unversioned-python.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.14.2/macros.in.pyerror rpm-4.14.2/macros.in ---- rpm-4.14.2/macros.in.pyerror 2019-06-04 13:33:48.450727270 +0300 -+++ rpm-4.14.2/macros.in 2019-06-04 13:34:09.717695822 +0300 -@@ -50,7 +50,7 @@ - %__mv @__MV@ - %__patch @__PATCH@ - %__perl @__PERL@ --%__python @__PYTHON@ -+%__python %{error:attempt to use unversioned python, define %%__python to %{_bindir}/python2 or %{_bindir}/python3 explicitly} - %__restorecon @__RESTORECON@ - %__rm @__RM@ - %__rsh @__RSH@ diff --git a/SOURCES/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch b/SOURCES/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch deleted file mode 100644 index 05ca170..0000000 --- a/SOURCES/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -up rpm-4.14.3/scripts/brp-strip.orig rpm-4.14.3/scripts/brp-strip ---- rpm-4.14.3/scripts/brp-strip.orig 2021-02-09 14:43:35.393940550 +0100 -+++ rpm-4.14.3/scripts/brp-strip 2021-02-09 14:43:49.459222054 +0100 -@@ -12,9 +12,8 @@ Darwin*) exit 0 ;; - esac - - # Strip ELF binaries --for f in `find "$RPM_BUILD_ROOT" -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -exec file {} \; | \ -+for f in `find "$RPM_BUILD_ROOT" -type f -exec file {} \; | \ - grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ -- grep -v ' shared object,' | \ - sed -n -e 's/^\(.*\):[ ]*ELF.*, not stripped.*/\1/p'`; do - $STRIP -g "$f" || : - done diff --git a/SOURCES/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch b/SOURCES/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch deleted file mode 100644 index 8e4e835..0000000 --- a/SOURCES/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch +++ /dev/null @@ -1,186 +0,0 @@ -diff -up rpm-4.14.3/sign/rpmgensig.c.orig rpm-4.14.3/sign/rpmgensig.c ---- rpm-4.14.3/sign/rpmgensig.c.orig 2020-06-26 15:57:43.781333983 +0200 -+++ rpm-4.14.3/sign/rpmgensig.c 2020-06-26 15:58:29.819229616 +0200 -@@ -8,7 +8,6 @@ - #include - #include - #include --#include - - #include /* RPMSIGTAG & related */ - #include -@@ -33,68 +32,6 @@ typedef struct sigTarget_s { - rpm_loff_t size; - } *sigTarget; - --/* -- * There is no function for creating unique temporary fifos so create -- * unique temporary directory and then create fifo in it. -- */ --static char *mkTempFifo(void) --{ -- char *tmppath = NULL, *tmpdir = NULL, *fifofn = NULL; -- mode_t mode; -- -- tmppath = rpmExpand("%{_tmppath}", NULL); -- if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1)) -- goto exit; -- -- -- tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL); -- mode = umask(0077); -- tmpdir = mkdtemp(tmpdir); -- umask(mode); -- if (tmpdir == NULL) { -- rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n"), -- tmpdir); -- tmpdir = _free(tmpdir); -- goto exit; -- } -- -- fifofn = rpmGetPath(tmpdir, "/fifo", NULL); -- if (mkfifo(fifofn, 0600) == -1) { -- rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n"), fifofn); -- fifofn = _free(fifofn); -- } -- --exit: -- if (fifofn == NULL && tmpdir != NULL) -- unlink(tmpdir); -- -- free(tmppath); -- free(tmpdir); -- -- return fifofn; --} -- --/* Delete fifo and then temporary directory in which it was located */ --static int rpmRmTempFifo(const char *fn) --{ -- int rc = 0; -- char *dfn = NULL, *dir = NULL; -- -- if ((rc = unlink(fn)) != 0) { -- rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n"), fn); -- return rc; -- } -- -- dfn = xstrdup(fn); -- dir = dirname(dfn); -- -- if ((rc = rmdir(dir)) != 0) -- rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n"), dir); -- free(dfn); -- -- return rc; --} -- - static int closeFile(FD_t *fdp) - { - if (fdp == NULL || *fdp == NULL) -@@ -241,27 +178,38 @@ exit: - static int runGPG(sigTarget sigt, const char *sigfile) - { - int pid = 0, status; -- FD_t fnamedPipe = NULL; -- char *namedPipeName = NULL; -+ int pipefd[2]; -+ FILE *fpipe = NULL; - unsigned char buf[BUFSIZ]; - ssize_t count; - ssize_t wantCount; - rpm_loff_t size; - int rc = 1; /* assume failure */ - -- namedPipeName = mkTempFifo(); -+ if (pipe(pipefd) < 0) { -+ rpmlog(RPMLOG_ERR, _("Could not create pipe for signing: %m\n")); -+ goto exit; -+ } - -- rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1); -+ rpmPushMacro(NULL, "__plaintext_filename", NULL, "-", -1); - rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1); - - if (!(pid = fork())) { - char *const *av; - char *cmd = NULL; -- const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); -+ const char *tty = ttyname(STDIN_FILENO); -+ const char *gpg_path = NULL; -+ -+ if (!getenv("GPG_TTY") && (!tty || setenv("GPG_TTY", tty, 0))) -+ rpmlog(RPMLOG_WARNING, _("Could not set GPG_TTY to stdin: %m\n")); - -+ gpg_path = rpmExpand("%{?_gpg_path}", NULL); - if (gpg_path && *gpg_path != '\0') - (void) setenv("GNUPGHOME", gpg_path, 1); - -+ dup2(pipefd[0], STDIN_FILENO); -+ close(pipefd[1]); -+ - unsetenv("MALLOC_CHECK_"); - cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); - rc = poptParseArgvString(cmd, NULL, (const char ***)&av); -@@ -276,9 +224,10 @@ static int runGPG(sigTarget sigt, const - rpmPopMacro(NULL, "__plaintext_filename"); - rpmPopMacro(NULL, "__signature_filename"); - -- fnamedPipe = Fopen(namedPipeName, "w"); -- if (!fnamedPipe) { -- rpmlog(RPMLOG_ERR, _("Fopen failed\n")); -+ close(pipefd[0]); -+ fpipe = fdopen(pipefd[1], "w"); -+ if (!fpipe) { -+ rpmlog(RPMLOG_ERR, _("Could not open pipe for writing: %m\n")); - goto exit; - } - -@@ -291,8 +240,8 @@ static int runGPG(sigTarget sigt, const - size = sigt->size; - wantCount = size < sizeof(buf) ? size : sizeof(buf); - while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) { -- Fwrite(buf, sizeof(buf[0]), count, fnamedPipe); -- if (Ferror(fnamedPipe)) { -+ fwrite(buf, sizeof(buf[0]), count, fpipe); -+ if (ferror(fpipe)) { - rpmlog(RPMLOG_ERR, _("Could not write to pipe\n")); - goto exit; - } -@@ -304,8 +253,13 @@ static int runGPG(sigTarget sigt, const - sigt->fileName, Fstrerror(sigt->fd)); - goto exit; - } -- Fclose(fnamedPipe); -- fnamedPipe = NULL; -+ -+exit: -+ -+ if (fpipe) -+ fclose(fpipe); -+ if (pipefd[1]) -+ close(pipefd[1]); - - (void) waitpid(pid, &status, 0); - pid = 0; -@@ -314,20 +268,6 @@ static int runGPG(sigTarget sigt, const - } else { - rc = 0; - } -- --exit: -- -- if (fnamedPipe) -- Fclose(fnamedPipe); -- -- if (pid) -- waitpid(pid, &status, 0); -- -- if (namedPipeName) { -- rpmRmTempFifo(namedPipeName); -- free(namedPipeName); -- } -- - return rc; - } - diff --git a/SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch b/SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch deleted file mode 100644 index 3a9e808..0000000 --- a/SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch +++ /dev/null @@ -1,378 +0,0 @@ -From c33faabc2d09b9ad8c80b941b6114c1e4c2be80f Mon Sep 17 00:00:00 2001 -Message-Id: -From: Radovan Sroka -Date: Tue, 27 Oct 2020 16:18:04 +0100 -Subject: [PATCH] Added fapolicyd rpm plugin - -Fapolicyd (File Access Policy Daemon) implements application whitelisting -to decide file access rights. Applications that are known via a reputation -source are allowed access while unknown applications are not. - -The rpm plugin allows us to use rpm database as a source of trust. -We used dnf plugin since the beggining but it only provides notification -when transaction ends. With "integrity checking" requirement we need -a continual addition of files which are installed during the system -update. With fapolicyd rpm plugin we can allow using of recently -added/updated files in scriptlets during rpm transaction. - -The fapolicyd plugin gathers metadata of currently installed files. -It sends the information about files and about ongoing rpm transaction -to the fapolicyd daemon. The information is written to Linux pipe which -is placed in /var/run/fapolicyd/fapolicyd.fifo. - -The data format is "%s %lu %64s\n". [path, size, sha256] - -The fapolicyd rpm plugin can be enabled with "--with-fapolicyd" -configure option. - -Related PRs: -https://github.com/linux-application-whitelisting/fapolicyd/pull/105 -https://github.com/linux-application-whitelisting/fapolicyd/pull/106 - -Signed-off-by: Radovan Sroka -(cherry picked from commit 39595ccee321497dc3b08c7cab8a10304345429c) - -Backported from commit 39595ccee321497dc3b08c7cab8a10304345429c ---- - Makefile.am | 1 + - configure.ac | 8 ++ - doc/Makefile.am | 2 +- - doc/rpm-plugin-fapolicyd.8 | 21 +++++ - macros.in | 1 + - plugins/Makefile.am | 6 ++ - plugins/fapolicyd.c | 189 +++++++++++++++++++++++++++++++++++++ - 7 files changed, 227 insertions(+), 1 deletion(-) - create mode 100644 doc/rpm-plugin-fapolicyd.8 - create mode 100644 plugins/fapolicyd.c - -diff --git a/Makefile.am b/Makefile.am -index 1f20f05b7..8e92f0cde 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -16,6 +16,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ - --with-selinux \ - --with-imaevm \ - --with-crypto=openssl \ -+ --with-fapolicyd \ - --disable-dependency-tracking - - include $(top_srcdir)/rpm.am -diff --git a/configure.ac b/configure.ac -index 3fcb3ff20..3d0e9ef91 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -983,6 +983,14 @@ AS_IF([test "$enable_inhibit_plugin" = yes],[ - ]) - AM_CONDITIONAL(ENABLE_INHIBIT_PLUGIN,[test "$enable_inhibit_plugin" = yes]) - -+#================= -+# Check for fapolicyd support -+AC_ARG_WITH(fapolicyd, -+AS_HELP_STRING([--with-fapolicyd],[build with File Access Policy Daemon support]), -+with_fapolicyd=$withval, -+with_fapolicyd=auto) -+AM_CONDITIONAL(FAPOLICYD,[test "$with_fapolicyd" = yes]) -+ - with_dbus=no - AS_IF([test "$enable_plugins" != no],[ - AS_IF([test "$enable_inhibit_plugin" != no],[ -diff --git a/doc/Makefile.am b/doc/Makefile.am -index d2f520d64..535ad3ec3 100644 ---- a/doc/Makefile.am -+++ b/doc/Makefile.am -@@ -9,7 +9,7 @@ EXTRA_DIST += $(man_man1_DATA) - man_man8dir = $(mandir)/man8 - man_man8_DATA = rpm.8 rpm-misc.8 rpmbuild.8 rpmdeps.8 rpmgraph.8 rpm2cpio.8 - man_man8_DATA += rpmdb.8 rpmkeys.8 rpmsign.8 rpmspec.8 --man_man8_DATA += rpm-plugin-systemd-inhibit.8 -+man_man8_DATA += rpm-plugin-systemd-inhibit.8 rpm-plugin-fapolicyd.8 - EXTRA_DIST += $(man_man8_DATA) - - man_fr_man8dir = $(mandir)/fr/man8 -diff --git a/doc/rpm-plugin-fapolicyd.8 b/doc/rpm-plugin-fapolicyd.8 -new file mode 100644 -index 000000000..fe7a8c78e ---- /dev/null -+++ b/doc/rpm-plugin-fapolicyd.8 -@@ -0,0 +1,21 @@ -+'\" t -+.TH "RPM-FAPOLICYD" "8" "28 Jan 2021" "Red Hat, Inc." -+.SH NAME -+rpm-plugin-fapolicyd \- Fapolicyd plugin for the RPM Package Manager -+ -+.SH Description -+ -+The plugin gathers metadata of currently installed files. It sends the -+information about files and about ongoing rpm transaction to the fapolicyd daemon. -+The information is written to Linux pipe which is placed in -+/var/run/fapolicyd/fapolicyd.fifo. -+ -+.SH Configuration -+ -+There are currently no options for this plugin in particular. See -+.BR rpm-plugins (8) -+on how to control plugins in general. -+ -+.SH SEE ALSO -+.IR fapolicyd (8) -+.IR rpm-plugins (8) -diff --git a/macros.in b/macros.in -index a6069ee4d..2fbda64cc 100644 ---- a/macros.in -+++ b/macros.in -@@ -1173,6 +1173,7 @@ package or when debugging this package.\ - %__transaction_selinux %{__plugindir}/selinux.so - %__transaction_syslog %{__plugindir}/syslog.so - %__transaction_ima %{__plugindir}/ima.so -+%__transaction_fapolicyd %{__plugindir}/fapolicyd.so - %__transaction_prioreset %{__plugindir}/prioreset.so - - #------------------------------------------------------------------------------ -diff --git a/plugins/Makefile.am b/plugins/Makefile.am -index ab4eee34f..cbfb81e19 100644 ---- a/plugins/Makefile.am -+++ b/plugins/Makefile.am -@@ -42,3 +42,9 @@ ima_la_sources = ima.c - ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la - plugins_LTLIBRARIES += ima.la - endif -+ -+if FAPOLICYD -+fapolicyd_la_sources = fapolicyd.c -+fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la -+plugins_LTLIBRARIES += fapolicyd.la -+endif -diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c -new file mode 100644 -index 000000000..50f50155c ---- /dev/null -+++ b/plugins/fapolicyd.c -@@ -0,0 +1,189 @@ -+#include "system.h" -+ -+#include -+#include -+#include "lib/rpmplugin.h" -+ -+#include -+#include -+#include -+#include -+ -+struct fapolicyd_data { -+ int fd; -+ long changed_files; -+ const char * fifo_path; -+}; -+ -+static struct fapolicyd_data fapolicyd_state = { -+ .fd = -1, -+ .changed_files = 0, -+ .fifo_path = "/run/fapolicyd/fapolicyd.fifo", -+}; -+ -+static rpmRC open_fifo(struct fapolicyd_data* state) -+{ -+ int fd = -1; -+ struct stat s; -+ -+ fd = open(state->fifo_path, O_RDWR); -+ if (fd == -1) { -+ rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno)); -+ goto bad; -+ } -+ -+ if (stat(state->fifo_path, &s) == -1) { -+ rpmlog(RPMLOG_DEBUG, "Stat: %s -> %s\n", state->fifo_path, strerror(errno)); -+ goto bad; -+ } -+ -+ if (!S_ISFIFO(s.st_mode)) { -+ rpmlog(RPMLOG_DEBUG, "File: %s exists but it is not a pipe!\n", state->fifo_path); -+ goto bad; -+ } -+ -+ /* keep only file's permition bits */ -+ mode_t mode = s.st_mode & ~S_IFMT; -+ -+ /* we require pipe to have 0660 permission */ -+ if (mode != 0660) { -+ rpmlog(RPMLOG_ERR, "File: %s has %o instead of 0660 \n", -+ state->fifo_path, -+ mode ); -+ goto bad; -+ } -+ -+ state->fd = fd; -+ /* considering success */ -+ return RPMRC_OK; -+ -+ bad: -+ if (fd > 0) -+ close(fd); -+ return RPMRC_FAIL; -+} -+ -+static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) -+{ -+ ssize_t len = strlen(str); -+ ssize_t written = 0; -+ ssize_t n = 0; -+ -+ while (written < len) { -+ if ((n = write(state->fd, str + written, len - written)) < 0) { -+ if (errno == EINTR || errno == EAGAIN) -+ continue; -+ rpmlog(RPMLOG_DEBUG, "Write: %s -> %s\n", state->fifo_path, strerror(errno)); -+ goto bad; -+ } -+ written += n; -+ } -+ -+ return RPMRC_OK; -+ -+ bad: -+ return RPMRC_FAIL; -+} -+ -+static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) -+{ -+ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) -+ goto end; -+ -+ if (!rstreq(rpmtsRootDir(ts), "/")) -+ goto end; -+ -+ (void) open_fifo(&fapolicyd_state); -+ -+ end: -+ return RPMRC_OK; -+} -+ -+static void fapolicyd_cleanup(rpmPlugin plugin) -+{ -+ if (fapolicyd_state.fd > 0) -+ (void) close(fapolicyd_state.fd); -+ -+ fapolicyd_state.fd = -1; -+} -+ -+static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) -+{ -+ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) -+ goto end; -+ -+ /* we are ready */ -+ if (fapolicyd_state.fd > 0) { -+ /* send a signal that transaction is over */ -+ (void) write_fifo(&fapolicyd_state, "1\n"); -+ /* flush cache */ -+ (void) write_fifo(&fapolicyd_state, "2\n"); -+ } -+ -+ end: -+ return RPMRC_OK; -+} -+ -+static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name, -+ int type) -+{ -+ if (fapolicyd_state.fd == -1) -+ goto end; -+ -+ if (fapolicyd_state.changed_files > 0) { -+ /* send signal to flush cache */ -+ (void) write_fifo(&fapolicyd_state, "2\n"); -+ -+ /* optimize flushing */ -+ /* flush only when there was an actual change */ -+ fapolicyd_state.changed_files = 0; -+ } -+ -+ end: -+ return RPMRC_OK; -+} -+ -+static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, -+ const char *path, const char *dest, -+ mode_t file_mode, rpmFsmOp op) -+{ -+ /* not ready */ -+ if (fapolicyd_state.fd == -1) -+ goto end; -+ -+ rpmFileAction action = XFO_ACTION(op); -+ -+ /* Ignore skipped files and unowned directories */ -+ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) { -+ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping early: path %s dest %s\n", -+ path, dest); -+ goto end; -+ } -+ -+ if (!S_ISREG(rpmfiFMode(fi))) { -+ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping non regular: path %s dest %s\n", -+ path, dest); -+ goto end; -+ } -+ -+ fapolicyd_state.changed_files++; -+ -+ char buffer[4096]; -+ -+ rpm_loff_t size = rpmfiFSize(fi); -+ char * sha = rpmfiFDigestHex(fi, NULL); -+ -+ snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); -+ (void) write_fifo(&fapolicyd_state, buffer); -+ -+ end: -+ return RPMRC_OK; -+} -+ -+struct rpmPluginHooks_s fapolicyd_hooks = { -+ .init = fapolicyd_init, -+ .cleanup = fapolicyd_cleanup, -+ .scriptlet_pre = fapolicyd_scriptlet_pre, -+ .tsm_post = fapolicyd_tsm_post, -+ .fsm_file_prepare = fapolicyd_fsm_file_prepare, -+}; --- -2.29.2 - -commit c66cee32e74ce1e507c031605e3d7b2c1391a52c -Author: Radovan Sroka -Date: Wed Feb 10 17:04:55 2021 +0100 - - Fixed issues find by coverity - - - enhance the check for the file descriptor fd because 0 is also a valid - descriptor - - - added free() for sha so it doesn't leak memory for every file that is - processed - - Signed-off-by: Radovan Sroka - -diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c -index 50f50155c..48f65ae11 100644 ---- a/plugins/fapolicyd.c -+++ b/plugins/fapolicyd.c -@@ -58,7 +58,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state) - return RPMRC_OK; - - bad: -- if (fd > 0) -+ if (fd >= 0) - close(fd); - return RPMRC_FAIL; - } -@@ -176,6 +176,8 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, - snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); - (void) write_fifo(&fapolicyd_state, buffer); - -+ free(sha); -+ - end: - return RPMRC_OK; - } diff --git a/SOURCES/rpm-4.14.3-add-path-query-option.patch b/SOURCES/rpm-4.14.3-add-path-query-option.patch deleted file mode 100644 index 0504ec8..0000000 --- a/SOURCES/rpm-4.14.3-add-path-query-option.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 013cd4ba63c35fa75feeccde0022d56e68bc5845 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Mon, 16 Aug 2021 18:21:02 +0200 -Subject: [PATCH] Add support for RPMDBI_BASENAMES on file queries - -There are legitimate reasons (such as rhbz#1940895 or the included test) -for wanting the former behavior where all file states were considered in -file queries prior to commit 9ad57bda4a82b9847826daa766b4421d877bb3d9, -so celebrate the tenth anniversary of that commit by adding a CLI switch -(a new package selector --path), as contemplated back then. - -Update the man page for --file to reflect it's current behavior and make ---path that more obvious. - -Resolves: rhbz#1940895 - -Combined with: -d1aebda01033bc8ba0d748b49f6fad9a5c0caa3f -f62b6d27cd741406a52a7e9c5b1d6f581dbd3af8 - -Backported for 4.14.3. ---- - doc/rpm.8 | 9 ++++++-- - lib/poptQV.c | 6 +++++- - lib/query.c | 7 +++++-- - lib/rpmcli.h | 1 + - tests/rpmquery.at | 52 +++++++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 70 insertions(+), 5 deletions(-) - -diff --git a/doc/rpm.8 b/doc/rpm.8 -index 15a3db25f..74604c8ec 100644 ---- a/doc/rpm.8 -+++ b/doc/rpm.8 -@@ -57,7 +57,7 @@ rpm \- RPM Package Manager - .PP - - [\fB\fIPACKAGE_NAME\fB\fR] -- [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR] -+ [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR] [\fB--path \fIPATH\fB\fR] - [\fB-g,--group \fIGROUP\fB\fR] {\fB-p,--package \fIPACKAGE_FILE\fB\fR] - [\fB--hdrid \fISHA1\fB\fR] [\fB--pkgid \fIMD5\fB\fR] [\fB--tid \fITID\fB\fR] - [\fB--querybynumber \fIHDRNUM\fB\fR] [\fB--triggeredby \fIPACKAGE_NAME\fB\fR] -@@ -555,7 +555,7 @@ starts with "b". - List duplicated packages. - .TP - \fB-f, --file \fIFILE\fB\fR --Query package owning \fIFILE\fR. -+Query package owning installed \fIFILE\fR. - .TP - \fB--filecaps\fR - List file names with POSIX1.e capabilities. -@@ -598,6 +598,11 @@ that will be expanded to paths that are substituted in place of - the package manifest as additional \fIPACKAGE_FILE\fR - arguments to the query. - .TP -+\fB--path \fIPATH\fB\fR -+Query package(s) owning \fIPATH\fR, whether the file is installed or not. -+Multiple packages may own a \fIPATH\fR, but the file is only owned by the -+package installed last. -+.TP - \fB--pkgid \fIMD5\fB\fR - Query package that contains a given package identifier, i.e. the - \fIMD5\fR digest of the combined header and -diff --git a/lib/poptQV.c b/lib/poptQV.c -index 9021d7b3c..f752d8b82 100644 ---- a/lib/poptQV.c -+++ b/lib/poptQV.c -@@ -27,6 +27,7 @@ struct rpmQVKArguments_s rpmQVKArgs; - #define POPT_WHATENHANCES -1014 - #define POPT_WHATOBSOLETES -1015 - #define POPT_WHATCONFLICTS -1016 -+#define POPT_QUERYBYPATH -1017 - - /* ========== Query/Verify/Signature source args */ - static void rpmQVSourceArgCallback( poptContext con, -@@ -58,6 +59,7 @@ static void rpmQVSourceArgCallback( poptContext con, - case POPT_WHATSUPPLEMENTS: qva->qva_source |= RPMQV_WHATSUPPLEMENTS; break; - case POPT_WHATENHANCES: qva->qva_source |= RPMQV_WHATENHANCES; break; - case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY; break; -+ case POPT_QUERYBYPATH: qva->qva_source |= RPMQV_PATH_ALL; break; - case POPT_QUERYBYPKGID: qva->qva_source |= RPMQV_PKGID; break; - case POPT_QUERYBYHDRID: qva->qva_source |= RPMQV_HDRID; break; - case POPT_QUERYBYTID: qva->qva_source |= RPMQV_TID; break; -@@ -80,7 +82,9 @@ struct poptOption rpmQVSourcePoptTable[] = { - { "checksig", 'K', POPT_ARGFLAG_DOC_HIDDEN, NULL, 'K', - N_("rpm checksig mode"), NULL }, - { "file", 'f', 0, 0, 'f', -- N_("query/verify package(s) owning file"), "FILE" }, -+ N_("query/verify package(s) owning installed file"), "FILE" }, -+ { "path", '\0', 0, 0, POPT_QUERYBYPATH, -+ N_("query/verify package(s) owning path, installed or not"), "PATH" }, - { "group", 'g', 0, 0, 'g', - N_("query/verify package(s) in group"), "GROUP" }, - { "package", 'p', 0, 0, 'p', -diff --git a/lib/query.c b/lib/query.c -index 26cdecf10..e6ea1fa2d 100644 ---- a/lib/query.c -+++ b/lib/query.c -@@ -440,6 +440,7 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar - } - /* fallthrough on absolute and relative paths */ - case RPMQV_PATH: -+ case RPMQV_PATH_ALL: - { char * fn; - - for (s = arg; *s != '\0'; s++) -@@ -458,8 +459,10 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar - fn = xstrdup(arg); - (void) rpmCleanPath(fn); - -- /* XXX Add a switch to enable former BASENAMES behavior? */ -- mi = rpmtsInitIterator(ts, RPMDBI_INSTFILENAMES, fn, 0); -+ rpmDbiTagVal tag = RPMDBI_INSTFILENAMES; -+ if (qva->qva_source == RPMQV_PATH_ALL) -+ tag = RPMDBI_BASENAMES; -+ mi = rpmtsInitIterator(ts, tag, fn, 0); - if (mi == NULL) - mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0); - -diff --git a/lib/rpmcli.h b/lib/rpmcli.h -index 99af2585a..c0d07d137 100644 ---- a/lib/rpmcli.h -+++ b/lib/rpmcli.h -@@ -102,6 +102,7 @@ enum rpmQVSources_e { - RPMQV_SPECBUILTRPMS, /*!< ... from pkgs which would be built from spec */ - RPMQV_WHATOBSOLETES, /*!< ... from obsoletes db search. */ - RPMQV_WHATCONFLICTS, /*!< ... from conflicts db search. */ -+ RPMQV_PATH_ALL, /*!< ... from file path db search (all states). */ - }; - - typedef rpmFlags rpmQVSources; -diff --git a/tests/rpmquery.at b/tests/rpmquery.at -index 36c62339a..ad580f664 100644 ---- a/tests/rpmquery.at -+++ b/tests/rpmquery.at -@@ -194,6 +194,58 @@ runroot rpm \ - - AT_CLEANUP - -+# ------------------------------ -+# query a package by a file -+AT_SETUP([rpm -qf]) -+AT_KEYWORDS([query]) -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm \ -+ --nodeps \ -+ -i /data/RPMS/hello-1.0-1.i386.rpm -+runroot rpm \ -+ -qf /usr/local/bin/hello -+], -+[0], -+[hello-1.0-1.i386 -+], -+[]) -+AT_CLEANUP -+ -+AT_SETUP([rpm -qf on non-installed file]) -+AT_KEYWORDS([query]) -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm \ -+ --nodeps \ -+ --excludedocs \ -+ -i /data/RPMS/hello-1.0-1.i386.rpm -+runroot rpm \ -+ -qf /usr/share/doc/hello-1.0/FAQ -+], -+[1], -+[], -+[error: file /usr/share/doc/hello-1.0/FAQ: No such file or directory -+]) -+AT_CLEANUP -+ -+AT_SETUP([rpm -q --path on non-installed file]) -+AT_KEYWORDS([query]) -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm \ -+ --nodeps \ -+ --excludedocs \ -+ -i /data/RPMS/hello-1.0-1.i386.rpm -+runroot rpm \ -+ -q --path /usr/share/doc/hello-1.0/FAQ -+], -+[0], -+[hello-1.0-1.i386 -+], -+[]) -+AT_CLEANUP -+ - # ------------------------------ - AT_SETUP([integer array query]) - AT_KEYWORDS([query]) --- -2.35.1 - diff --git a/SOURCES/rpm-4.14.3-add-read-only-support-for-sqlite.patch b/SOURCES/rpm-4.14.3-add-read-only-support-for-sqlite.patch deleted file mode 100644 index 419d754..0000000 --- a/SOURCES/rpm-4.14.3-add-read-only-support-for-sqlite.patch +++ /dev/null @@ -1,798 +0,0 @@ -From 34790c335fe6e5e1099c9320d7b3134398104120 Mon Sep 17 00:00:00 2001 -Message-Id: <34790c335fe6e5e1099c9320d7b3134398104120.1624429665.git.pmatilai@redhat.com> -From: Panu Matilainen -Date: Wed, 23 Jun 2021 08:24:44 +0300 -Subject: [PATCH] Add read-only support for sqlite - -Based on latest upstream sqlite backend version, chainsaw write support -out and adjust for the infra differences (which there are more than a -few) and add an error message instead. ---- - configure.ac | 23 ++ - lib/Makefile.am | 6 + - lib/backend/dbi.c | 14 + - lib/backend/dbi.h | 5 + - lib/backend/sqlite.c | 659 +++++++++++++++++++++++++++++++++++++++++++ - macros.in | 1 + - 6 files changed, 708 insertions(+) - create mode 100644 lib/backend/sqlite.c - -diff --git a/configure.ac b/configure.ac -index 3fcb3ff20..e04aced68 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -589,6 +589,29 @@ AS_IF([test "$enable_ndb" = yes],[ - ]) - AM_CONDITIONAL([NDB], [test "$enable_ndb" = yes]) - -+# Check for SQLITE support -+AC_ARG_ENABLE([sqlite], -+ [AS_HELP_STRING([--enable-sqlite=@<:@yes/no/auto@:>@)], -+ [build with sqlite rpm database format support (default=yes)])], -+ [enable_sqlite="$enableval"], -+ [enable_sqlite=yes]) -+ -+AS_IF([test "x$enable_sqlite" != "xno"], [ -+ PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.22.0], [have_sqlite=yes], [have_sqlite=no]) -+ AS_IF([test "$enable_sqlite" = "yes"], [ -+ if test "$have_sqlite" = "no"; then -+ AC_MSG_ERROR([--enable-sqlite specified, but not available]) -+ fi -+ ]) -+]) -+ -+if test "x$have_sqlite" = "xyes"; then -+ AC_DEFINE([WITH_SQLITE], [1], [Define if SQLITE is available]) -+ SQLITE_REQUIRES=sqlite -+ AC_SUBST(SQLITE_REQUIRES) -+fi -+AM_CONDITIONAL([SQLITE], [test "x$have_sqlite" = "xyes"]) -+ - #================= - # Check for LMDB support - AC_ARG_ENABLE([lmdb], -diff --git a/lib/Makefile.am b/lib/Makefile.am -index baf3238ee..8a9fe77bd 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -76,6 +76,12 @@ librpm_la_SOURCES += \ - backend/ndb/rpmxdb.h - endif - -+if SQLITE -+AM_CPPFLAGS += $(SQLITE_CFLAGS) -+librpm_la_LIBADD += $(SQLITE_LIBS) -+librpm_la_SOURCES += backend/sqlite.c -+endif -+ - if LMDB - AM_CPPFLAGS += $(LMDB_CFLAGS) - librpm_la_LIBADD += $(LMDB_LIBS) -diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c -index e99a5f2b2..dc3587f58 100644 ---- a/lib/backend/dbi.c -+++ b/lib/backend/dbi.c -@@ -48,6 +48,11 @@ dbDetectBackend(rpmdb rdb) - if (!strcmp(db_backend, "ndb")) { - rdb->db_ops = &ndb_dbops; - } else -+#endif -+#ifdef WITH_SQLITE -+ if (!strcmp(db_backend, "sqlite")) { -+ rdb->db_ops = &sqlite_dbops; -+ } else - #endif - { - rdb->db_ops = &db3_dbops; -@@ -75,6 +80,15 @@ dbDetectBackend(rpmdb rdb) - free(path); - #endif - -+#ifdef WITH_SQLITE -+ path = rstrscat(NULL, dbhome, "/rpmdb.sqlite", NULL); -+ if (access(path, F_OK) == 0 && rdb->db_ops != &sqlite_dbops) { -+ rdb->db_ops = &sqlite_dbops; -+ rpmlog(RPMLOG_WARNING, _("Found SQLITE rpmdb.sqlite database while attempting %s backend: using sqlite backend.\n"), db_backend); -+ } -+ free(path); -+#endif -+ - path = rstrscat(NULL, dbhome, "/Packages", NULL); - if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) { - rdb->db_ops = &db3_dbops; -diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h -index 02f49c8fd..ff2b4f974 100644 ---- a/lib/backend/dbi.h -+++ b/lib/backend/dbi.h -@@ -275,6 +275,11 @@ RPM_GNUC_INTERNAL - extern struct rpmdbOps_s lmdb_dbops; - #endif - -+#if defined(WITH_SQLITE) -+RPM_GNUC_INTERNAL -+extern struct rpmdbOps_s sqlite_dbops; -+#endif -+ - #ifdef __cplusplus - } - #endif -diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c -new file mode 100644 -index 000000000..3caeba5f0 ---- /dev/null -+++ b/lib/backend/sqlite.c -@@ -0,0 +1,659 @@ -+#include "system.h" -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include "lib/rpmdb_internal.h" -+ -+#include "debug.h" -+ -+static const int sleep_ms = 50; -+ -+struct dbiCursor_s { -+ sqlite3 *sdb; -+ sqlite3_stmt *stmt; -+ const char *fmt; -+ int flags; -+ rpmTagVal tag; -+ int ctype; -+ struct dbiCursor_s *subc; -+ -+ const void *key; -+ unsigned int keylen; -+}; -+ -+static int sqlexec(sqlite3 *sdb, const char *fmt, ...); -+ -+static void rpm_match3(sqlite3_context *sctx, int argc, sqlite3_value **argv) -+{ -+ int match = 0; -+ if (argc == 3) { -+ int b1len = sqlite3_value_bytes(argv[0]); -+ int b2len = sqlite3_value_bytes(argv[1]); -+ int n = sqlite3_value_int(argv[2]); -+ if (b1len >= n && b2len >= n) { -+ const char *b1 = sqlite3_value_blob(argv[0]); -+ const char *b2 = sqlite3_value_blob(argv[1]); -+ match = (memcmp(b1, b2, n) == 0); -+ } -+ } -+ sqlite3_result_int(sctx, match); -+} -+ -+static void errCb(void *data, int err, const char *msg) -+{ -+ rpmdb rdb = data; -+ rpmlog(RPMLOG_WARNING, "%s: %s: %s\n", -+ rdb->db_descr, sqlite3_errstr(err), msg); -+} -+ -+static int dbiCursorReset(dbiCursor dbc) -+{ -+ if (dbc->stmt) { -+ sqlite3_reset(dbc->stmt); -+ sqlite3_clear_bindings(dbc->stmt); -+ } -+ return 0; -+} -+ -+static int dbiCursorResult(dbiCursor dbc) -+{ -+ int rc = sqlite3_errcode(dbc->sdb); -+ int err = (rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW); -+ if (err) { -+ rpmlog(RPMLOG_ERR, "%s: %d: %s\n", sqlite3_sql(dbc->stmt), -+ sqlite3_errcode(dbc->sdb), sqlite3_errmsg(dbc->sdb)); -+ } -+ return err ? RPMRC_FAIL : RPMRC_OK; -+} -+ -+static int dbiCursorPrep(dbiCursor dbc, const char *fmt, ...) -+{ -+ if (dbc->stmt == NULL) { -+ char *cmd = NULL; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ cmd = sqlite3_vmprintf(fmt, ap); -+ va_end(ap); -+ -+ sqlite3_prepare_v2(dbc->sdb, cmd, -1, &dbc->stmt, NULL); -+ sqlite3_free(cmd); -+ } else { -+ dbiCursorReset(dbc); -+ } -+ -+ return dbiCursorResult(dbc); -+} -+ -+static int dbiCursorBindPkg(dbiCursor dbc, unsigned int hnum, -+ void *blob, unsigned int bloblen) -+{ -+ int rc = 0; -+ -+ if (hnum) -+ rc = sqlite3_bind_int(dbc->stmt, 1, hnum); -+ else -+ rc = sqlite3_bind_null(dbc->stmt, 1); -+ -+ if (blob) { -+ if (!rc) -+ rc = sqlite3_bind_blob(dbc->stmt, 2, blob, bloblen, NULL); -+ } -+ return dbiCursorResult(dbc); -+} -+ -+static int dbiCursorBindIdx(dbiCursor dbc, const void *key, int keylen, -+ dbiIndexItem rec) -+{ -+ int rc; -+ if (dbc->ctype == SQLITE_TEXT) { -+ rc = sqlite3_bind_text(dbc->stmt, 1, key, keylen, NULL); -+ } else { -+ rc = sqlite3_bind_blob(dbc->stmt, 1, key, keylen, NULL); -+ } -+ -+ if (rec) { -+ if (!rc) -+ rc = sqlite3_bind_int(dbc->stmt, 2, rec->hdrNum); -+ if (!rc) -+ rc = sqlite3_bind_int(dbc->stmt, 3, rec->tagNum); -+ } -+ -+ return dbiCursorResult(dbc); -+} -+ -+static int sqlite_init(rpmdb rdb, const char * dbhome) -+{ -+ int rc = 0; -+ char *dbfile = NULL; -+ -+ if (rdb->db_dbenv == NULL) { -+ dbfile = rpmGenPath(dbhome, "rpmdb.sqlite", NULL); -+ sqlite3 *sdb = NULL; -+ int xx, flags = 0; -+ int retry_open = 1; -+ -+ free(rdb->db_descr); -+ rdb->db_descr = xstrdup("sqlite"); -+ -+ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY) -+ flags |= SQLITE_OPEN_READONLY; -+ else { -+ rpmlog(RPMLOG_ERR, -+ _("unable to open sqlite database %s for writing, sqlite support is read-only\n"), dbfile); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+ while (retry_open--) { -+ xx = sqlite3_open_v2(dbfile, &sdb, flags, NULL); -+ /* Attempt to create if missing, discarding OPEN_READONLY (!) */ -+ if (xx == SQLITE_CANTOPEN && (flags & SQLITE_OPEN_READONLY)) { -+ /* Sqlite allocates resources even on failure to open (!) */ -+ sqlite3_close(sdb); -+ flags &= ~SQLITE_OPEN_READONLY; -+ flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); -+ retry_open++; -+ } -+ } -+ -+ if (xx != SQLITE_OK) { -+ rpmlog(RPMLOG_ERR, _("Unable to open sqlite database %s: %s\n"), -+ dbfile, sqlite3_errstr(xx)); -+ rc = 1; -+ goto exit; -+ } -+ -+ sqlite3_create_function(sdb, "match", 3, -+ (SQLITE_UTF8|SQLITE_DETERMINISTIC), -+ NULL, rpm_match3, NULL, NULL); -+ -+ sqlite3_busy_timeout(sdb, sleep_ms); -+ sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb); -+ -+ sqlexec(sdb, "PRAGMA secure_delete = OFF"); -+ sqlexec(sdb, "PRAGMA case_sensitive_like = ON"); -+ -+ if (sqlite3_db_readonly(sdb, NULL) == 0) { -+ if (sqlexec(sdb, "PRAGMA journal_mode = WAL") == 0) { -+ int one = 1; -+ /* Annoying but necessary to support non-privileged readers */ -+ sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL, &one); -+ -+ if (!rpmExpandNumeric("%{?_flush_io}")) -+ sqlexec(sdb, "PRAGMA wal_autocheckpoint = 0"); -+ } -+ } -+ -+ rdb->db_dbenv = sdb; -+ } -+ rdb->db_opens++; -+ -+exit: -+ free(dbfile); -+ return rc; -+} -+ -+static int sqlite_fini(rpmdb rdb) -+{ -+ int rc = 0; -+ if (rdb) { -+ sqlite3 *sdb = rdb->db_dbenv; -+ if (rdb->db_opens > 1) { -+ rdb->db_opens--; -+ } else { -+ if (sqlite3_db_readonly(sdb, NULL) == 0) { -+ sqlexec(sdb, "PRAGMA optimize"); -+ sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE"); -+ } -+ rdb->db_dbenv = NULL; -+ int xx = sqlite3_close(sdb); -+ rc = (xx != SQLITE_OK); -+ } -+ } -+ -+ return rc; -+} -+ -+static int sqlexec(sqlite3 *sdb, const char *fmt, ...) -+{ -+ int rc = 0; -+ char *cmd = NULL; -+ char *err = NULL; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ cmd = sqlite3_vmprintf(fmt, ap); -+ va_end(ap); -+ -+ /* sqlite3_exec() doesn't seeem to honor sqlite3_busy_timeout() */ -+ while ((rc = sqlite3_exec(sdb, cmd, NULL, NULL, &err)) == SQLITE_BUSY) { -+ usleep(sleep_ms); -+ } -+ -+ if (rc) -+ rpmlog(RPMLOG_ERR, "sqlite failure: %s: %s\n", cmd, err); -+ else -+ rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc); -+ -+ sqlite3_free(cmd); -+ -+ return rc ? RPMRC_FAIL : RPMRC_OK; -+} -+ -+static int dbiExists(dbiIndex dbi) -+{ -+ const char *col = (dbi->dbi_type == DBI_PRIMARY) ? "hnum" : "key"; -+ const char *tbl = dbi->dbi_file; -+ int rc = sqlite3_table_column_metadata(dbi->dbi_db, NULL, tbl, col, -+ NULL, NULL, NULL, NULL, NULL); -+ return (rc == 0); -+} -+ -+static int init_table(dbiIndex dbi, rpmTagVal tag) -+{ -+ int rc = 0; -+ -+ if (dbiExists(dbi)) -+ return 0; -+ -+ if (dbi->dbi_type == DBI_PRIMARY) { -+ rc = sqlexec(dbi->dbi_db, -+ "CREATE TABLE IF NOT EXISTS '%q' (" -+ "hnum INTEGER PRIMARY KEY AUTOINCREMENT," -+ "blob BLOB NOT NULL" -+ ")", -+ dbi->dbi_file); -+ } else { -+ const char *keytype = (rpmTagGetClass(tag) == RPM_STRING_CLASS) ? -+ "TEXT" : "BLOB"; -+ rc = sqlexec(dbi->dbi_db, -+ "CREATE TABLE IF NOT EXISTS '%q' (" -+ "key '%q' NOT NULL, " -+ "hnum INTEGER NOT NULL, " -+ "idx INTEGER NOT NULL, " -+ "FOREIGN KEY (hnum) REFERENCES 'Packages'(hnum)" -+ ")", -+ dbi->dbi_file, keytype); -+ } -+ if (!rc) -+ dbi->dbi_flags |= DBI_CREATED; -+ -+ return rc; -+} -+ -+static int create_index(sqlite3 *sdb, const char *table, const char *col) -+{ -+ return sqlexec(sdb, -+ "CREATE INDEX IF NOT EXISTS '%s_%s_idx' ON '%q'(%s ASC)", -+ table, col, table, col); -+} -+ -+static int init_index(dbiIndex dbi, rpmTagVal tag) -+{ -+ int rc = 0; -+ -+ /* Can't create on readonly database, but things will still work */ -+ if (sqlite3_db_readonly(dbi->dbi_db, NULL) == 1) -+ return 0; -+ -+ if (dbi->dbi_type == DBI_SECONDARY) { -+ int string = (rpmTagGetClass(tag) == RPM_STRING_CLASS); -+ int array = (rpmTagGetReturnType(tag) == RPM_ARRAY_RETURN_TYPE); -+ if (!rc && string) -+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "key"); -+ if (!rc && array) -+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "hnum"); -+ } -+ return rc; -+} -+ -+static int sqlite_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) -+{ -+ int rc = sqlite_init(rdb, rpmdbHome(rdb)); -+ -+ if (!rc) { -+ dbiIndex dbi = dbiNew(rdb, rpmtag); -+ dbi->dbi_db = rdb->db_dbenv; -+ -+ rc = init_table(dbi, rpmtag); -+ -+ if (!rc && !(rdb->db_flags & RPMDB_FLAG_REBUILD)) -+ rc = init_index(dbi, rpmtag); -+ -+ if (!rc && dbip) -+ *dbip = dbi; -+ else -+ dbiFree(dbi); -+ } -+ -+ return rc; -+} -+ -+static int sqlite_Close(dbiIndex dbi, unsigned int flags) -+{ -+ rpmdb rdb = dbi->dbi_rpmdb; -+ int rc = 0; -+ if (rdb->db_flags & RPMDB_FLAG_REBUILD) -+ rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file)); -+ sqlite_fini(dbi->dbi_rpmdb); -+ dbiFree(dbi); -+ return rc; -+} -+ -+static int sqlite_Verify(dbiIndex dbi, unsigned int flags) -+{ -+ int errors = -1; -+ int key_errors = -1; -+ sqlite3_stmt *s = NULL; -+ const char *cmd = "PRAGMA integrity_check"; -+ -+ if (dbi->dbi_type == DBI_SECONDARY) -+ return RPMRC_OK; -+ -+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) { -+ errors = 0; -+ while (sqlite3_step(s) == SQLITE_ROW) { -+ const char *txt = (const char *)sqlite3_column_text(s, 0); -+ if (!rstreq(txt, "ok")) { -+ errors++; -+ rpmlog(RPMLOG_ERR, "verify: %s\n", txt); -+ } -+ } -+ sqlite3_finalize(s); -+ } else { -+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db)); -+ } -+ -+ /* No point checking higher-level errors if low-level errors exist */ -+ if (errors) -+ goto exit; -+ -+ cmd = "PRAGMA foreign_key_check"; -+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) { -+ key_errors = 0; -+ while (sqlite3_step(s) == SQLITE_ROW) { -+ key_errors++; -+ rpmlog(RPMLOG_ERR, "verify key: %s[%lld]\n", -+ sqlite3_column_text(s, 0), -+ sqlite3_column_int64(s, 1)); -+ } -+ sqlite3_finalize(s); -+ } else { -+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db)); -+ } -+ -+exit: -+ -+ return (errors == 0 && key_errors == 0) ? RPMRC_OK : RPMRC_FAIL; -+} -+ -+static void sqlite_SetFSync(rpmdb rdb, int enable) -+{ -+ if (rdb->db_dbenv) { -+ sqlexec(rdb->db_dbenv, -+ "PRAGMA synchronous = %s", enable ? "FULL" : "OFF"); -+ } -+} -+ -+static int sqlite_Ctrl(rpmdb rdb, dbCtrlOp ctrl) -+{ -+ int rc = 0; -+ -+ switch (ctrl) { -+ case DB_CTRL_LOCK_RW: -+ rc = sqlexec(rdb->db_dbenv, "SAVEPOINT 'rwlock'"); -+ break; -+ case DB_CTRL_UNLOCK_RW: -+ rc = sqlexec(rdb->db_dbenv, "RELEASE 'rwlock'"); -+ break; -+ default: -+ break; -+ } -+ -+ return rc; -+} -+ -+static dbiCursor sqlite_CursorInit(dbiIndex dbi, unsigned int flags) -+{ -+ dbiCursor dbc = xcalloc(1, sizeof(*dbc)); -+ dbc->sdb = dbi->dbi_db; -+ dbc->flags = flags; -+ dbc->tag = rpmTagGetValue(dbi->dbi_file); -+ if (rpmTagGetClass(dbc->tag) == RPM_STRING_CLASS) { -+ dbc->ctype = SQLITE_TEXT; -+ } else { -+ dbc->ctype = SQLITE_BLOB; -+ } -+ if (dbc->flags & DBC_WRITE) -+ sqlexec(dbc->sdb, "SAVEPOINT '%s'", dbi->dbi_file); -+ return dbc; -+} -+ -+static dbiCursor sqlite_CursorFree(dbiIndex dbi, dbiCursor dbc) -+{ -+ if (dbc) { -+ sqlite3_finalize(dbc->stmt); -+ if (dbc->subc) -+ dbiCursorFree(dbi, dbc->subc); -+ if (dbc->flags & DBC_WRITE) -+ sqlexec(dbc->sdb, "RELEASE '%s'", dbi->dbi_file); -+ free(dbc); -+ } -+ return NULL; -+} -+ -+static rpmRC sqlite_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum) -+{ -+ return RPMRC_FAIL; -+} -+ -+static rpmRC sqlite_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen) -+{ -+ return RPMRC_FAIL; -+} -+ -+static rpmRC sqlite_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum) -+{ -+ return RPMRC_FAIL; -+} -+ -+static rpmRC sqlite_stepPkg(dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen) -+{ -+ int rc = sqlite3_step(dbc->stmt); -+ -+ if (rc == SQLITE_ROW) { -+ if (hdrLen) -+ *hdrLen = sqlite3_column_bytes(dbc->stmt, 1); -+ if (hdrBlob) -+ *hdrBlob = (void *) sqlite3_column_blob(dbc->stmt, 1); -+ } -+ return rc; -+} -+ -+static rpmRC sqlite_pkgdbByKey(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen) -+{ -+ int rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q' WHERE hnum=?", -+ dbi->dbi_file); -+ -+ if (!rc) -+ rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0); -+ -+ if (!rc) -+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen); -+ -+ return dbiCursorResult(dbc); -+} -+ -+static rpmRC sqlite_pkgdbIter(dbiIndex dbi, dbiCursor dbc, -+ unsigned char **hdrBlob, unsigned int *hdrLen) -+{ -+ int rc = RPMRC_OK; -+ if (dbc->stmt == NULL) { -+ rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q'", dbi->dbi_file); -+ } -+ -+ if (!rc) -+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen); -+ -+ if (rc == SQLITE_DONE) { -+ rc = RPMRC_NOTFOUND; -+ } else { -+ rc = dbiCursorResult(dbc); -+ } -+ -+ return rc; -+} -+ -+static rpmRC sqlite_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen) -+{ -+ int rc; -+ -+ if (hdrNum) { -+ rc = sqlite_pkgdbByKey(dbi, dbc, hdrNum, hdrBlob, hdrLen); -+ } else { -+ rc = sqlite_pkgdbIter(dbi, dbc, hdrBlob, hdrLen); -+ } -+ -+ return rc; -+} -+ -+static unsigned int sqlite_pkgdbKey(dbiIndex dbi, dbiCursor dbc) -+{ -+ return sqlite3_column_int(dbc->stmt, 0); -+} -+ -+static rpmRC sqlite_idxdbByKey(dbiIndex dbi, dbiCursor dbc, -+ const char *keyp, size_t keylen, int searchType, -+ dbiIndexSet *set) -+{ -+ int rc = RPMRC_NOTFOUND; -+ -+ if (searchType == DBC_PREFIX_SEARCH) { -+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' " -+ "WHERE MATCH(key,'%q',%d) " -+ "ORDER BY key", -+ dbi->dbi_file, keyp, keylen); -+ } else { -+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' WHERE key=?", -+ dbi->dbi_file); -+ if (!rc) -+ rc = dbiCursorBindIdx(dbc, keyp, keylen, NULL); -+ } -+ -+ -+ if (!rc) { -+ while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) { -+ unsigned int hnum = sqlite3_column_int(dbc->stmt, 0); -+ unsigned int tnum = sqlite3_column_int(dbc->stmt, 1); -+ -+ if (*set == NULL) -+ *set = dbiIndexSetNew(5); -+ dbiIndexSetAppendOne(*set, hnum, tnum, 0); -+ } -+ } -+ -+ if (rc == SQLITE_DONE) { -+ rc = (*set) ? RPMRC_OK : RPMRC_NOTFOUND; -+ } else { -+ rc = dbiCursorResult(dbc); -+ } -+ -+ return rc; -+} -+ -+static rpmRC sqlite_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set) -+{ -+ int rc = RPMRC_OK; -+ -+ if (dbc->stmt == NULL) { -+ rc = dbiCursorPrep(dbc, "SELECT DISTINCT key FROM '%q' ORDER BY key", -+ dbi->dbi_file); -+ if (set) -+ dbc->subc = dbiCursorInit(dbi, 0); -+ } -+ -+ if (!rc) -+ rc = sqlite3_step(dbc->stmt); -+ -+ if (rc == SQLITE_ROW) { -+ if (dbc->ctype == SQLITE_TEXT) { -+ dbc->key = sqlite3_column_text(dbc->stmt, 0); -+ } else { -+ dbc->key = sqlite3_column_blob(dbc->stmt, 0); -+ } -+ dbc->keylen = sqlite3_column_bytes(dbc->stmt, 0); -+ if (dbc->subc) { -+ rc = sqlite_idxdbByKey(dbi, dbc->subc, dbc->key, dbc->keylen, -+ DBC_NORMAL_SEARCH, set); -+ } else { -+ rc = RPMRC_OK; -+ } -+ } else if (rc == SQLITE_DONE) { -+ rc = RPMRC_NOTFOUND; -+ } else { -+ rc = dbiCursorResult(dbc); -+ } -+ -+ return rc; -+} -+ -+static rpmRC sqlite_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType) -+{ -+ int rc; -+ if (keyp) { -+ rc = sqlite_idxdbByKey(dbi, dbc, keyp, keylen, searchType, set); -+ } else { -+ rc = sqlite_idxdbIter(dbi, dbc, set); -+ } -+ -+ return rc; -+} -+ -+static rpmRC sqlite_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) -+{ -+ return RPMRC_FAIL; -+} -+ -+static rpmRC sqlite_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) -+{ -+ return RPMRC_FAIL; -+} -+ -+static const void * sqlite_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen) -+{ -+ const void *key = NULL; -+ if (dbc) { -+ key = dbc->key; -+ if (key && keylen) -+ *keylen = dbc->keylen; -+ } -+ return key; -+} -+ -+struct rpmdbOps_s sqlite_dbops = { -+ .open = sqlite_Open, -+ .close = sqlite_Close, -+ .verify = sqlite_Verify, -+ .setFSync = sqlite_SetFSync, -+ .ctrl = sqlite_Ctrl, -+ -+ .cursorInit = sqlite_CursorInit, -+ .cursorFree = sqlite_CursorFree, -+ -+ .pkgdbPut = sqlite_pkgdbPut, -+ .pkgdbDel = sqlite_pkgdbDel, -+ .pkgdbGet = sqlite_pkgdbGet, -+ .pkgdbKey = sqlite_pkgdbKey, -+ .pkgdbNew = sqlite_pkgdbNew, -+ -+ .idxdbGet = sqlite_idxdbGet, -+ .idxdbPut = sqlite_idxdbPut, -+ .idxdbDel = sqlite_idxdbDel, -+ .idxdbKey = sqlite_idxdbKey -+}; -+ -diff --git a/macros.in b/macros.in -index a6069ee4d..9ad3d60ef 100644 ---- a/macros.in -+++ b/macros.in -@@ -620,6 +620,7 @@ package or when debugging this package.\ - # bdb Berkeley DB - # lmdb Lightning Memory-mapped Database - # ndb new data base format -+# sqlite Sqlite database (read-only in this version!) - # - %_db_backend bdb - --- -2.31.1 - diff --git a/SOURCES/rpm-4.14.3-backport-multithreaded-zstd.patch b/SOURCES/rpm-4.14.3-backport-multithreaded-zstd.patch deleted file mode 100644 index 51a0290..0000000 --- a/SOURCES/rpm-4.14.3-backport-multithreaded-zstd.patch +++ /dev/null @@ -1,178 +0,0 @@ -From a5803faa083690526b96484c7e6a4cc915ca3921 Mon Nov 28 16:35:09 2022 -From: Aleksandr Kazakov -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 ---- - 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 - diff --git a/SOURCES/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch b/SOURCES/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch deleted file mode 100644 index 58606e9..0000000 --- a/SOURCES/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.14.3/lib/header.c.orig rpm-4.14.3/lib/header.c ---- rpm-4.14.3/lib/header.c.orig 2020-04-28 14:50:11.816399041 +0200 -+++ rpm-4.14.3/lib/header.c 2021-02-03 16:47:23.567245743 +0100 -@@ -1910,7 +1910,7 @@ rpmRC hdrblobRead(FD_t fd, int magic, in - - if (regionTag == RPMTAG_HEADERSIGNATURES) { - il_max = 32; -- dl_max = 8192; -+ dl_max = 64 * 1024 * 1024; - } - - memset(block, 0, sizeof(block)); diff --git a/SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch b/SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch deleted file mode 100644 index 343bd02..0000000 --- a/SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 534fd1f0c84b12ba6080a46e07c57ef913c77cba Mon Sep 17 00:00:00 2001 -From: Radovan Sroka -Date: Thu, 25 Aug 2022 15:38:01 +0200 -Subject: [PATCH] fapolicyd: Make write() nonblocking - -- switch to read only and non blocking mode for pipe -- add 1 minute loop to wait for pipe to reappear - -Sometimes during the system update/upgrade fapolicyd -get restarted e.g. when systemd gets updated. -That can lead to the situation where fapolicyd pipe -has been removed and created again. -In such cases rpm-plugin-fapolicyd gets stuck on -write() to the pipe which does not exist anymore. -After switching to non blocking file descriptor -we can try to reopen the pipe if there is an error -from write(). Assuming that a new pipe should appear -when fapolicyd daemon starts again. -If not then after 1 minute of waiting we expect -fapolicyd daemon to be not active and we let the -transaction continue. - -Signed-off-by: Radovan Sroka ---- - plugins/fapolicyd.c | 74 +++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 65 insertions(+), 9 deletions(-) - -diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c -index 1ff50c30f..6c6322941 100644 ---- a/plugins/fapolicyd.c -+++ b/plugins/fapolicyd.c -@@ -27,7 +27,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state) - int fd = -1; - struct stat s; - -- fd = open(state->fifo_path, O_RDWR); -+ fd = open(state->fifo_path, O_WRONLY|O_NONBLOCK); - if (fd == -1) { - rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno)); - goto bad; -@@ -55,15 +55,26 @@ static rpmRC open_fifo(struct fapolicyd_data* state) - } - - state->fd = fd; -+ - /* considering success */ - return RPMRC_OK; - - bad: - if (fd >= 0) - close(fd); -+ -+ state->fd = -1; - return RPMRC_FAIL; - } - -+static void close_fifo(struct fapolicyd_data* state) -+{ -+ if (state->fd > 0) -+ (void) close(state->fd); -+ -+ state->fd = -1; -+} -+ - static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) - { - ssize_t len = strlen(str); -@@ -86,6 +97,54 @@ static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) - return RPMRC_FAIL; - } - -+static void try_to_write_to_fifo(struct fapolicyd_data* state, const char * str) -+{ -+ int reload = 0; -+ int printed = 0; -+ -+ /* 1min/60s */ -+ const int timeout = 60; -+ -+ /* wait up to X seconds */ -+ for (int i = 0; i < timeout; i++) { -+ -+ if (reload) { -+ if (!printed) { -+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: waiting for the service connection to resume, it can take up to %d seconds\n", timeout); -+ printed = 1; -+ } -+ -+ (void) close_fifo(state); -+ (void) open_fifo(state); -+ } -+ -+ if (state->fd >= 0) { -+ if (write_fifo(state, str) == RPMRC_OK) { -+ -+ /* write was successful after few reopens */ -+ if (reload) -+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has resumed\n"); -+ -+ break; -+ } -+ } -+ -+ /* failed write or reopen */ -+ reload = 1; -+ sleep(1); -+ -+ /* the last iteration */ -+ /* consider failure */ -+ if (i == timeout-1) { -+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has not resumed\n"); -+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: continuing without the service\n"); -+ } -+ -+ } -+ -+} -+ -+ - static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) - { - if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) -@@ -102,10 +161,7 @@ static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) - - static void fapolicyd_cleanup(rpmPlugin plugin) - { -- if (fapolicyd_state.fd > 0) -- (void) close(fapolicyd_state.fd); -- -- fapolicyd_state.fd = -1; -+ (void) close_fifo(&fapolicyd_state); - } - - static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) -@@ -116,9 +172,9 @@ static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) - /* we are ready */ - if (fapolicyd_state.fd > 0) { - /* send a signal that transaction is over */ -- (void) write_fifo(&fapolicyd_state, "1\n"); -+ (void) try_to_write_to_fifo(&fapolicyd_state, "1\n"); - /* flush cache */ -- (void) write_fifo(&fapolicyd_state, "2\n"); -+ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n"); - } - - end: -@@ -133,7 +189,7 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name, - - if (fapolicyd_state.changed_files > 0) { - /* send signal to flush cache */ -- (void) write_fifo(&fapolicyd_state, "2\n"); -+ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n"); - - /* optimize flushing */ - /* flush only when there was an actual change */ -@@ -176,7 +232,7 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, - char * sha = rpmfiFDigestHex(fi, NULL); - - snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); -- (void) write_fifo(&fapolicyd_state, buffer); -+ (void) try_to_write_to_fifo(&fapolicyd_state, buffer); - - free(sha); - --- -2.37.3 - diff --git a/SOURCES/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch b/SOURCES/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch deleted file mode 100644 index 48039c7..0000000 --- a/SOURCES/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch +++ /dev/null @@ -1,101 +0,0 @@ -diff -up rpm-4.14.3/lib/rpmscript.c.orig rpm-4.14.3/lib/rpmscript.c ---- rpm-4.14.3/lib/rpmscript.c.orig 2021-02-08 14:07:44.527197946 +0100 -+++ rpm-4.14.3/lib/rpmscript.c 2021-02-08 14:09:05.732749080 +0100 -@@ -46,27 +46,27 @@ struct scriptInfo_s { - }; - - static const struct scriptInfo_s scriptInfo[] = { -- { RPMSCRIPT_PREIN, "%prein", 0, -+ { RPMSCRIPT_PREIN, "prein", 0, - RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS }, -- { RPMSCRIPT_PREUN, "%preun", 0, -+ { RPMSCRIPT_PREUN, "preun", 0, - RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS }, -- { RPMSCRIPT_POSTIN, "%post", 0, -+ { RPMSCRIPT_POSTIN, "post", 0, - RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS }, -- { RPMSCRIPT_POSTUN, "%postun", 0, -+ { RPMSCRIPT_POSTUN, "postun", 0, - RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS }, -- { RPMSCRIPT_PRETRANS, "%pretrans", 0, -+ { RPMSCRIPT_PRETRANS, "pretrans", 0, - RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS }, -- { RPMSCRIPT_POSTTRANS, "%posttrans", 0, -+ { RPMSCRIPT_POSTTRANS, "posttrans", 0, - RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS }, -- { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN, -+ { RPMSCRIPT_TRIGGERPREIN, "triggerprein", RPMSENSE_TRIGGERPREIN, - RPMTAG_TRIGGERPREIN, 0, 0 }, -- { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN, -+ { RPMSCRIPT_TRIGGERUN, "triggerun", RPMSENSE_TRIGGERUN, - RPMTAG_TRIGGERUN, 0, 0 }, -- { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN, -+ { RPMSCRIPT_TRIGGERIN, "triggerin", RPMSENSE_TRIGGERIN, - RPMTAG_TRIGGERIN, 0, 0 }, -- { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN, -+ { RPMSCRIPT_TRIGGERPOSTUN, "triggerpostun", RPMSENSE_TRIGGERPOSTUN, - RPMTAG_TRIGGERPOSTUN, 0, 0 }, -- { RPMSCRIPT_VERIFY, "%verify", 0, -+ { RPMSCRIPT_VERIFY, "verify", 0, - RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS}, - { 0, "unknown", 0, - RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND } -@@ -457,7 +457,7 @@ static const char * tag2sln(rpmTagVal ta - } - - static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body, -- rpmscriptFlags flags) -+ rpmscriptFlags flags, const char *prefix) - { - char *nevra = headerGetAsString(h, RPMTAG_NEVRA); - rpmScript script = xcalloc(1, sizeof(*script)); -@@ -465,7 +465,7 @@ static rpmScript rpmScriptNew(Header h, - script->type = getScriptType(tag); - script->flags = flags; - script->body = (body != NULL) ? xstrdup(body) : NULL; -- rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra); -+ rasprintf(&script->descr, "%%%s%s(%s)", prefix, tag2sln(tag), nevra); - - /* macros need to be expanded before possible queryformat */ - if (script->body && (script->flags & RPMSCRIPT_FLAG_EXPAND)) { -@@ -556,6 +556,7 @@ rpmScript rpmScriptFromTriggerTag(Header - rpmScript script = NULL; - struct rpmtd_s tscripts, tprogs, tflags; - headerGetFlags hgflags = HEADERGET_MINMEM; -+ const char *prefix = ""; - - switch (tm) { - case RPMSCRIPT_NORMALTRIGGER: -@@ -567,11 +568,13 @@ rpmScript rpmScriptFromTriggerTag(Header - headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags); - headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags); - headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags); -+ prefix = "file"; - break; - case RPMSCRIPT_TRANSFILETRIGGER: - headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags); - headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags); - headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags); -+ prefix = "transfile"; - break; - } - -@@ -582,7 +585,8 @@ rpmScript rpmScriptFromTriggerTag(Header - if (rpmtdSetIndex(&tflags, ix) >= 0) - sflags = rpmtdGetNumber(&tflags); - -- script = rpmScriptNew(h, triggerTag, rpmtdGetString(&tscripts), sflags); -+ script = rpmScriptNew(h, triggerTag, -+ rpmtdGetString(&tscripts), sflags, prefix); - - /* hack up a hge-style NULL-terminated array */ - script->args = xmalloc(2 * sizeof(*script->args) + strlen(prog) + 1); -@@ -608,7 +612,7 @@ rpmScript rpmScriptFromTag(Header h, rpm - - script = rpmScriptNew(h, scriptTag, - headerGetString(h, scriptTag), -- headerGetNumber(h, getFlagTag(scriptTag))); -+ headerGetNumber(h, getFlagTag(scriptTag)), ""); - - if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) { - script->args = prog.data; diff --git a/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch b/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch deleted file mode 100644 index 6b26ec5..0000000 --- a/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch +++ /dev/null @@ -1,184 +0,0 @@ -From f17aa638649fb8de730fecdbc906dc869b626ba5 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Tue, 16 Nov 2021 11:49:18 +0200 -Subject: [PATCH 1/2] Fix spurious %transfiletriggerpostun execution - (RhBug:2023311) - -If a package has multiple %transfiletriggerpostun triggers, any one -of them matching would cause all of them to run, due to disconnect -in the intel gathering stage: we'd gather all the headers with matching -files into a lump, and then add any postun triggers found in them, -but this loses the triggering file information and causes all postuns -to run. - -The triggers need to be added while looping over the file matches, -like runFileTriggers() does. Doing so actually simplifies the code. -These should really be unified to use the same code, but leaving -that exercise to another rainy day. ---- - lib/rpmtriggers.c | 64 +++++++++++++++++++++++------------------------ - 1 file changed, 31 insertions(+), 33 deletions(-) - -diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c -index 0827af0c2..dc457f7cc 100644 ---- a/lib/rpmtriggers.c -+++ b/lib/rpmtriggers.c -@@ -97,19 +97,37 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs) - } - } - -+static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter) -+{ -+ int tix = 0; -+ rpmds ds; -+ rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); -+ -+ while ((ds = rpmdsFilterTi(triggers, tix))) { -+ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) { -+ struct rpmtd_s priorities; -+ -+ if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, -+ &priorities, HEADERGET_MINMEM)) { -+ rpmtdSetIndex(&priorities, tix); -+ rpmtriggersAdd(ts->trigs2run, headerGetInstance(trigH), -+ tix, *rpmtdGetUint32(&priorities)); -+ } -+ } -+ rpmdsFree(ds); -+ tix++; -+ } -+ rpmdsFree(triggers); -+} -+ - void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) - { -- rpmdbMatchIterator mi; - rpmdbIndexIterator ii; -- Header trigH; - const void *key; - size_t keylen; - rpmfiles files; -- rpmds rpmdsTriggers; -- rpmds rpmdsTrigger; - - ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME); -- mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES); - files = rpmteFiles(te); - - /* Iterate over file triggers in rpmdb */ -@@ -121,39 +139,19 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) - rpmfi fi = rpmfilesFindPrefix(files, pfx); - while (rpmfiNext(fi) >= 0) { - if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { -- /* If yes then store it */ -- rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii), -- rpmdbIndexIteratorNumPkgs(ii)); -- break; -+ unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii); -+ const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii); -+ /* Save any matching postun triggers */ -+ for (int i = 0; i < npkg; i++) { -+ Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]); -+ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN); -+ headerFree(h); -+ } - } - } - rpmfiFree(fi); - } - rpmdbIndexIteratorFree(ii); -- -- if (rpmdbGetIteratorCount(mi)) { -- /* Filter triggers and save only trans postun triggers into ts */ -- while ((trigH = rpmdbNextIterator(mi)) != NULL) { -- int tix = 0; -- rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); -- while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) { -- if ((rpmdsNext(rpmdsTrigger) >= 0) && -- (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) { -- struct rpmtd_s priorities; -- -- headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, -- &priorities, HEADERGET_MINMEM); -- rpmtdSetIndex(&priorities, tix); -- rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi), -- tix, *rpmtdGetUint32(&priorities)); -- } -- rpmdsFree(rpmdsTrigger); -- tix++; -- } -- rpmdsFree(rpmdsTriggers); -- } -- } -- rpmdbFreeIterator(mi); - rpmfilesFree(files); - } - --- -2.35.1 - -From e617e7c550d3523998707c55f96b37ede2c48c78 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 2 Feb 2022 13:46:23 +0200 -Subject: [PATCH 2/2] Really fix spurious %transfiletriggerpostun execution - (RhBug:2023311) - -Commit b3d672a5523dfec033160e5cc866432a0e808649 got the base reasoning -in the ballpark but the code all wrong, introducing a severe performance -regression without actually fixing what it claimed to. - -The missing incredient is actually comparing the current prefix with the -triggers in matched package (trying to describe this makes my head -spin): a package may have multiple triggers on multiple prefixes and -we need to make sure we only execute triggers of this type, from this -prefix. - -This stuff really needs more and better testcases. - -Fixes: b3d672a5523dfec033160e5cc866432a0e808649 ---- - lib/rpmtriggers.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c -index dc457f7cc..c652981be 100644 ---- a/lib/rpmtriggers.c -+++ b/lib/rpmtriggers.c -@@ -97,14 +97,16 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs) - } - } - --static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter) -+static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter, -+ const char *prefix) - { - int tix = 0; - rpmds ds; - rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); - - while ((ds = rpmdsFilterTi(triggers, tix))) { -- if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) { -+ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter) && -+ strcmp(prefix, rpmdsN(ds)) == 0) { - struct rpmtd_s priorities; - - if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, -@@ -141,12 +143,13 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) - if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { - unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii); - const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii); -- /* Save any matching postun triggers */ -+ /* Save any postun triggers matching this prefix */ - for (int i = 0; i < npkg; i++) { - Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]); -- addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN); -+ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN, pfx); - headerFree(h); - } -+ break; - } - } - rpmfiFree(fi); --- -2.35.1 - diff --git a/SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch b/SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch deleted file mode 100644 index 8321161..0000000 --- a/SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch +++ /dev/null @@ -1,100 +0,0 @@ -commit 8f4b3c3cab8922a2022b9e47c71f1ecf906077ef -Author: Demi Marie Obenour -Date: Mon Feb 8 16:05:01 2021 -0500 - - hdrblobInit() needs bounds checks too - - Users can pass untrusted data to hdrblobInit() and it must be robust - against this. - -diff --git a/lib/header.c b/lib/header.c -index ea39e679f..ebba9c2b0 100644 ---- a/lib/header.c -+++ b/lib/header.c -@@ -11,6 +11,7 @@ - #include "system.h" - #include - #include -+#include - #include - #include - #include "lib/header_internal.h" -@@ -1912,6 +1913,25 @@ hdrblob hdrblobFree(hdrblob blob) - return NULL; - } - -+static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl, -+ char **emsg) { -+ uint32_t il_max = HEADER_TAGS_MAX; -+ uint32_t dl_max = HEADER_DATA_MAX; -+ if (regionTag == RPMTAG_HEADERSIGNATURES) { -+ il_max = 32; -+ dl_max = 64 * 1024 * 1024; -+ } -+ if (hdrchkRange(il_max, il)) { -+ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il); -+ return RPMRC_FAIL; -+ } -+ if (hdrchkRange(dl_max, dl)) { -+ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; -+} -+ - rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg) - { - int32_t block[4]; -@@ -1924,13 +1944,6 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl - size_t nb; - rpmRC rc = RPMRC_FAIL; /* assume failure */ - int xx; -- int32_t il_max = HEADER_TAGS_MAX; -- int32_t dl_max = HEADER_DATA_MAX; -- -- if (regionTag == RPMTAG_HEADERSIGNATURES) { -- il_max = 32; -- dl_max = 64 * 1024 * 1024; -- } - - memset(block, 0, sizeof(block)); - if ((xx = Freadall(fd, bs, blen)) != blen) { -@@ -1943,15 +1956,9 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl - goto exit; - } - il = ntohl(block[2]); -- if (hdrchkRange(il_max, il)) { -- rasprintf(emsg, _("hdr tags: BAD, no. of tags(%d) out of range"), il); -- goto exit; -- } - dl = ntohl(block[3]); -- if (hdrchkRange(dl_max, dl)) { -- rasprintf(emsg, _("hdr data: BAD, no. of bytes(%d) out of range"), dl); -+ if (hdrblobVerifyLengths(regionTag, il, dl, emsg)) - goto exit; -- } - - nb = (il * sizeof(struct entryInfo_s)) + dl; - uc = sizeof(il) + sizeof(dl) + nb; -@@ -1995,11 +2002,18 @@ rpmRC hdrblobInit(const void *uh, size_t uc, - struct hdrblob_s *blob, char **emsg) - { - rpmRC rc = RPMRC_FAIL; -- - memset(blob, 0, sizeof(*blob)); -+ if (uc && uc < 8) { -+ rasprintf(emsg, _("hdr length: BAD")); -+ goto exit; -+ } -+ - blob->ei = (int32_t *) uh; /* discards const */ -- blob->il = ntohl(blob->ei[0]); -- blob->dl = ntohl(blob->ei[1]); -+ blob->il = ntohl((uint32_t)(blob->ei[0])); -+ blob->dl = ntohl((uint32_t)(blob->ei[1])); -+ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK) -+ goto exit; -+ - blob->pe = (entryInfo) &(blob->ei[2]); - blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) + - (blob->il * sizeof(*blob->pe)) + blob->dl; diff --git a/SOURCES/rpm-4.14.3-imp-covscan-fixes.patch b/SOURCES/rpm-4.14.3-imp-covscan-fixes.patch deleted file mode 100644 index 679c474..0000000 --- a/SOURCES/rpm-4.14.3-imp-covscan-fixes.patch +++ /dev/null @@ -1,327 +0,0 @@ -commit c7d7c5acd0c14d0450016887cba1d86483086794 -Author: Michal Domonkos -Date: Mon Jun 21 10:05:10 2021 +0200 - - Add quoting to literal curly brackets - - These curly brackets are already treated as literals by the shell, so - let's make that explicit for clarity, and silence a ShellCheck warning - at the same time. - - More info: https://github.com/koalaman/shellcheck/wiki/SC1083 - - Found by ShellCheck. - -diff -up rpm-4.16.1.3/scripts/check-rpaths-worker.orig rpm-4.16.1.3/scripts/check-rpaths-worker ---- rpm-4.16.1.3/scripts/check-rpaths-worker.orig 2021-06-29 15:34:31.671003589 +0200 -+++ rpm-4.16.1.3/scripts/check-rpaths-worker 2021-06-29 15:34:51.993414093 +0200 -@@ -120,13 +120,13 @@ for i; do - (/lib64/*|/usr/lib64/*|/usr/X11R6/lib64/*|/usr/local/lib64/*) - badness=0;; - -- (\$ORIGIN|\${ORIGINX}|\$ORIGIN/*|\${ORIGINX}/*) -+ (\$ORIGIN|\$\{ORIGINX\}|\$ORIGIN/*|\$\{ORIGINX\}/*) - test $allow_ORIGIN -eq 0 && badness=8 || { - badness=0 - new_allow_ORIGIN=1 - } - ;; -- (/*\$PLATFORM*|/*\${PLATFORM}*|/*\$LIB*|/*\${LIB}*) -+ (/*\$PLATFORM*|/*\$\{PLATFORM\}*|/*\$LIB*|/*\$\{LIB\}*) - badness=0;; - - (/lib|/usr/lib|/usr/X11R6/lib) -From d8dc4fd37b1d90cd97de7fcf484d449ec132c9b3 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Wed, 9 Jun 2021 21:31:40 +0200 -Subject: [PATCH 1/7] Fix memory leak in sqlexec() - -Callers are supposed to free the error strings themselves: -https://www.sqlite.org/capi3ref.html#sqlite3_exec - -Found by Coverity. ---- - lib/backend/sqlite.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c -index 7c2de45aa..dbefeb163 100644 ---- a/lib/backend/sqlite.c -+++ b/lib/backend/sqlite.c -@@ -233,6 +233,7 @@ static int sqlexec(sqlite3 *sdb, const char *fmt, ...) - rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc); - - sqlite3_free(cmd); -+ sqlite3_free(err); - - return rc ? RPMRC_FAIL : RPMRC_OK; - } --- -2.31.1 - -From 5baf73feb4951cc3b3f553a4b18d3b3599cbf87c Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Fri, 25 Jun 2021 11:21:46 +0200 -Subject: [PATCH 2/7] Always free the arg list passed to rpmGlob() - -Even though the actual implementation of rpmGlob() does not allocate the -passed arg list (av) if the return code (rc) is non-zero or arg count -(ac) is 0, it's the responsibility of the caller (rpmInstall() here) to -free that memory, so make sure we do that irrespectively of the above -conditions. - -Found by Coverity. ---- - lib/rpminstall.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/rpminstall.c b/lib/rpminstall.c -index 724126e94..302ec0ba1 100644 ---- a/lib/rpminstall.c -+++ b/lib/rpminstall.c -@@ -461,6 +461,7 @@ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv) - rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp); - } - eiu->numFailed++; -+ argvFree(av); - continue; - } - --- -2.31.1 - -From 3c8b01b67ec907afaaffe71691fa41b878578527 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Mon, 14 Jun 2021 10:21:25 +0200 -Subject: [PATCH 3/7] Fix resource leak in Fts_children() - -This function is not used anywhere within our codebase (and neither is -it part of the public API) so it's basically a no-op... Still, rather -than yanking it completely, let's just silence the Coverity error here. - -Found by Coverity. ---- - misc/fts.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/misc/fts.c b/misc/fts.c -index d3ebb2946..caf27495d 100644 ---- a/misc/fts.c -+++ b/misc/fts.c -@@ -585,8 +585,10 @@ Fts_children(FTS * sp, int instr) - if ((fd = __open(".", O_RDONLY, 0)) < 0) - return (NULL); - sp->fts_child = fts_build(sp, instr); -- if (__fchdir(fd)) -+ if (__fchdir(fd)) { -+ (void)__close(fd); - return (NULL); -+ } - (void)__close(fd); - return (sp->fts_child); - } --- -2.31.1 - -From 39b7bf8579e0522cf16347b3a7e332d3b6d742c6 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Mon, 14 Jun 2021 12:34:23 +0200 -Subject: [PATCH 4/7] Fix memory leak in fts_build() - -Turns out this leak is already fixed in glibc's current version of fts.c -(where our copy originates from), so let's just backport that. - -Original commit in glibc: -https://sourceware.org/git/?p=glibc.git;\ -a=commit;h=db67c2c98b89a5723af44df54f38b779de8d4a65 - -Found by Coverity. ---- - misc/fts.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/misc/fts.c b/misc/fts.c -index caf27495d..f7fce0eaa 100644 ---- a/misc/fts.c -+++ b/misc/fts.c -@@ -855,6 +855,7 @@ mem1: saved_errno = errno; - fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { - cur->fts_info = FTS_ERR; - SET(FTS_STOP); -+ fts_lfree(head); - return (NULL); - } - -@@ -862,6 +863,7 @@ mem1: saved_errno = errno; - if (!nitems) { - if (type == BREAD) - cur->fts_info = FTS_DP; -+ fts_lfree(head); - return (NULL); - } - --- -2.31.1 - -From 9c093c4f092dd6bd1e0c8d2b852a72b74db076c2 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Tue, 15 Jun 2021 13:34:21 +0200 -Subject: [PATCH 5/7] Fix memory leak in decodePkts() - -Found by Coverity. ---- - rpmio/rpmpgp.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index c59185dce..ee5c81e24 100644 ---- a/rpmio/rpmpgp.c -+++ b/rpmio/rpmpgp.c -@@ -1371,9 +1371,13 @@ static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen) - crc = pgpCRC(dec, declen); - if (crcpkt != crc) { - ec = PGPARMOR_ERR_CRC_CHECK; -+ _free(dec); - goto exit; - } -- if (pkt) *pkt = dec; -+ if (pkt) -+ *pkt = dec; -+ else -+ _free(dec); - if (pktlen) *pktlen = declen; - ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */ - goto exit; --- -2.31.1 - -From 590b2fc06252567eb7d57197dc361a8b459d62a3 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Mon, 21 Jun 2021 17:51:14 +0200 -Subject: [PATCH 6/7] Fix memory leak with multiple %lang-s in one line - -We permit two equivalent forms of specifying a list of languages per -file: - - %lang(xx,yy,zz) /path/to/file - %lang(xx) %lang(yy) %lang(zz) /path/to/file - -The leak was when parsing the second form. - -Found by Coverity. ---- - build/files.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/build/files.c b/build/files.c -index f8153ad2b..0c8859f6c 100644 ---- a/build/files.c -+++ b/build/files.c -@@ -777,6 +777,8 @@ static rpmRC parseForLang(char * buf, FileEntry cur) - - if (*pe == ',') pe++; /* skip , if present */ - } -+ -+ q = _free(q); - } - - rc = RPMRC_OK; --- -2.31.1 - -From b7a1e996326ee29a163d67ceb1e6127fdc251c14 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Fri, 25 Jun 2021 15:15:08 +0200 -Subject: [PATCH 7/7] Fix memory leaks in Lua rex extension - -This covers the following usage: - -expr = rex.newPOSIX() -expr:match() # A leak occurred here -expr:gmatch(, ) # A leak occurred here - -Found by Coverity. ---- - luaext/lrexlib.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/luaext/lrexlib.c b/luaext/lrexlib.c -index 09c5a6454..0f29b6371 100644 ---- a/luaext/lrexlib.c -+++ b/luaext/lrexlib.c -@@ -80,6 +80,7 @@ static void rex_push_matches(lua_State *L, const char *text, regmatch_t *match, - - static int rex_match(lua_State *L) - { -+ int rc = 0; - int res; - #ifdef REG_BASIC - size_t len; -@@ -109,9 +110,10 @@ static int rex_match(lua_State *L) - lua_pushstring(L, "n"); - lua_pushnumber(L, ncapt); - lua_rawset(L, -3); -- return 3; -- } else -- return 0; -+ rc = 3; -+ } -+ free(match); -+ return rc; - } - - static int rex_gmatch(lua_State *L) -@@ -158,6 +160,7 @@ static int rex_gmatch(lua_State *L) - break; - } - lua_pushnumber(L, nmatch); -+ free(match); - return 1; - } - --- -2.31.1 - -commit 9747a6af016a3458d54fe060777c95e3900b5fa4 -Author: Demi Marie Obenour -Date: Tue Mar 2 12:47:29 2021 -0500 - - Fix a tiny memory leak - - Found by fuzzing rpmReadPackageFile() with libfuzzer under ASAN. - -diff --git a/lib/headerutil.c b/lib/headerutil.c -index 22e36c74d..fab210ff2 100644 ---- a/lib/headerutil.c -+++ b/lib/headerutil.c -@@ -333,8 +333,10 @@ static void providePackageNVR(Header h) - rpmds hds, nvrds; - - /* Generate provides for this package name-version-release. */ -- if (!(name && pEVR)) -+ if (!(name && pEVR)) { -+ free(pEVR); - return; -+ } - - /* - * Rpm prior to 3.0.3 does not have versioned provides. -commit cb2ae4bdf2f60876fdc68e3f84938e9c37182fab -Author: Igor Gnatenko -Date: Tue Feb 6 14:50:27 2018 +0100 - - lua: fix memory leak in Pexec() - - Signed-off-by: Igor Gnatenko - -diff --git a/luaext/lposix.c b/luaext/lposix.c -index 5d7ad3c87..2730bcff7 100644 ---- a/luaext/lposix.c -+++ b/luaext/lposix.c -@@ -348,6 +348,7 @@ static int Pexec(lua_State *L) /** exec(path,[args]) */ - for (i=1; i -Date: Thu, 27 May 2021 13:58:58 +0300 -Subject: [PATCH] Macroize find-debuginfo script location - -Makes it easier to handle varying paths, mainly in preparation for the -next step. - -Backported for 4.14.3. ---- - macros.in | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/macros.in b/macros.in -index a6069ee4d..be28a3b28 100644 ---- a/macros.in -+++ b/macros.in -@@ -82,6 +82,8 @@ - %__remsh %{__rsh} - %__strip @__STRIP@ - -+%__find_debuginfo %{_rpmconfigdir}/find-debuginfo.sh -+ - # XXX avoid failures if tools are not installed when rpm is built. - %__libtoolize libtoolize - %__aclocal aclocal -@@ -177,7 +179,7 @@ - # the script. See the script for details. - # - %__debug_install_post \ -- %{_rpmconfigdir}/find-debuginfo.sh \\\ -+ %{__find_debuginfo} \\\ - %{?_smp_mflags} \\\ - %{?_missing_build_ids_terminate_build:--strict-build-id} \\\ - %{?_no_recompute_build_ids:-n} \\\ --- -2.33.1 - diff --git a/SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch b/SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch deleted file mode 100644 index 4a4f4ae..0000000 --- a/SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch +++ /dev/null @@ -1,162 +0,0 @@ -commit d6a86b5e69e46cc283b1e06c92343319beb42e21 -Author: Panu Matilainen -Date: Thu Mar 4 13:21:19 2021 +0200 - - Be much more careful about copying data from the signature header - - Only look for known tags, and ensure correct type and size where known - before copying over. Bump the old arbitrary 16k count limit to 16M limit - though, it's not inconceivable that a package could have that many files. - While at it, ensure none of these tags exist in the main header, - which would confuse us greatly. - - This is optimized for backporting ease, upstream can remove redundancies - and further improve checking later. - - Reported and initial patches by Demi Marie Obenour. - - Fixes: RhBug:1935049, RhBug:1933867, RhBug:1935035, RhBug:1934125, ... - - Fixes: CVE-2021-3421, CVE-2021-20271 - - Combined with e2f1f1931c5ccf3ecbe4e1e12cacb1e17a277776 and backported into - 4.14.3 - -diff -up rpm-4.14.3/lib/package.c.orig rpm-4.14.3/lib/package.c ---- rpm-4.14.3/lib/package.c.orig 2021-05-31 12:32:49.970393976 +0200 -+++ rpm-4.14.3/lib/package.c 2021-05-31 13:53:58.250673275 +0200 -@@ -31,76 +31,72 @@ struct pkgdata_s { - rpmRC rc; - }; - -+struct taglate_s { -+ rpmTagVal stag; -+ rpmTagVal xtag; -+ rpm_count_t count; -+ int quirk; -+} const xlateTags[] = { -+ { RPMSIGTAG_SIZE, RPMTAG_SIGSIZE, 1, 0 }, -+ { RPMSIGTAG_PGP, RPMTAG_SIGPGP, 0, 0 }, -+ { RPMSIGTAG_MD5, RPMTAG_SIGMD5, 16, 0 }, -+ { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 }, -+ /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */ -+ { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 }, -+ { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, -+ { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, -+ { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, -+ { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0, 0 }, -+ { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1, 0 }, -+ { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1, 0 }, -+ { 0 } -+}; -+ - /** \ingroup header - * Translate and merge legacy signature tags into header. - * @param h header (dest) - * @param sigh signature header (src) -+ * @return failing tag number, 0 on success - */ - static --void headerMergeLegacySigs(Header h, Header sigh) -+rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg) - { -- HeaderIterator hi; -+ const struct taglate_s *xl; - struct rpmtd_s td; - -- hi = headerInitIterator(sigh); -- for (; headerNext(hi, &td); rpmtdFreeData(&td)) -- { -- switch (td.tag) { -- /* XXX Translate legacy signature tag values. */ -- case RPMSIGTAG_SIZE: -- td.tag = RPMTAG_SIGSIZE; -- break; -- case RPMSIGTAG_PGP: -- td.tag = RPMTAG_SIGPGP; -- break; -- case RPMSIGTAG_MD5: -- td.tag = RPMTAG_SIGMD5; -- break; -- case RPMSIGTAG_GPG: -- td.tag = RPMTAG_SIGGPG; -- break; -- case RPMSIGTAG_PGP5: -- td.tag = RPMTAG_SIGPGP5; -- break; -- case RPMSIGTAG_PAYLOADSIZE: -- td.tag = RPMTAG_ARCHIVESIZE; -- break; -- case RPMSIGTAG_SHA1: -- case RPMSIGTAG_SHA256: -- case RPMSIGTAG_DSA: -- case RPMSIGTAG_RSA: -- default: -- if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE)) -+ rpmtdReset(&td); -+ for (xl = xlateTags; xl->stag; xl++) { -+ /* There mustn't be one in the main header */ -+ if (headerIsEntry(h, xl->xtag)) { -+ /* Some tags may exist in either header, but never both */ -+ if (xl->quirk && !headerIsEntry(sigh, xl->stag)) - continue; - break; - } -- if (!headerIsEntry(h, td.tag)) { -- switch (td.type) { -- case RPM_NULL_TYPE: -- continue; -+ if (headerGet(sigh, xl->stag, &td, HEADERGET_RAW|HEADERGET_MINMEM)) { -+ /* Translate legacy tags */ -+ if (xl->stag != xl->xtag) -+ td.tag = xl->xtag; -+ /* Ensure type and tag size match expectations */ -+ if (td.type != rpmTagGetTagType(td.tag)) - break; -- case RPM_CHAR_TYPE: -- case RPM_INT8_TYPE: -- case RPM_INT16_TYPE: -- case RPM_INT32_TYPE: -- case RPM_INT64_TYPE: -- if (td.count != 1) -- continue; -+ if (td.count < 1 || td.count > 16*1024*1024) - break; -- case RPM_STRING_TYPE: -- case RPM_BIN_TYPE: -- if (td.count >= 16*1024) -- continue; -+ if (xl->count && td.count != xl->count) - break; -- case RPM_STRING_ARRAY_TYPE: -- case RPM_I18NSTRING_TYPE: -- continue; -+ if (!headerPut(h, &td, HEADERPUT_DEFAULT)) - break; -- } -- (void) headerPut(h, &td, HEADERPUT_DEFAULT); -+ rpmtdFreeData(&td); - } - } -- headerFreeIterator(hi); -+ rpmtdFreeData(&td); -+ -+ if (xl->stag) { -+ rasprintf(msg, "invalid signature tag %s (%d)", -+ rpmTagGetName(xl->xtag), xl->xtag); -+ } -+ -+ return xl->stag; - } - - /** -@@ -363,7 +359,8 @@ rpmRC rpmReadPackageFile(rpmts ts, FD_t - goto exit; - - /* Append (and remap) signature tags to the metadata. */ -- headerMergeLegacySigs(h, sigh); -+ if (headerMergeLegacySigs(h, sigh, &msg)) -+ goto exit; - applyRetrofits(h); - - /* Bump reference count for return. */ diff --git a/SOURCES/rpm-4.14.3-python3.diff b/SOURCES/rpm-4.14.3-python3.diff deleted file mode 100644 index 7ec81b5..0000000 --- a/SOURCES/rpm-4.14.3-python3.diff +++ /dev/null @@ -1,13 +0,0 @@ ---- rpm-4.14.3/configure.ac.orig 2020-05-04 21:08:41.481365399 +0200 -+++ rpm-4.14.3/configure.ac 2020-05-04 21:09:03.550604043 +0200 -@@ -129,8 +129,8 @@ - - AC_PATH_PROG(__PERL, perl, /usr/bin/perl, $MYPATH) - AC_PATH_PROG(__PGP, pgp, /usr/bin/pgp, $MYPATH) --AC_PATH_PROG(__PYTHON, python2, /usr/bin/python2, $MYPATH) --AC_PATH_PROG(PYTHON, python2, /usr/bin/python2, $MYPATH) -+AC_PATH_PROG(__PYTHON, python3, /usr/bin/python3, $MYPATH) -+AC_PATH_PROG(PYTHON, python3, /usr/bin/python3, $MYPATH) - AC_PATH_PROG(__RM, rm, /bin/rm, $MYPATH) - AC_PATH_PROG(__RSH, rsh, /usr/bin/rsh, $MYPATH) - AC_PATH_PROG(__SED, sed, /bin/sed, $MYPATH) diff --git a/SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch b/SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch deleted file mode 100644 index ff9d1a3..0000000 --- a/SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch +++ /dev/null @@ -1,29 +0,0 @@ -From fe274b8f965582fdf97e6c46f90b9e7c124b0b8b Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Fri, 16 Dec 2022 15:50:12 +0100 -Subject: [PATCH] rpm2archive: Don't print usage on no arguments - -given as we want to default to reading from stdin and writing to stdout in -that case. ---- - rpm2archive.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/rpm2archive.c b/rpm2archive.c -index 09da8d16b..53f047f58 100644 ---- a/rpm2archive.c -+++ b/rpm2archive.c -@@ -241,10 +241,6 @@ int main(int argc, const char *argv[]) - exit(EXIT_FAILURE); - } - } -- if (argc < 2 || poptGetNextOpt(optCon) == 0) { -- poptPrintUsage(optCon, stderr, 0); -- exit(EXIT_FAILURE); -- } - - rpmts ts = rpmtsCreate(); - rpmVSFlags vsflags = 0; --- -2.38.1 - diff --git a/SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch b/SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch deleted file mode 100644 index 92c84ae..0000000 --- a/SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch +++ /dev/null @@ -1,138 +0,0 @@ -From d8a169164cf40fc1cf6448792c1fa991f19bb375 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Thu, 22 Apr 2021 14:50:34 +0200 -Subject: [PATCH] Add --nocompression option to rpm2archive - -Also use popt for the command line handling. As we are using librpm -anyway there is no reason to keep the dependencies low (as with -rpm2cpio). - -Resolves: #1530 ---- - doc/rpm2archive.8 | 16 ++++++++++--- - rpm2archive.c | 60 ++++++++++++++++++++++++++++++++++------------- - 2 files changed, 57 insertions(+), 19 deletions(-) - -diff --git a/rpm2archive.c b/rpm2archive.c -index d96db006ea..cb39c7a712 100644 ---- a/rpm2archive.c -+++ b/rpm2archive.c -@@ -10,6 +10,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -18,6 +20,16 @@ - - #define BUFSIZE (128*1024) - -+int compress = 1; -+ -+static struct poptOption optionsTable[] = { -+ { "nocompression", 'n', POPT_ARG_VAL, &compress, 0, -+ N_("create uncompressed tar file"), -+ NULL }, -+ POPT_AUTOHELP -+ POPT_TABLEEND -+}; -+ - static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi) - { - archive_entry_clear(entry); -@@ -60,7 +72,7 @@ static void write_file_content(struct archive * a, char * buf, rpmfi fi) - } - } - --static int process_package(rpmts ts, char * filename) -+static int process_package(rpmts ts, const char * filename) - { - FD_t fdi; - FD_t gzdi; -@@ -119,9 +131,11 @@ static int process_package(rpmts ts, char * filename) - - /* create archive */ - a = archive_write_new(); -- if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { -- fprintf(stderr, "Error: Could not create gzip output filter\n"); -- exit(EXIT_FAILURE); -+ if (compress) { -+ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { -+ fprintf(stderr, "%s\n", archive_error_string(a)); -+ exit(EXIT_FAILURE); -+ } - } - if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) { - fprintf(stderr, "Error: Format pax restricted is not supported\n"); -@@ -142,7 +156,12 @@ static int process_package(rpmts ts, char * filename) - } - archive_write_open_fd(a, STDOUT_FILENO); - } else { -- char * outname = rstrscat(NULL, filename, ".tgz", NULL); -+ char * outname = rstrscat(NULL, filename, NULL); -+ if (compress) { -+ outname = rstrscat(&outname, ".tgz", NULL); -+ } else { -+ outname = rstrscat(&outname, ".tar", NULL); -+ } - if (archive_write_open_filename(a, outname) != ARCHIVE_OK) { - fprintf(stderr, "Error: Can't open output file: %s\n", outname); - exit(EXIT_FAILURE); -@@ -203,21 +222,22 @@ static int process_package(rpmts ts, char * filename) - return rc; - } - --int main(int argc, char *argv[]) -+int main(int argc, const char *argv[]) - { -- int rc = 0, i; -+ int rc = 0; -+ poptContext optCon; -+ const char *fn; - - xsetprogname(argv[0]); /* Portability call -- see system.h */ - rpmReadConfigFiles(NULL, NULL); - -- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { -- fprintf(stderr, "Usage: %s [file.rpm ...]\n", argv[0]); -+ optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); -+ poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); -+ if (argc < 2 || poptGetNextOpt(optCon) == 0) { -+ poptPrintUsage(optCon, stderr, 0); - exit(EXIT_FAILURE); - } - -- if (argc == 1) -- argv[argc++] = "-"; /* abuse NULL pointer at the end of argv */ -- - rpmts ts = rpmtsCreate(); - rpmVSFlags vsflags = 0; - -@@ -227,13 +247,21 @@ int main(int argc, char *argv[]) - vsflags |= RPMVSF_NOHDRCHK; - (void) rpmtsSetVSFlags(ts, vsflags); - -- for (i = 1; i < argc; i++) { -+ /* if no file name is given use stdin/stdout */ -+ if (!poptPeekArg(optCon)) { -+ rc = process_package(ts, "-"); -+ if (rc != 0) -+ goto exit; -+ } - -- rc = process_package(ts, argv[i]); -+ while ((fn = poptGetArg(optCon)) != NULL) { -+ rc = process_package(ts, fn); - if (rc != 0) -- return rc; -+ goto exit; - } - -+ exit: -+ poptFreeContext(optCon); - (void) rpmtsFree(ts); - return rc; - } diff --git a/SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch b/SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch deleted file mode 100644 index 0170c35..0000000 --- a/SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8f416b275a365426b07c75adfc017e0b18a85450 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Fri, 16 Dec 2022 15:45:20 +0100 -Subject: [PATCH] rpm2archive: Properly parse popt options - -and issue an error message for unknown options. Before unknown options -could mess up the argument parsing leading to reading and writing from -stdin/stdout. - -Thanks to Eva Mrakova and the Red Hat QE team for spotting this! ---- - rpm2archive.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/rpm2archive.c b/rpm2archive.c -index de1a17d2b..09da8d16b 100644 ---- a/rpm2archive.c -+++ b/rpm2archive.c -@@ -233,6 +233,14 @@ int main(int argc, const char *argv[]) - - optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); - poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); -+ while ((rc = poptGetNextOpt(optCon)) != -1) { -+ if (rc < 0) { -+ fprintf(stderr, "%s: %s\n", -+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS), -+ poptStrerror(rc)); -+ exit(EXIT_FAILURE); -+ } -+ } - if (argc < 2 || poptGetNextOpt(optCon) == 0) { - poptPrintUsage(optCon, stderr, 0); - exit(EXIT_FAILURE); --- -2.38.1 - diff --git a/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch b/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch deleted file mode 100644 index ee12010..0000000 --- a/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 2e61e5846f8301f85da9d30281538ea736d96fd0 Mon Sep 17 00:00:00 2001 -From: Michal Domonkos -Date: Tue, 7 Dec 2021 08:08:37 +0100 -Subject: [PATCH] Skip recorded symlinks in --setperms (RhBug:1900662) - -If a package contains a symlink in the buildroot which is declared as a -ghost or config file but is a regular file or directory on the system -where it's installed, a --setperms call will reset its permissions to -those of a symlink (777 on Linux), which almost certainly is not the -correct thing to do. - -To fix that, just skip files that were recorded as symlinks. - -This is a special case of a general issue in --setperms; since file -permission semantics may change depending on the file type, to stay on -the safe side, any (ghost or config) file whose type changes after -installation should probably be skipped. However, symlinks are the most -prominent case here, so let's just focus on that now and avoid adding -too much cleverness to a popt alias (this got us into trouble not too -long ago, see commits 38c2f6e and 0d83637). We may revisit this in the -eventual C implementation. ---- - rpmpopt.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/rpmpopt.in b/rpmpopt.in -index 67fcabfb1..e130a5d05 100644 ---- a/rpmpopt.in -+++ b/rpmpopt.in -@@ -44,6 +44,7 @@ rpm alias --scripts --qf '\ - --POPTdesc=$"list install/erase scriptlets from package(s)" - - rpm alias --setperms -q --qf '[\[ -L %{FILENAMES:shescape} \] || \ -+ \[ -n %{FILELINKTOS:shescape} \] || \ - ( \[ $((%{FILEFLAGS} & 2#1001000)) != 0 \] && \[ ! -e %{FILENAMES:shescape} \] ) || \ - chmod %7{FILEMODES:octal} %{FILENAMES:shescape}\n]' \ - --pipe "grep -v \(none\) | grep '^. -L ' | sed 's/chmod .../chmod /' | sh" \ --- -2.35.1 - diff --git a/SOURCES/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch b/SOURCES/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch deleted file mode 100644 index 7d4e85b..0000000 --- a/SOURCES/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch +++ /dev/null @@ -1,401 +0,0 @@ -From 82c53e4b7f720012a391d8f6e5da9ee3c4f22bed Mon Sep 17 00:00:00 2001 -From: Demi Marie Obenour -Date: Thu, 6 May 2021 18:34:45 -0400 -Subject: [PATCH] Validate and require subkey binding signatures on PGP public - keys - -All subkeys must be followed by a binding signature by the primary key -as per the OpenPGP RFC, enforce the presence and validity in the parser. - -The implementation is as kludgey as they come to work around our -simple-minded parser structure without touching API, to maximise -backportability. Store all the raw packets internally as we decode them -to be able to access previous elements at will, needed to validate ordering -and access the actual data. Add testcases for manipulated keys whose -import previously would succeed. - -Combined with: -5ff86764b17f31535cb247543a90dd739076ec38 -b5e8bc74b2b05aa557f663fe227b94d2bc64fbd8 -9f03f42e2614a68f589f9db8fe76287146522c0c -b6dffb6dc5ffa2ddc389743f0507876cab341315 (mem-leak fix) -ae3d2d234ae47ff85229d3fce97a266fa1aa5a61 (use-after-free fix) - -Fixes CVE-2021-3521. ---- - rpmio/rpmpgp.c | 122 +++++++++++++++--- - sign/rpmgensig.c | 2 +- - tests/Makefile.am | 3 + - tests/data/keys/CVE-2021-3521-badbind.asc | 25 ++++ - .../data/keys/CVE-2021-3521-nosubsig-last.asc | 25 ++++ - tests/data/keys/CVE-2021-3521-nosubsig.asc | 37 ++++++ - tests/rpmsigdig.at | 28 ++++ - 7 files changed, 224 insertions(+), 18 deletions(-) - create mode 100644 tests/data/keys/CVE-2021-3521-badbind.asc - create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig-last.asc - create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig.asc - -diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index 46cd0f31a..bd4992ec7 100644 ---- a/rpmio/rpmpgp.c -+++ b/rpmio/rpmpgp.c -@@ -511,7 +511,7 @@ pgpDigAlg pgpDigAlgFree(pgpDigAlg alg) - return NULL; - } - --static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, -+static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, - const uint8_t *p, const uint8_t *h, size_t hlen, - pgpDigParams sigp) - { -@@ -524,10 +524,8 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, - int mpil = pgpMpiLen(p); - if (p + mpil > pend) - break; -- if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) { -- if (sigalg->setmpi(sigalg, i, p)) -- break; -- } -+ if (sigalg->setmpi(sigalg, i, p)) -+ break; - p += mpil; - } - -@@ -600,7 +598,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, - } - - p = ((uint8_t *)v) + sizeof(*v); -- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); -+ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); - } break; - case 4: - { pgpPktSigV4 v = (pgpPktSigV4)h; -@@ -658,7 +656,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, - if (p > (h + hlen)) - return 1; - -- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); -+ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); - } break; - default: - rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version); -@@ -999,36 +997,127 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype) - return algo; - } - -+static pgpDigParams pgpDigParamsNew(uint8_t tag) -+{ -+ pgpDigParams digp = xcalloc(1, sizeof(*digp)); -+ digp->tag = tag; -+ return digp; -+} -+ -+static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag) -+{ -+ int rc = -1; -+ if (pkt->tag == exptag) { -+ uint8_t head[] = { -+ 0x99, -+ (pkt->blen >> 8), -+ (pkt->blen ), -+ }; -+ -+ rpmDigestUpdate(hash, head, 3); -+ rpmDigestUpdate(hash, pkt->body, pkt->blen); -+ rc = 0; -+ } -+ return rc; -+} -+ -+static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig, -+ const struct pgpPkt *all, int i) -+{ -+ int rc = -1; -+ DIGEST_CTX hash = NULL; -+ -+ switch (selfsig->sigtype) { -+ case PGPSIGTYPE_SUBKEY_BINDING: -+ hash = rpmDigestInit(selfsig->hash_algo, 0); -+ if (hash) { -+ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY); -+ if (!rc) -+ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY); -+ } -+ break; -+ default: -+ /* ignore types we can't handle */ -+ rc = 0; -+ break; -+ } -+ -+ if (hash && rc == 0) -+ rc = pgpVerifySignature(key, selfsig, hash); -+ -+ rpmDigestFinal(hash, NULL, NULL, 0); -+ -+ return rc; -+} -+ - int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, - pgpDigParams * ret) - { - const uint8_t *p = pkts; - const uint8_t *pend = pkts + pktlen; - pgpDigParams digp = NULL; -- struct pgpPkt pkt; -+ pgpDigParams selfsig = NULL; -+ int i = 0; -+ int alloced = 16; /* plenty for normal cases */ -+ struct pgpPkt *all = xmalloc(alloced * sizeof(*all)); - int rc = -1; /* assume failure */ -+ int expect = 0; -+ int prevtag = 0; - - while (p < pend) { -- if (decodePkt(p, (pend - p), &pkt)) -+ struct pgpPkt *pkt = &all[i]; -+ if (decodePkt(p, (pend - p), pkt)) - break; - - if (digp == NULL) { -- if (pkttype && pkt.tag != pkttype) { -+ if (pkttype && pkt->tag != pkttype) { - break; - } else { -- digp = xcalloc(1, sizeof(*digp)); -- digp->tag = pkt.tag; -+ digp = pgpDigParamsNew(pkt->tag); - } - } - -- if (pgpPrtPkt(&pkt, digp)) -+ if (expect) { -+ if (pkt->tag != expect) -+ break; -+ selfsig = pgpDigParamsNew(pkt->tag); -+ } -+ -+ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp)) - break; - -- p += (pkt.body - pkt.head) + pkt.blen; -+ if (selfsig) { -+ /* subkeys must be followed by binding signature */ -+ int xx = 1; /* assume failure */ -+ -+ if (!(prevtag == PGPTAG_PUBLIC_SUBKEY && -+ selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING)) -+ xx = pgpVerifySelf(digp, selfsig, all, i); -+ -+ selfsig = pgpDigParamsFree(selfsig); -+ if (xx) -+ break; -+ expect = 0; -+ } -+ -+ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY) -+ expect = PGPTAG_SIGNATURE; -+ prevtag = pkt->tag; -+ -+ i++; -+ p += (pkt->body - pkt->head) + pkt->blen; -+ if (pkttype == PGPTAG_SIGNATURE) -+ break; -+ -+ if (alloced <= i) { -+ alloced *= 2; -+ all = xrealloc(all, alloced * sizeof(*all)); -+ } - } - -- rc = (digp && (p == pend)) ? 0 : -1; -+ rc = (digp && (p == pend) && expect == 0) ? 0 : -1; - -+ free(all); - if (ret && rc == 0) { - *ret = digp; - } else { -@@ -1063,8 +1152,7 @@ int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen, - digps = xrealloc(digps, alloced * sizeof(*digps)); - } - -- digps[count] = xcalloc(1, sizeof(**digps)); -- digps[count]->tag = PGPTAG_PUBLIC_SUBKEY; -+ digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY); - /* Copy UID from main key to subkey */ - digps[count]->userid = xstrdup(mainkey->userid); - -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index 771d01098..b33fe996c 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -409,7 +409,7 @@ static int haveSignature(rpmtd sigtd, Header h) - pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2); - if (pgpDigParamsCmp(sig1, sig2) == 0) - rc = 1; -- pgpDigParamsFree(sig2); -+ sig2 = pgpDigParamsFree(sig2); - } - pgpDigParamsFree(sig1); - rpmtdFreeData(&oldtd); -diff --git a/tests/Makefile.am b/tests/Makefile.am -index 5f5207e56..309347262 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -87,6 +87,9 @@ EXTRA_DIST += data/SPECS/hello-config-buildid.spec - EXTRA_DIST += data/SPECS/hello-cd.spec - EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub - EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret -+EXTRA_DIST += data/keys/CVE-2021-3521-badbind.asc -+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig.asc -+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig-last.asc - EXTRA_DIST += data/macros.testfile - - # testsuite voodoo -diff --git a/tests/data/keys/CVE-2021-3521-badbind.asc b/tests/data/keys/CVE-2021-3521-badbind.asc -new file mode 100644 -index 000000000..aea00f9d7 ---- /dev/null -+++ b/tests/data/keys/CVE-2021-3521-badbind.asc -@@ -0,0 +1,25 @@ -+-----BEGIN PGP PUBLIC KEY BLOCK----- -+Version: rpm-4.17.90 (NSS-3) -+ -+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g -+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY -+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 -+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas -+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ -+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl -+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK -+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf -+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB -+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr -+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX -+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq -++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN -+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY -+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz -+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 -+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c -+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m -+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= -+=WCfs -+-----END PGP PUBLIC KEY BLOCK----- -+ -diff --git a/tests/data/keys/CVE-2021-3521-nosubsig-last.asc b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc -new file mode 100644 -index 000000000..aea00f9d7 ---- /dev/null -+++ b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc -@@ -0,0 +1,25 @@ -+-----BEGIN PGP PUBLIC KEY BLOCK----- -+Version: rpm-4.17.90 (NSS-3) -+ -+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g -+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY -+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 -+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas -+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ -+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl -+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK -+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf -+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB -+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr -+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX -+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq -++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN -+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY -+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz -+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 -+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c -+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m -+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= -+=WCfs -+-----END PGP PUBLIC KEY BLOCK----- -+ -diff --git a/tests/data/keys/CVE-2021-3521-nosubsig.asc b/tests/data/keys/CVE-2021-3521-nosubsig.asc -new file mode 100644 -index 000000000..3a2e7417f ---- /dev/null -+++ b/tests/data/keys/CVE-2021-3521-nosubsig.asc -@@ -0,0 +1,37 @@ -+-----BEGIN PGP PUBLIC KEY BLOCK----- -+Version: rpm-4.17.90 (NSS-3) -+ -+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g -+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY -+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 -+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas -+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ -+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl -+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK -+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf -+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB -+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr -+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX -+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq -++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN -+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY -+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz -+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 -+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c -+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m -+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAG5AQ0EWOY5GAEIAKT68NmshdC4 -+VcRhOhlXBvZq23NtskkKoPvW+ZlMuxbRDG48pGBtxhjOngriVUGceEWsXww5Q7En -+uRBYglkxkW34ENym0Ji6tsPYfhbbG+dZWKIL4vMIzPOIwlPrXrm558vgkdMM/ELZ -+8WIz3KtzvYubKUk2Qz+96lPXbwnlC/SBFRpBseJC5LoOb/5ZGdR/HeLz1JXiacHF -+v9Nr3cZWqg5yJbDNZKfASdZgC85v3kkvhTtzknl//5wqdAMexbuwiIh2xyxbO+B/ -+qqzZFrVmu3sV2Tj5lLZ/9p1qAuEM7ULbixd/ld8yTmYvQ4bBlKv2bmzXtVfF+ymB -+Tm6BzyQEl/MAEQEAAYkBHwQYAQgACQUCWOY5GAIbDAAKCRBDRFkeGWTF/PANB/9j -+mifmj6z/EPe0PJFhrpISt9PjiUQCt0IPtiL5zKAkWjHePIzyi+0kCTBF6DDLFxos -+3vN4bWnVKT1kBhZAQlPqpJTg+m74JUYeDGCdNx9SK7oRllATqyu+5rncgxjWVPnQ -+zu/HRPlWJwcVFYEVXYL8xzfantwQTqefjmcRmBRdA2XJITK+hGWwAmrqAWx+q5xX -+Pa8wkNMxVzNS2rUKO9SoVuJ/wlUvfoShkJ/VJ5HDp3qzUqncADfdGN35TDzscngQ -+gHvnMwVBfYfSCABV1hNByoZcc/kxkrWMmsd/EnIyLd1Q1baKqc3cEDuC6E6/o4yJ -+E4XX4jtDmdZPreZALsiB -+=rRop -+-----END PGP PUBLIC KEY BLOCK----- -+ -diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at -index 09fcdd525..a74f400ae 100644 ---- a/tests/rpmsigdig.at -+++ b/tests/rpmsigdig.at -@@ -212,6 +212,34 @@ UNW2iqnN3BA7guhOv6OMiROF1+I7Q5nWT63mQC7IgQ== - []) - AT_CLEANUP - -+AT_SETUP([rpmkeys --import invalid keys]) -+AT_KEYWORDS([rpmkeys import]) -+RPMDB_INIT -+ -+AT_CHECK([ -+runroot rpmkeys --import /data/keys/CVE-2021-3521-badbind.asc -+], -+[1], -+[], -+[error: /data/keys/CVE-2021-3521-badbind.asc: key 1 import failed.] -+) -+AT_CHECK([ -+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig.asc -+], -+[1], -+[], -+[error: /data/keys/CVE-2021-3521-nosubsig.asc: key 1 import failed.] -+) -+ -+AT_CHECK([ -+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig-last.asc -+], -+[1], -+[], -+[error: /data/keys/CVE-2021-3521-nosubsig-last.asc: key 1 import failed.] -+) -+AT_CLEANUP -+ - # ------------------------------ - # Test pre-built package verification - AT_SETUP([rpmkeys -K 1]) --- -2.34.1 - diff --git a/SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch b/SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch deleted file mode 100644 index 4a8a6f5..0000000 --- a/SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch +++ /dev/null @@ -1,51 +0,0 @@ -From f1634250587479d664b34b6de1a6546b2c2b9de5 Mon Sep 17 00:00:00 2001 -From: Florian Festi -Date: Mon, 18 Jan 2021 15:02:34 +0100 -Subject: [PATCH] rpm2archive: Add more error handling - -Cleanly error out if file can't be written instead of segfaulting - -Resolves: #1091 ---- - rpm2archive.c | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/rpm2archive.c b/rpm2archive.c -index 646f1663d..15c5da016 100644 ---- a/rpm2archive.c -+++ b/rpm2archive.c -@@ -119,9 +119,14 @@ static int process_package(rpmts ts, char * filename) - - /* create archive */ - a = archive_write_new(); -- archive_write_add_filter_gzip(a); -- archive_write_set_format_pax_restricted(a); -- -+ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { -+ fprintf(stderr, "Error: Could not create gzip output filter\n"); -+ exit(EXIT_FAILURE); -+ } -+ if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) { -+ fprintf(stderr, "Error: Format pax restricted is not supported\n"); -+ exit(EXIT_FAILURE); -+ } - if (!strcmp(filename, "-")) { - if (isatty(STDOUT_FILENO)) { - fprintf(stderr, "Error: refusing to output archive data to a terminal.\n"); -@@ -130,9 +135,11 @@ static int process_package(rpmts ts, char * filename) - archive_write_open_fd(a, STDOUT_FILENO); - } else { - char * outname = rstrscat(NULL, filename, ".tgz", NULL); -- archive_write_open_filename(a, outname); -+ if (archive_write_open_filename(a, outname) != ARCHIVE_OK) { -+ fprintf(stderr, "Error: Can't open output file: %s\n", outname); -+ exit(EXIT_FAILURE); -+ } - _free(outname); -- // XXX error handling - } - - entry = archive_entry_new(); --- -2.38.1 - diff --git a/SOURCES/rpm-4.7.1-geode-i686.patch b/SOURCES/rpm-4.7.1-geode-i686.patch deleted file mode 100644 index 2e8692a..0000000 --- a/SOURCES/rpm-4.7.1-geode-i686.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/rpmrc.in b/rpmrc.in -index 4a6cca9..d62ddaf 100644 ---- a/rpmrc.in -+++ b/rpmrc.in -@@ -281,7 +281,7 @@ arch_compat: alphaev5: alpha - arch_compat: alpha: axp noarch - - arch_compat: athlon: i686 --arch_compat: geode: i586 -+arch_compat: geode: i686 - arch_compat: pentium4: pentium3 - arch_compat: pentium3: i686 - arch_compat: i686: i586 - diff --git a/SOURCES/rpm-4.8.1-use-gpg2.patch b/SOURCES/rpm-4.8.1-use-gpg2.patch deleted file mode 100644 index 61ef55e..0000000 --- a/SOURCES/rpm-4.8.1-use-gpg2.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.8.1/macros.in.gpg2 rpm-4.8.1/macros.in ---- rpm-4.8.0/macros.in.gpg2 2011-01-17 12:17:38.000000000 +0200 -+++ rpm-4.8.0/macros.in 2011-01-17 12:17:59.000000000 +0200 -@@ -40,7 +40,7 @@ - %__cp @__CP@ - %__cpio @__CPIO@ - %__file @__FILE@ --%__gpg @__GPG@ -+%__gpg /usr/bin/gpg2 - %__grep @__GREP@ - %__gzip @__GZIP@ - %__id @__ID@ diff --git a/SOURCES/rpm-4.9.90-no-man-dirs.patch b/SOURCES/rpm-4.9.90-no-man-dirs.patch deleted file mode 100644 index 04f276a..0000000 --- a/SOURCES/rpm-4.9.90-no-man-dirs.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs rpm-4.9.90.git11486/scripts/find-lang.sh ---- rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs 2012-03-07 11:31:10.000000000 +0200 -+++ rpm-4.9.90.git11486/scripts/find-lang.sh 2012-03-07 15:11:57.465801075 +0200 -@@ -181,7 +181,7 @@ s:%lang(C) :: - find "$TOP_DIR" -type d|sed ' - s:'"$TOP_DIR"':: - '"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+/\):: --'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1*: -+'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1/*: - s:^\([^%].*\):: - s:%lang(C) :: - /^$/d' >> $MO_NAME diff --git a/SPECS/rpm.spec b/SPECS/rpm.spec deleted file mode 100644 index ec4a51f..0000000 --- a/SPECS/rpm.spec +++ /dev/null @@ -1,2626 +0,0 @@ -# build against xz? -%bcond_without xz -# just for giggles, option to build with internal Berkeley DB -%bcond_with int_bdb -# run internal testsuite? -%bcond_with check -# build with plugins? -%bcond_without plugins -# build with sanitizers? -%bcond_with sanitizer -# build with libarchive? (needed for rpm2archive) -%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_without ndb -# build with zstd support? -%bcond_without zstd -# build with lmdb support? -%bcond_with lmdb -# build with readonly sqlite support? -%bcond_without sqlite - -%if 0%{?rhel} > 7 -# Disable python2 build by default -%bcond_with python2 -%else -%bcond_without python2 -%endif - -%define rpmhome /usr/lib/rpm - -%global rpmver 4.14.3 -#global snapver rc2 -%global rel 26.3 - -%global srcver %{version}%{?snapver:-%{snapver}} -%global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} - -%define bdbname libdb -%define bdbver 5.3.15 -%define dbprefix db - -Summary: The RPM package management system -Name: rpm -Version: %{rpmver} -Release: %{?snapver:0.%{snapver}.}%{rel}%{?dist} -Group: System Environment/Base -Url: http://www.rpm.org/ -Source0: http://ftp.rpm.org/releases/%{srcdir}/%{name}-%{srcver}.tar.bz2 -%if %{with int_bdb} -Source1: db-%{bdbver}.tar.gz -%else -BuildRequires: libdb-devel -%endif - -# Disable autoconf config.site processing (#962837) -Patch1: rpm-4.11.x-siteconfig.patch -# Fedora specspo is setup differently than what rpm expects, considering -# this as Fedora-specific patch for now -Patch2: rpm-4.13.0-fedora-specspo.patch -# In current Fedora, man-pages pkg owns all the localized man directories -Patch3: rpm-4.9.90-no-man-dirs.patch -# gnupg2 comes installed by default, avoid need to drag in gnupg too -Patch4: rpm-4.8.1-use-gpg2.patch -# Temporary band-aid for rpm2cpio whining on payload size mismatch (#1142949) -Patch5: rpm-4.12.0-rpm2cpio-hack.patch - -# Downstream-only patch: -# Add envvar that will be present during RPM build -# - Part of a Fedora Change for F28: -# - "Avoid /usr/bin/python in RPM build" -# - https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build -Patch7: rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch - -# Patches already upstream: -Patch101: rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch -Patch102: 0001-Document-noverify-in-the-man-page-RhBug-1646458.patch -Patch104: 0001-Mark-elements-with-associated-problems-as-failed.patch -Patch108: 0001-Only-read-through-payload-on-verify-if-actually-need.patch -Patch111: 0003-Verify-packages-before-signing-RhBug-1646388.patch -Patch112: 0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch -Patch116: 0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch -Patch119: 0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch -Patch132: 0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch -Patch133: 0002-Handle-.debug_macro-in-debugedit.patch -Patch134: 0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch -Patch135: 0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch -Patch136: 0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch -Patch137: 0001-Fix-brp-strip-static-archive-parallelism.patch -Patch138: 0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch -Patch139: 0001-Make-check-buildroot-check-the-build-files-in-parall.patch -Patch140: 0001-Fix-resource-leaks-on-zstd-open-error-paths.patch -# XXX should be before 0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch -Patch141: 0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch -Patch142: rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch -Patch143: 0001-Work-around-buggy-signature-region-preventing-resign.patch -Patch144: 0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch -Patch145: 0001-Always-close-libelf-handle-1313.patch -Patch146: 0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch -Patch147: 0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch -Patch148: 0001-Add-limits-to-autopatch-macro.patch -Patch149: rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch -Patch150: rpm-4.14.3-add-fapolicyd-rpm-plugin.patch -Patch151: 0001-Unblock-signals-in-forked-scriptlets.patch -Patch152: rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch -Patch153: rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch -Patch154: rpm-4.14.3-more-careful-sig-hdr-copy.patch -Patch156: rpm-4.14.3-hdrblobInit-add-bounds-check.patch -Patch157: rpm-4.14.3-add-read-only-support-for-sqlite.patch -Patch158: rpm-4.14.3-imp-covscan-fixes.patch -Patch159: rpm-4.14.3-add-path-query-option.patch -Patch160: rpm-4.14.3-macroize-find-debuginfo-script-location.patch -Patch161: rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch -Patch162: rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch -Patch163: rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch -Patch164: rpm-4.14.3-fapolicyd-make-write-nonblocking.patch -Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch -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 - -# Python 3 string API sanity -Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch -Patch501: 0001-Return-NULL-string-as-None-from-utf8FromString.patch -# Make test-suite work with Python 3 -Patch503: 0001-Honor-PYTHON-from-configure-when-running-tests.patch -Patch504: 0002-Use-Python-3-compatible-exception-syntax-in-tests.patch -Patch505: 0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch -Patch506: 0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch -Patch507: 0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch -Patch508: rpm-4.14.3-python3.diff -Patch509: rpm-4-14.3-selinux-log-error.patch - -# These are not yet upstream -# Audit support -Patch800: rpm-4.14.2-audit-3.patch - -Patch906: rpm-4.7.1-geode-i686.patch -# Probably to be upstreamed in slightly different form -Patch907: rpm-4.13.90-ldflags.patch - -# Switch off the part of the brp-python-bytecompile script -# that utilizes python2 to bytecompile .py files within -# non-standard paths. -Patch1000: disable-python-extra.patch - -# Compile Python 3.6 stuff with /usr/libexec/platform-python instead of -# /usr/bin/python3.6 -Patch1001: compile-with-Platform-Python-binary-where-relevant.patch -# make unversioned %%__python an error unless explicitly overridden -Patch1002: rpm-4.14.2-unversioned-python.patch - -%if %{with zstd} -# multithreaded zstd compression -Patch1003: 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+ - -Requires: coreutils -%if %{without int_bdb} -# db recovery tools, rpmdb_util symlinks -Requires: %{_bindir}/%{dbprefix}_stat -%endif -Requires: popt%{_isa} >= 1.10.2.1 -Requires: curl - -%if %{without int_bdb} -BuildRequires: %{bdbname}-devel -%endif - -%if %{with check} -BuildRequires: fakechroot gnupg2 -%endif - -# XXX generally assumed to be installed but make it explicit as rpm -# is a bit special... -BuildRequires: redhat-rpm-config -BuildRequires: gcc make -BuildRequires: gawk -BuildRequires: elfutils-devel >= 0.112 -BuildRequires: elfutils-libelf-devel -BuildRequires: readline-devel zlib-devel -BuildRequires: openssl-devel -# The popt version here just documents an older known-good version -BuildRequires: popt-devel >= 1.10.2 -BuildRequires: file-devel -BuildRequires: gettext-devel -BuildRequires: ncurses-devel -BuildRequires: bzip2-devel >= 0.9.0c-2 -BuildRequires: lua-devel >= 5.1 -BuildRequires: libcap-devel -BuildRequires: libacl-devel -BuildRequires: audit-libs-devel -%if %{with sqlite} -BuildRequires: sqlite-devel -%endif -%if %{with xz} -BuildRequires: xz-devel >= 4.999.8 -%endif -%if %{with libarchive} -BuildRequires: libarchive-devel -%endif -%if %{with zstd} -BuildRequires: libzstd-devel -%endif -%if %{with lmdb} -BuildRequires: lmdb-devel -%endif -# Only required by sepdebugcrcfix patch -BuildRequires: binutils-devel -# Couple of patches change makefiles so, require for now... -BuildRequires: automake libtool - -%if %{with plugins} -BuildRequires: libselinux-devel -BuildRequires: dbus-devel -%endif - -%if %{with sanitizer} -BuildRequires: libasan -BuildRequires: libubsan -#BuildRequires: liblsan -#BuildRequires: libtsan -%global sanitizer_flags -fsanitize=address -fsanitize=undefined -%endif - -%if %{with libimaevm} -%if 0%{?fedora} >= 28 || 0%{?rhel} > 7 -%global imadevname ima-evm-utils-devel -%else -%global imadevname ima-evm-utils -%endif -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, -verifying, querying, and updating software packages. Each software -package consists of an archive of files along with information about -the package like its version, a description, etc. - -%package libs -Summary: Libraries for manipulating RPM packages -Group: Development/Libraries -License: GPLv2+ and LGPLv2+ with exceptions -Requires: %{name} = %{version}-%{release} -# librpm uses cap_compare, introduced sometimes between libcap 2.10 and 2.16. -# A manual require is needed, see #505596 -Requires: libcap%{_isa} >= 2.16 - -%description libs -This package contains the RPM shared libraries. - -%package build-libs -Summary: Libraries for building and signing RPM packages -Group: Development/Libraries -License: GPLv2+ and LGPLv2+ with exceptions -Requires: rpm-libs%{_isa} = %{version}-%{release} -Requires: %{_bindir}/gpg2 - -%description build-libs -This package contains the RPM shared libraries for building and signing -packages. - -%package devel -Summary: Development files for manipulating RPM packages -Group: Development/Libraries -License: GPLv2+ and LGPLv2+ with exceptions -Requires: %{name} = %{version}-%{release} -Requires: %{name}-libs%{_isa} = %{version}-%{release} -Requires: %{name}-build-libs%{_isa} = %{version}-%{release} -Requires: popt-devel%{_isa} - -%description devel -This package contains the RPM C library and header files. These -development files will simplify the process of writing programs that -manipulate RPM packages and databases. These files are intended to -simplify the process of creating graphical package managers or any -other tools that need an intimate knowledge of RPM packages in order -to function. - -This package should be installed if you want to develop programs that -will manipulate RPM packages and databases. - -%package build -Summary: Scripts and executable programs used to build packages -Group: Development/Tools -Requires: rpm = %{version}-%{release} -Requires: elfutils >= 0.128 binutils -Requires: findutils sed grep gawk diffutils file patch >= 2.5 -Requires: tar unzip gzip bzip2 cpio xz -%if %{with zstd} -Requires: zstd >= 1.3.8 -%endif -Requires: pkgconfig >= 1:0.24 -Requires: /usr/bin/gdb-add-index -# Technically rpmbuild doesn't require any external configuration, but -# creating distro-compatible packages does. To make the common case -# "just work" while allowing for alternatives, depend on a virtual -# provide, typically coming from redhat-rpm-config. -Requires: system-rpm-config - -%description build -The rpm-build package contains the scripts and executable programs -that are used to build packages using the RPM Package Manager. - -%package sign -Summary: Package signing support -Group: System Environment/Base -Requires: rpm-build-libs%{_isa} = %{version}-%{release} - -%description sign -This package contains support for digitally signing RPM packages. - -%if %{with python2} -%package -n python2-%{name} -Summary: Python 2 bindings for apps which will manipulate RPM packages -Group: Development/Libraries -BuildRequires: python2-devel -%{?python_provide:%python_provide python2-%{name}} -Requires: %{name}-libs%{?_isa} = %{version}-%{release} -Provides: %{name}-python = %{version}-%{release} -Obsoletes: %{name}-python < %{version}-%{release} - -%description -n python2-%{name} -The python2-rpm package contains a module that permits applications -written in the Python programming language to use the interface -supplied by RPM Package Manager libraries. - -This package should be installed if you want to develop Python 2 -programs that will manipulate RPM packages and databases. -%endif # with python2 - -%package -n python3-%{name} -Summary: Python 3 bindings for apps which will manipulate RPM packages -Group: Development/Libraries -BuildRequires: python3-devel -%{?python_provide:%python_provide python3-%{name}} -Requires: %{name}-libs%{?_isa} = %{version}-%{release} -Provides: %{name}-python3 = %{version}-%{release} -Obsoletes: %{name}-python3 < %{version}-%{release} -# Lowest compatible DNF version (acts as a safeguard to protect DNF from -# breaking in case the user attempts to upgrade RPM separately). -# Version 4.2.7 added support for the new API output format introduced in -# rpm-4.14.2-10. -Conflicts: python3-dnf < 4.2.7 - -%description -n python3-%{name} -The python3-rpm package contains a module that permits applications -written in the Python programming language to use the interface -supplied by RPM Package Manager libraries. - -This package should be installed if you want to develop Python 3 -programs that will manipulate RPM packages and databases. - -%package apidocs -Summary: API documentation for RPM libraries -Group: Documentation -BuildArch: noarch - -%description apidocs -This package contains API documentation for developing applications -that will manipulate RPM packages and databases. - -%package cron -Summary: Create daily logs of installed packages. -Group: System Environment/Base -BuildArch: noarch -Requires: crontabs logrotate rpm = %{version}-%{release} - -%description cron -This package contains a cron job which creates daily logs of installed -packages on a system. - -%if %{with plugins} -%package plugin-selinux -Summary: Rpm plugin for SELinux functionality -Group: System Environment/Base -Requires: rpm-libs%{_isa} = %{version}-%{release} -Requires: selinux-policy-base - -%description plugin-selinux -%{summary} - -%package plugin-syslog -Summary: Rpm plugin for syslog functionality -Group: System Environment/Base -Requires: rpm-libs%{_isa} = %{version}-%{release} - -%description plugin-syslog -%{summary} - -%package plugin-systemd-inhibit -Summary: Rpm plugin for systemd inhibit functionality -Group: System Environment/Base -Requires: rpm-libs%{_isa} = %{version}-%{release} - -%description plugin-systemd-inhibit -This plugin blocks systemd from entering idle, sleep or shutdown while an rpm -transaction is running using the systemd-inhibit mechanism. - -%package plugin-ima -Summary: Rpm plugin ima file signatures -Group: System Environment/Base -Requires: rpm-libs%{_isa} = %{version}-%{release} - -%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 -Requires: rpm-libs%{_isa} = %{version}-%{release} - -%description plugin-prioreset -%{summary} - -Useful on legacy SysV init systems if you run rpm transactions with -nice/ionice priorities. Should not be used on systemd systems. - -%package plugin-fapolicyd -Summary: Rpm plugin for fapolicyd functionality -Requires: rpm-libs%{_isa} = %{version}-%{release} -Provides: fapolicyd-plugin -Obsoletes: fapolicyd-dnf-plugin - -%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 -%autosetup -n %{name}-%{srcver} %{?with_int_bdb:-a 1} -p1 - -%if %{with int_bdb} -ln -s db-%{bdbver} db -%endif - -%build -%if %{without int_bdb} -#CPPFLAGS=-I%{_includedir}/db%{bdbver} -#LDFLAGS=-L%{_libdir}/db%{bdbver} -%endif -CPPFLAGS="$CPPFLAGS -DLUA_COMPAT_APIINTCASTS" -CFLAGS="$RPM_OPT_FLAGS %{?sanitizer_flags} -DLUA_COMPAT_APIINTCASTS" -LDFLAGS="$LDFLAGS %{?__global_ldflags}" -export CPPFLAGS CFLAGS LDFLAGS - -autoreconf -i -f - -# Hardening hack taken from macro %%configure defined in redhat-rpm-config -for i in $(find . -name ltmain.sh) ; do - %{__sed} -i.backup -e 's~compiler_flags=$~compiler_flags="%{_hardened_ldflags}"~' $i -done; - -# Using configure macro has some unwanted side-effects on rpm platform -# setup, use the old-fashioned way for now only defining minimal paths. -./configure \ - --prefix=%{_usr} \ - --sysconfdir=%{_sysconfdir} \ - --localstatedir=%{_var} \ - --sharedstatedir=%{_var}/lib \ - --libdir=%{_libdir} \ - --build=%{_target_platform} \ - --host=%{_target_platform} \ - --with-vendor=redhat \ - %{!?with_int_bdb: --with-external-db} \ - %{!?with_plugins: --disable-plugins} \ - --with-lua \ - --with-selinux \ - --with-cap \ - --with-acl \ - %{?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} \ - --with-fapolicyd \ - --enable-python \ - --with-crypto=openssl \ - PYTHON=python3 - -make %{?_smp_mflags} - -pushd python -%if %{with python2} -%{__python2} setup.py build -%endif # with python2 -%{__python3} setup.py build -popd - -%install -rm -rf $RPM_BUILD_ROOT - -make DESTDIR="$RPM_BUILD_ROOT" install - -# We need to build with --enable-python for the self-test suite, but we -# actually package the bindings built with setup.py (#531543#c26) -pushd python -%if %{with python2} -%{__python2} setup.py install --skip-build --root $RPM_BUILD_ROOT -%endif # with python2 -%{__python3} setup.py install --skip-build --root $RPM_BUILD_ROOT -popd - - -# Save list of packages through cron -mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/cron.daily -install -m 755 scripts/rpm.daily ${RPM_BUILD_ROOT}%{_sysconfdir}/cron.daily/rpm - -mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d -install -m 644 scripts/rpm.log ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/rpm - -mkdir -p ${RPM_BUILD_ROOT}/usr/lib/tmpfiles.d -echo "r /var/lib/rpm/__db.*" > ${RPM_BUILD_ROOT}/usr/lib/tmpfiles.d/rpm.conf - -mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm -mkdir -p $RPM_BUILD_ROOT%{rpmhome}/macros.d - -mkdir -p $RPM_BUILD_ROOT/var/lib/rpm -for dbi in \ - Basenames Conflictname Dirnames Group Installtid Name Obsoletename \ - Packages Providename Requirename Triggername Sha1header Sigmd5 \ - __db.001 __db.002 __db.003 __db.004 __db.005 __db.006 __db.007 \ - __db.008 __db.009 -do - touch $RPM_BUILD_ROOT/var/lib/rpm/$dbi -done - -# plant links to relevant db utils as rpmdb_foo for documention compatibility -%if %{without int_bdb} -for dbutil in dump load recover stat upgrade verify -do - ln -s ../../bin/%{dbprefix}_${dbutil} $RPM_BUILD_ROOT/%{rpmhome}/rpmdb_${dbutil} -done -%endif - -%find_lang %{name} - -find $RPM_BUILD_ROOT -name "*.la"|xargs rm -f - -# These live in perl-generators and python-rpm-generators now -rm -f $RPM_BUILD_ROOT/%{rpmhome}/{perldeps.pl,perl.*,pythond*} -rm -f $RPM_BUILD_ROOT/%{_fileattrsdir}/{perl*,python*} -# Axe unused cruft -rm -f $RPM_BUILD_ROOT/%{rpmhome}/{tcl.req,osgideps.pl} - -# Avoid unnecessary dependency on /usr/bin/python -chmod a-x $RPM_BUILD_ROOT/%{rpmhome}/python-macro-helper - -%if %{with check} -%check -make check || cat tests/rpmtests.log -%endif - -%post libs -p /sbin/ldconfig -%postun libs -p /sbin/ldconfig - -%post build-libs -p /sbin/ldconfig -%postun build-libs -p /sbin/ldconfig - -%files -f %{name}.lang -%license COPYING -%doc CREDITS doc/manual/[a-z]* - -/usr/lib/tmpfiles.d/rpm.conf -%dir %{_sysconfdir}/rpm - -%attr(0755, root, root) %dir /var/lib/rpm -%attr(0644, root, root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/rpm/* - -%{_bindir}/rpm -%if %{with libarchive} -%{_bindir}/rpm2archive -%endif -%{_bindir}/rpm2cpio -%{_bindir}/rpmdb -%{_bindir}/rpmkeys -%{_bindir}/rpmquery -%{_bindir}/rpmverify - -%{_mandir}/man8/rpm.8* -%{_mandir}/man8/rpmdb.8* -%{_mandir}/man8/rpmkeys.8* -%{_mandir}/man8/rpm2cpio.8* -%{_mandir}/man8/rpm-misc.8* - -# XXX this places translated manuals to wrong package wrt eg rpmbuild -%lang(fr) %{_mandir}/fr/man[18]/*.[18]* -%lang(ko) %{_mandir}/ko/man[18]/*.[18]* -%lang(ja) %{_mandir}/ja/man[18]/*.[18]* -%lang(pl) %{_mandir}/pl/man[18]/*.[18]* -%lang(ru) %{_mandir}/ru/man[18]/*.[18]* -%lang(sk) %{_mandir}/sk/man[18]/*.[18]* - -%attr(0755, root, root) %dir %{rpmhome} -%{rpmhome}/macros -%{rpmhome}/macros.d -%{rpmhome}/rpmpopt* -%{rpmhome}/rpmrc - -%{rpmhome}/rpmdb_* -%{rpmhome}/rpm.daily -%{rpmhome}/rpm.log -%{rpmhome}/rpm.supp -%{rpmhome}/rpm2cpio.sh -%{rpmhome}/tgpg -%{rpmhome}/python-macro-helper - -%{rpmhome}/platform - -%dir %{rpmhome}/fileattrs - -%files libs -%{_libdir}/librpmio.so.* -%{_libdir}/librpm.so.* -%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 - -%files plugin-selinux -%{_libdir}/rpm-plugins/selinux.so - -%files plugin-systemd-inhibit -%{_libdir}/rpm-plugins/systemd_inhibit.so -%{_mandir}/man8/rpm-plugin-systemd-inhibit.8* - -%files plugin-ima -%{_libdir}/rpm-plugins/ima.so - -%files plugin-prioreset -%{_libdir}/rpm-plugins/prioreset.so - -%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 -%{_libdir}/librpmbuild.so.* -%{_libdir}/librpmsign.so.* - -%files build -%{_bindir}/rpmbuild -%{_bindir}/gendiff -%{_bindir}/rpmspec - -%{_mandir}/man1/gendiff.1* -%{_mandir}/man8/rpmbuild.8* -%{_mandir}/man8/rpmdeps.8* -%{_mandir}/man8/rpmspec.8* - -%{rpmhome}/brp-* -%{rpmhome}/check-* -%{rpmhome}/debugedit -%{rpmhome}/sepdebugcrcfix -%{rpmhome}/find-debuginfo.sh -%{rpmhome}/find-lang.sh -%{rpmhome}/*provides* -%{rpmhome}/*requires* -%{rpmhome}/*deps* -%{rpmhome}/*.prov -%{rpmhome}/*.req -%{rpmhome}/config.* -%{rpmhome}/mkinstalldirs -%{rpmhome}/macros.p* -%{rpmhome}/fileattrs/* - -%files sign -%{_bindir}/rpmsign -%{_mandir}/man8/rpmsign.8* - -%if %{with python2} -%files -n python2-%{name} -%{python2_sitearch}/%{name}/ -%{python2_sitearch}/%{name}-%{version}*.egg-info -%endif # with python2 - -%files -n python3-%{name} -%{python3_sitearch}/%{name}/ -%{python3_sitearch}/%{name}-%{version}*.egg-info - -%files devel -%{_mandir}/man8/rpmgraph.8* -%{_bindir}/rpmgraph -%{_libdir}/librp*[a-z].so -%{_libdir}/pkgconfig/%{name}.pc -%{_includedir}/%{name}/ - -%files cron -%{_sysconfdir}/cron.daily/rpm -%config(noreplace) %{_sysconfdir}/logrotate.d/rpm - -%files apidocs -%license COPYING -%doc doc/librpm/html/* - -%changelog -* Wed Sep 13 2023 Richard Phibel - 4.14.3-26.3 -- Fix IMA signature lengths assumed constant - -* Thu Aug 17 2023 Richard Phibel - 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 - 4.14.3-26.1 -- Merge upstream changes for Hyperscale - -* Mon Dec 19 2022 Florian Festi - 4.14.4-26 -- Add --nocompression to rpm2archive (#2129345) - -* Fri Dec 16 2022 Davide Cavalca - 4.14.3-25.1 -- Merge upstream changes for Hyperscale - -* Wed Nov 30 2022 Richard Phibel - 4.14.3-24.3 -- Add deny list support and workaround for RPM CoW - -* Tue Nov 29 2022 Aleksandr Kazakov - 4.14.3-24.2 -- Backport support for multi-threaded zstd compression - -* Sat Oct 29 2022 Richard Phibel - 4.14.3-24.1 -- Merge upstream changes for Hyperscale - -* Tue Sep 13 2022 Michal Domonkos - 4.14.3-24 -- Make write() nonblocking in fapolicyd plugin (#2110787) - -* Tue Jun 21 2022 Manu Bretelle - 4.14.3-23.2 -- Revert ndb by default (e62c0500274012ca77817a24814de38944c8abd4) - -* Mon May 16 2022 Manu Bretelle - 4.14.3-23.1 -- Rebuild for Hyperscale - -* Tue Apr 05 2022 Michal Domonkos - 4.14.3-23 -- Fix minor ABI regression in rpmcli.h (#1940895) - -* Fri Mar 25 2022 Manu Bretelle - 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 - 4.14.3-21.5 -- Backport GH#1040 to allow ndb DB query on read-only FS - -* Tue Feb 15 2022 Michal Domonkos - 4.14.3-22 -- Fix spurious %transfiletriggerpostun execution (#2023693) -- Skip recorded symlinks in --setperms (#1900662) - -* Mon Feb 14 2022 Manu Bretelle - 4.14.3-21.4 -- Use ndb by default -- Fix support for hardlinks - -* Tue Feb 08 2022 Manu Bretelle - 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 - 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 - 4.14.3-21.1 -- Rebuild for Hyperscale - -* Mon Jan 10 2022 Michal Domonkos - 4.14.3-21 -- Address covscan issues in binding sigs validation patch (#1958480) - -* Thu Dec 09 2021 Michal Domonkos - 4.14.3-20 -- Add --path query option (#1940895) -- Macroize find-debuginfo script location (#2019540) -- Validate and require subkey binding sigs on PGP pubkeys (#1958480) -- Fixes CVE-2021-3521 - -* Thu Nov 04 2021 Matthew Almond - 4.14.3-18.2 -- Include PR1779 - -* Wed Oct 06 2021 Michal Domonkos - 4.14.3-19 -- Unbreak in-tree kmod strip by reverting brp-strip fix (#1967291) - -* Thu Sep 16 2021 Matthew Almond - 4.14.3-18.1 -- Rebase c8s-sig-hyperscale-experimental branch onto c8s changes - -* Thu Aug 26 2021 Michal Domonkos - 4.14.3-18 -- Address important covscan issues (#1996665), vol. 2 - -* Mon Aug 23 2021 Michal Domonkos - 4.14.3-17 -- Address important covscan issues (#1996665) - -* Thu Aug 19 2021 Michal Domonkos - 4.14.3-16 -- Add support for read-only sqlite rpmdb (#1938928) -- Drop compat .decode() method from returned Py3 strings (#1840142) - -* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.4 -- Add measure plugin - -* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.3 -- Move rpm2extents to plugin package - -* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.2 -- Added fsverity backport - -* Sat Jul 24 2021 Neal Gompa - 4.14.3-15.1 -- Rebuild for Hyperscale - -* Thu Jul 15 2021 Michal Domonkos - 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 - 4.14.3-14.1 -- Rebuild for Hyperscale - -* Thu May 27 2021 Michal Domonkos - 4.14.3-14 -- Be more careful about copying data from signature header (#1958477) -- Fixes CVE-2021-20271 - -* Thu Mar 18 2021 Matthew Almond - 4.14.3-13.1 -- PR1381 (Fix Fseek for offset > 2GiB) -- PR1470 (CoW) - -* Fri Feb 12 2021 Michal Domonkos - 4.14.3-13 -- Fix minor issues found by COVSCAN in fapolicyd plugin -- Actually honor libarchive bcond at configure time (#1902887) - -* Tue Feb 09 2021 Michal Domonkos - 4.14.3-12 -- Bump up the limit of signature header to 64MB (#1918777) -- Add fapolicyd plugin (#1923167) -- Unblock signals in forked scriptlets (#1913765) -- Fix ambiguous diagnostics output on file triggers (#1883338) -- Ensure ELF files get stripped when debuginfo is disabled (#1634084) - -* Sun Jan 10 2021 Michal Domonkos - 4.14.3-10 -- Rebuild for libimaevm soname bump, now for real (#1896046) - -* Thu Jan 07 2021 Florian Festi - 4.14.3-8 -- Add limits to autopatch macro (#1834931) - -* Thu Dec 03 2020 Michal Domonkos - 4.14.3-6 -- Rebuild for libimaevm soname bump (#1896046) - -* Fri Oct 30 2020 Florian Festi - 4.14.3-5 -- Don't error out when replacing an invalid signature (#1874062) -- Raise an expection when erasing a package fails in Python (#1872623) -- Fix builds on NFS filesystems (#1840728) - -* Fri Jun 26 2020 Michal Domonkos - 4.14.3-4 -- Fix hang when signing with expired key (#1746353) - -* Wed May 13 2020 Panu Matilainen - 4.14.3-3 -- Fix configure option for --with ndb (#1817010, Matthew Almond) - -* Mon May 11 2020 Florian Festi - 4.14.3-2 -- Re-add selinux fix dropped in rebase - -* Mon May 4 2020 Florian Festi - 4.14.3-1 -- Rebase to 4.14.3 (#1765187) - -* Fri Feb 21 2020 Michal Domonkos - 4.14.2-37 -- Add API safeguard for DNF by using Conflicts: (#1790400) - -* Thu Jan 09 2020 Panu Matilainen - 4.14.2-36 -- Revert DBUS shutdown patch, it causes regressions (#1783346) - -* Wed Nov 27 2019 Panu Matilainen - 4.14.2-35 -- Revert mistakenly included patch from caret backport - -* Thu Nov 21 2019 Panu Matilainen - 4.14.2-34 -- Backport caret version operator (#1654901) - -* Thu Nov 21 2019 Panu Matilainen - 4.14.2-33 -- Backport _smp_build_ncpus macro for #1691824 and #1704354 - -* Thu Nov 21 2019 Panu Matilainen - 4.14.2-32 -- Fix resource leaks on zstd open error - -* Mon Nov 18 2019 Florian Festi - 4.14.2-31 -- Parallelize /usr/lib/rpm/brp-strip-static-archive (#1691824) -- Parallelize /usr/lib/rpm/check-buildroot (#1704354) - -* Tue Nov 12 2019 Panu Matilainen - 4.14.2-30 -- Handle gcc -g3 debug level output in debuginfo (#1630926) - -* Thu Oct 24 2019 Panu Matilainen - 4.14.2-29 -- Use Python 3 for the test suite and make it pass (#1724138) - -* Thu Oct 24 2019 Panu Matilainen - 4.14.2-28 -- Accept PGP public keys with missing EOL (#1733971) - -* Thu Oct 24 2019 Panu Matilainen - 4.14.2-27 -- Support generating build-id's from compressed ELF files (#1650074) -- Compress annobit notes in find-debuginfo (#1719837) - -* Wed Oct 16 2019 Panu Matilainen - 4.14.2-26 -- Re-enable support for zstd (#1715799) - -* Wed Aug 07 2019 Florian Festi - 4.14.2-25 -- Fix memory leak in verify code (#1714657) - -* Wed Jul 31 2019 Florian Festi - 4.14.2-24 -- Fix off-by-one in hdrblobGet() breaking large packages (#1722921) - -* Thu Jul 25 2019 Florian Festi - 4.14.2-23 -- Use --dpbath only with full path (#1696408) -- Fix memory leaks (#1714657) -- Remove capabilities instead of setting empty caps via. --setcaps (#1700920) -- Fix bash warning from solution for #1689810 - -* Thu Jul 18 2019 Florian Festi - 4.14.2-22 -- Add information about FIPS mode to rpmsign man page (#1726678) - -* Wed Jul 03 2019 Florian Festi - 4.14.2-21 -- Fix bash warning from solution for #1689810 - -* Thu Jun 06 2019 Panu Matilainen - 4.14.2-20 -- Fix packages getting removed on failed update via dnf (#1710346) - -* Tue Jun 04 2019 Panu Matilainen - 4.14.2-19 -- Fix rare segfault in fingerprinting symlink round (#1660232) - -* Tue Jun 04 2019 Panu Matilainen - 4.14.2-18 -- Make use of unversioned %%__python macro an error (#1645663) - -* Wed Apr 24 2019 Florian Festi - 4.14.2-17 -- Add flag to use strip -g instead of full strip on DSOs (#1689810) - -* Wed Apr 24 2019 Florian Festi - 4.14.2-16 -- Sort list of hard linked files in find-debuginfo.sh (#1421272) -- Correct rpm -ql exit value when optional -p is omitted (#1680610) -- Show list of files only once when use rpm -ql and multiple rpm files (#1689898) - -* Fri Apr 12 2019 Panu Matilainen - 4.14.2-15 -- Fix %_minimize_writes stripping suid/sgid bits and capabilities (#1690876) - -* Thu Apr 11 2019 Panu Matilainen - 4.14.2-14 -- Verify packages before signing (#1646388) -- Make rpmsign exist values more consistent with our other tools - -* Thu Apr 11 2019 Panu Matilainen - 4.14.2-13 -- Report meaningful errors from SElinux plugin (#1679028) - -* Thu Apr 11 2019 Panu Matilainen - 4.14.2-12 -- Fix an ancient GIL locking bug, required for the .decode() trick - -* Thu Apr 11 2019 Panu Matilainen - 4.14.2-11 -- Revised patch for Py3 string data as surrogate-escaped utf-8 (#1631292) -- Add a .decode() method to returned Py3 strings for compatibility - -* Wed Mar 06 2019 Panu Matilainen - 4.14.2-10 -- Return all string data as surrogate-escaped utf-8 in Python 3 (#1631292) - -* Thu Dec 20 2018 Panu Matilainen - 4.14.2-9 -- Mark elements with associated problems as failed (needed for audit) - -* Fri Dec 14 2018 Panu Matilainen - 4.14.2-8 -- Differentiate between install and update in audit log - -* Mon Dec 03 2018 Panu Matilainen - 4.14.2-7 -- Move python-macro-helper to main package where the macros are (#1651926) -- Document --noverify in the man page (#1646458) -- Handle unsupported digests the same as disabled ones (#1652529) - -* Mon Dec 03 2018 Panu Matilainen - 4.14.2-6 -- Fix our SElinux dependencies (#1651926) - -* Fri Nov 30 2018 Florian Festi - 4.14.2-5 -- Add new tag MODULARITYLABEL (#1650287) - -* Mon Oct 22 2018 Panu Matilainen - 4.14.2-4 -- Fix nasty --setperms/--setugids regression introduced in 4.14.2 (#1640470) - -* Thu Sep 13 2018 Panu Matilainen - 4.14.2-3 -- Oops, op= was supposed to be first in the audit message (#1607612) - -* Thu Sep 13 2018 Panu Matilainen - 4.14.2-2 -- Revised audit patch, log removals and verify failures too (#1607612) - -* Mon Sep 03 2018 Panu Matilainen - 4.14.2-1 -- Buildrequire audit-libs-devel to actually enable the feature (#1607612) -- Update to rpm 4.14.2 final (http://rpm.org/wiki/Releases/4.14.2) - -* Fri Aug 10 2018 Panu Matilainen - 4.14.2-0.rc2.1 -- Update to rpm 4.14.2-rc2 -- Fixes a regression in rpmlog error handling (#1597274) -- Fixes several resource leaks found by covscan (#1602681) -- Fixes DISTTAG not getting copied to source rpms (#1596193) - -* Tue Aug 07 2018 Florian Festi - 4.14.2-0.rc1.5 -- Wrap zstd Requires in build condition - -* Thu Aug 02 2018 Florian Festi - 4.14.2-0.rc1.4 -- Add log entries to audit system (#1607612) - -* Wed Aug 01 2018 Panu Matilainen - 4.14.2-0.rc1.3 -- Disable test-suite by default to avoid fakechroot dependency (#1601024) - -* Mon Jul 30 2018 Florian Festi - 4.14.2-0.rc1.2 -- Build without zstd support - -* Wed Jul 18 2018 Florian Festi - 4.14.2-0.rc1.1 -- Update to rpm 4.14.2-rc1 - -* Tue Jul 03 2018 Tomas Orsava - 4.14.1-11 -- Compile Python 3.6 stuff with /usr/libexec/platform-python instead of - /usr/bin/python3.6 - -* Fri Jun 29 2018 Charalampos Stratakis - 4.14.1-10.1 -- Bump release for rebuild - -* Tue Jun 26 2018 Charalampos Stratakis - 4.14.1-9 -- Disable python2 bytecompilation - -* Fri Jun 22 2018 Charalampos Stratakis - 4.14.1-8 -- Conditionalize the python2 subpackage - -* Mon Feb 19 2018 Panu Matilainen - 4.14.1-7 -- Explicitly BuildRequire gcc and make - -* Fri Feb 09 2018 Igor Gnatenko - 4.14.1-6.1 -- Escape macros in %%changelog - -* Wed Jan 31 2018 Panu Matilainen - 4.14.1-6 -- Avoid unnecessary macro helper dependency on /usr/bin/python (#1538657) -- Fix release of previous changelog entry - -* Tue Jan 30 2018 Tomas Orsava - 4.14.1-5 -- Add envvar that will be present during RPM build, - Part of a Fedora Change for F28: "Avoid /usr/bin/python in RPM build" - https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build - -* Tue Jan 30 2018 Petr Viktorin - 4.14.1-4 -- Skip automatic Python byte-compilation if *.py files are not present - -* Thu Jan 25 2018 Florian Weimer - 4.14.1-3 -- Rebuild to work around gcc bug leading to librpm miscompilation (#1538648) - -* Thu Jan 18 2018 Panu Matilainen - 4.14.1-2 -- Avoid nuking the new python-macro-helper along with dep generators (#1535692) - -* Tue Jan 16 2018 Panu Matilainen - 4.14.1-1 -- Rebase to rpm 4.14.1 (http://rpm.org/wiki/Releases/4.14.1) - -* Tue Nov 07 2017 Igor Gnatenko - 4.14.0-5 -- Fix typo in Obsoletes - -* Mon Nov 06 2017 Igor Gnatenko - 4.14.0-4 -- Remove platform-python bits - -* Thu Oct 26 2017 Panu Matilainen - 4.14.0-3 -- Move selinux plugin dependency to selinux-policy in Fedora >= 28 (#1493267) - -* Thu Oct 12 2017 Panu Matilainen - 4.14.0-2 -- Dump out test-suite log in case of failures again -- Don't assume per-user groups in test-suite - -* Thu Oct 12 2017 Panu Matilainen - 4.14.0-1 -- Rebase to rpm 4.14.0 final (http://rpm.org/wiki/Releases/4.14.0) - -* Tue Oct 10 2017 Troy Dawson - 4.14.0-0.rc2.6 -- Cleanup spec file conditionals - -* Tue Oct 03 2017 Panu Matilainen - 4.14.0-0.rc2.5 -- Add build conditionals for zstd and lmdb support -- Enable zstd support - -* Tue Oct 03 2017 Panu Matilainen - 4.14.0-0.rc2.4 -- Spec cleanups - -* Fri Sep 29 2017 Panu Matilainen - 4.14.0-0.rc2.3 -- BuildRequire gnupg2 for the testsuite - -* Fri Sep 29 2017 Panu Matilainen - 4.14.0-0.rc2.2 -- ima-evm-utils only has a -devel package in fedora >= 28 - -* Thu Sep 28 2017 Panu Matilainen - 4.14.0-0.rc2.1 -- Rebase to rpm 4.14.0-rc2 (http://rpm.org/wiki/Releases/4.14.0) - -* Mon Sep 18 2017 Panu Matilainen - 4.14.0-0.rc1.3 -- Fix Ftell() past 2GB on 32bit architectures (#1492587) - -* Thu Sep 07 2017 Panu Matilainen - 4.14.0-0.rc1.2 -- Actually honor with/without libimaevm option -- ima-evm-utils-devel >= 1.0 is required for rpm >= 4.14.0 - -* Wed Sep 06 2017 Panu Matilainen - 4.14.0-0.rc1.1 -- Rebase to rpm 4.14.0-rc1 (http://rpm.org/wiki/Releases/4.14.0) -- Re-enable SHA256 header digest generation (see #1480407) - -* Mon Aug 28 2017 Panu Matilainen - 4.13.90-0.git14000.8 -- Band-aid for DB_VERSION_MISMATCH errors on glibc updates (#1465809) - -* Thu Aug 24 2017 Panu Matilainen - 4.13.90-0.git14000.7 -- Remove ugly kludges from posttrans script, BDB handles this now - -* Fri Aug 18 2017 Panu Matilainen - 4.13.90-0.git14000.6 -- Silence harmless but bogus error message on noarch packages (#1482144) - -* Thu Aug 17 2017 Miro Hrončok - 4.13.90-0.git14002.5 -- Build with platform_python - -* Mon Aug 14 2017 Miro Hrončok - 4.13.90-0.git14000.4 -- Add platform-python bytecompilation patch: platform-python-bytecompile.patch -- Add platform python deps generator patch: platform-python-abi.patch -- Add a platform-python subpackage and remove system python related declarations -- Build rpm without platform_python for bytecompilation - (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack) - -* Mon Aug 14 2017 Panu Matilainen - 4.13.90-0.git14000.3 -- Disable macro argument quoting as a band-aid to #1481025 - -* Fri Aug 11 2017 Panu Matilainen - 4.13.90-0.git14000.2 -- Disable SHA256 header-only digest generation temporarily (#1480407) - -* Thu Aug 10 2017 Panu Matilainen - 4.13.90-0.git14000.1 -- Rebase to rpm 4.13.90 aka 4.14.0-alpha (#1474836) - -* Mon Jul 31 2017 Igor Gnatenko - 4.13.0.1-41 -- Move _debuginfo_subpackages and _debugsource_packages to redhat-rpm-config - -* Sat Jul 29 2017 Igor Gnatenko - 4.13.0.1-40 -- Update latest patches from merged versions - -* Fri Jul 28 2017 Igor Gnatenko - 4.13.0.1-39 -- Backport fixes for debuginfo subpackages - -* Wed Jul 26 2017 Igor Gnatenko - 4.13.0.1-38 -- Backport trivial fix for debugsourcefiles.list ending up in random dir - -* Tue Jul 25 2017 Igor Gnatenko - 4.13.0.1-37 -- Enable debugsource and debuginfo subpackages by default - -* Mon Jul 24 2017 Igor Gnatenko - 4.13.0.1-36 -- Make sure that test results are not ignored - -* Sun Jul 23 2017 Mark Wielaard - 4.13.0.1-35 -- Fix rpmfd_write on big endian arches. - -* Fri Jul 21 2017 Mark Wielaard - 4.13.0.1-34 -- find-debuginfo.sh: Remove non-allocated NOBITS sections from minisymtab. - -* Thu Jul 20 2017 Igor Gnatenko - 4.13.0.1-33 -- Remove strict requirement on python libs - -* Tue Jul 18 2017 Mark Wielaard - 4.13.0.1-32 -- Add find-debuginfo.sh: Add --keep-section and --remove-section (#1465997) - -* Wed Jul 12 2017 Igor Gnatenko - 4.13.0.1-31 -- Add automatic provides debuginfo(build-id) = ... into debuginfo subpackages - -* Fri Jul 07 2017 Igor Gnatenko - 4.13.0.1-30 -- Fix brokeness when using %%filter_setup (RHBZ #1468476) - -* Tue Jul 04 2017 Mark Wielaard - 4.13.0.1-29 -- Track patches using https://pagure.io/rpm-fedora -- Use file list to explicitly set mode for build-id dirs/files - (#1452893, #1458839) - -* Thu Jun 29 2017 Mark Wielaard - 4.13.0.1-28 -- Add debugedit-prefix.patch. -- Add find-debuginfo-filter-built-ins.patch. -- Add find-debuginfo-dwz-multi.patch. -- Add find-debuginfo-and-macro-docs.patch. - -* Wed Jun 28 2017 Mark Wielaard - 4.13.0.1-27 -- Add find-debuginfo-split-traversal-and-extraction-fix.patch (#1465170) - -* Wed Jun 28 2017 Igor Gnatenko - 4.13.0.1-26 -- Backport patches for rich dependencies from dependency generators - -* Sun Jun 25 2017 Mark Wielaard - 4.13.0.1-25 -- Add support for debugsource and debuginfo subpackages - - find-debuginfo-untangle-unique-build-options.patch - - debugsrc-and-sub-debuginfo-packages.patch - -* Fri Jun 23 2017 Mark Wielaard - 4.13.0.1-24 -- Backport parallel debuginfo processing. - -* Tue May 30 2017 Mark Wielaard - 4.13.0.1-23 -- Fix resetting attr flags in buildid creation (#1449732) - -* Tue May 23 2017 Panu Matilainen - 4.13.0.1-22 -- Python dependency generators live in python-rpm-generators now (#1444925) - -* Tue May 23 2017 Panu Matilainen - 4.13.0.1-21 -- Fix rpmsign python module import failing (#1393659) - -* Tue Apr 25 2017 Mark Wielaard - 4.13.0.1-20 -- Fix rpmbuild world writable empty (tmp) dirs in debuginfo (#641022) - -* Sat Apr 15 2017 Mark Wielaard - 4.13.0.1-19 -- Minisymtab should only be added for executables or shared libraries. -- Add find-debuginfo.sh -n (debugedit --no-recompute-build-id) option. - -* Fri Mar 31 2017 Panu Matilainen - 4.13.0.1-18 -- gpg path must not depend on %%_prefix and such (#1437726) - -* Mon Mar 27 2017 Panu Matilainen - 4.13.0.1-17 -- Work around missing python[23] during build dependency parse -- Include ISA in the new python library version dependencies too - -* Mon Mar 27 2017 Panu Matilainen - 4.13.0.1-16 -- Band-aid for python library versioning inadequacies (#1435135) - -* Mon Mar 27 2017 Mark Wielaard - 4.13.0.1-15 -- Unbreak short-circuited binary builds (#1434235). - -* Tue Mar 21 2017 Mark Wielaard - 4.13.0.1-14 -- Add fix for off by one adding DW_FORM_string replacement (#1434347). - -* Mon Mar 20 2017 Mark Wielaard - 4.13.0.1-13 -- Add tests fix for sed file build-id regexp matching. -- Add fix for build-ids in non-executable ELF files (#1433837). - -* Fri Mar 17 2017 Mark Wielaard - 4.13.0.1-12 -- Fix reading and updating (cross-endian) build-id information. - -* Fri Mar 17 2017 Mark Wielaard - 4.13.0.1-11 -- Do not process build-ids for noarch packages. - -* Thu Mar 16 2017 Mark Wielaard - 4.13.0.1-10 -- Add fix for debugedit replace debug_line files. - -* Thu Mar 16 2017 Igor Gnatenko - 4.13.0.1-9 -- Switch to OpenSSL (RHBZ #1390624) - -* Wed Mar 15 2017 Mark Wielaard - 4.13.0.1-8 -- Add fix to reset buildid file attributes (#1432372) - -* Fri Mar 10 2017 Mark Wielaard - 4.13.0.1-7 -- Add fixup fix for build-id warnings on object files (#1430587) - -* Thu Mar 09 2017 Mark Wielaard - 4.13.0.1-6 -- Add fix for missing_build_ids_terminate_build without __debug_package. - -* Thu Mar 09 2017 Mark Wielaard - 4.13.0.1-5 -- Add fix for build-id warnings on object files (#1430587) - -* Wed Mar 08 2017 Panu Matilainen - 4.13.0.1-4 -- Mark Wielaard's backports for debuginfo parallel installation etc (#1427970) - -* Fri Feb 24 2017 Pavlina Moravcova Varekova - 4.13.0.1-3 -- Fix number of references on spec_Type (#1426578) - -* Thu Feb 16 2017 Tomas Orsava - 4.13.0.1-2 -- Fix handling of Python wheels by pythondistdeps.py --provides (#1421776) - -* Thu Feb 16 2017 Panu Matilainen - 4.13.0.1-1 -- Update to 4.13.0.1 ((http://rpm.org/wiki/Releases/4.13.0) - -* Tue Feb 14 2017 Florian Festi - 4.13.0-12 -- Fix Python byte compilation for Python3 only packages (#1411588) - -* Sat Feb 11 2017 Fedora Release Engineering - 4.13.0-11.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild - -* Mon Jan 23 2017 Panu Matilainen - 4.13.0-11 -- Fix malformed packages being generated around 4GB boundary (#1405570) -- Resurrect debuginfo GDB index generation (#1410907) - -* Fri Jan 06 2017 Igor Gnatenko - 4.13.0-10 -- Add Requires: python-setuptools for rpm-build (RHBZ #1410631) - -* Wed Dec 21 2016 Peter Robinson 4.13.0-9 -- Rebuild for Python 3.6 - -* Sun Dec 18 2016 Igor Gnatenko - 4.13.0-8 -- Switch rpm-build to system-python (RHBZ #1405483) - -* Fri Dec 09 2016 Charalampos Stratakis - 4.13.0-7 -- Rebuild for Python 3.6 - -* Sat Dec 03 2016 Igor Gnatenko - 4.13.0-6 -- Fix arch-dependent requires in subpackages (RHBZ #1398591) - -* Fri Nov 25 2016 Igor Gnatenko - 4.13.0-5 -- Fix arch-dependent requires in subpackages (RHBZ #1398591) - -* Fri Nov 11 2016 Panu Matilainen - 4.13.0-4 -- Expand python subpackage obsoletion range (related: #1394125) - -* Mon Nov 07 2016 Panu Matilainen - 4.13.0-3 -- Fix invalid memory access on %%transfiletriggerpostun (#1284645) - -* Fri Nov 04 2016 Thierry Vignaud - 4.13.0-2 -- Fix package name references in python sub-packages to match reality -- Re-enable test-suite now that it works again - -* Thu Nov 03 2016 Panu Matilainen - 4.13.0-1 -- Rebase to rpm 4.13.0 final (http://rpm.org/wiki/Releases/4.13.0) - -* Wed Nov 02 2016 Panu Matilainen - 4.13.0-0.rc2.2 -- Fix harmless unused variable warning from fedora-specspo patch - -* Thu Oct 20 2016 Panu Matilainen - 4.13.0-0.rc2.1 -- Rebase to rpm 4.13.0-rc2 - -* Fri Sep 23 2016 Richard W.M. Jones - 4.13.0-0.rc1.47 -- Backport two upstream patches which add riscv64 architecture support. - -* Wed Aug 24 2016 Igor Gnatenko - 4.13.0-0.rc1.46 -- Backport patch for missing import in Python dependency generator - -* Wed Aug 24 2016 Kalev Lember - 4.13.0-0.rc1.45 -- Fix -python2 and -python3 subpackage obsoleting from .42 - -* Tue Aug 23 2016 Igor Gnatenko - 4.13.0-0.rc1.44 -- Use %%python_provide for python3 subpackage - -* Mon Aug 22 2016 Igor Gnatenko - 4.13.0-0.rc1.43 -- Backport fixes to ignore .egg-link files in Python dependency generator - -* Fri Aug 12 2016 Florian Festi - 4.13.0-0.rc1.42 -- Enable --majorver-provides in Python dependency generator - -* Tue Aug 09 2016 Igor Gnatenko - 4.13.0-0.rc1.41 -- Add %%{?system_python_abi} -- rpm-python -> python2-rpm && rpm-python3 -> python3-rpm with providing old names -- Fixes and cleanups - -* Tue Jul 19 2016 Fedora Release Engineering - 4.13.0-0.rc1.40.1 -- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages - -* Mon Jul 18 2016 Petr Pisar - 4.13.0-0.rc1.40 -- Drop rpm-build's dependency on perl-generators (bug #1158860) - -* Fri Jul 15 2016 Florian Festi - 4.13.0-0.rc1.39 -- Pass relevant files to new Python dependency generator - -* Mon Jun 13 2016 Florian Festi - 4.13.0-0.rc1.38 -- Add new Python dependency generator (provides only for now) (#1340885) - -* Thu Jun 02 2016 Florian Festi - 4.13.0-0.rc1.37 -- Add support for _buildhost macro (#1309367) - -* Mon May 23 2016 Lubos Kardos 4.13.0-0.rc1.36 -- Fix signing with non-ASCII uid keys (#1243963) - -* Thu May 19 2016 Lubos Kardos 4.13.0-0.rc1.35 -- Use armv7hl isa for all armhfp (armv7h*l) arches (#1326871) - -* Tue May 17 2016 Lubos Kardos 4.13.0-0.rc1.34 -- Filter unversioned deps if corresponding versioned deps exist (#678605) - -* Mon Apr 25 2016 Lubos Kardos 4.13.0-0.rc1.33 -- Fix sigsegv in stringFormat() (#1316903) -- Fix reading rpmtd behind its size in formatValue() (#1316896) - -* Fri Apr 15 2016 Lubos Kardos 4.13.0-0.rc1.32 -- escape %% chars in previous changelog record - -* Fri Apr 15 2016 Lubos Kardos 4.13.0-0.rc1.31 -- Enable --no-backup-if-mismatch by default in %%patch macro (#884755) -- Add %%{_default_patch_flags} to %%__patch which is used in %%autosetup -- Use fuzz settings for %%autopatch/%%autosetup - -* Thu Apr 14 2016 Lubos Kardos 4.13.0-0-rc1.30 -- Make creating index records consistent for rich and rich-weak deps (#1325982) - -* Tue Apr 12 2016 Lubos Kardos 4.13.0-0.rc1.29 -- Add RPMCALLBACK_ELEM_PROGRESS callback type (needed by dnf) - -* Wed Apr 06 2016 Lubos Kardos 4.13.0-0.rc1.28 -- Fix non-working combination of %%lang and %%doc directive (#1254483) - -* Thu Mar 10 2016 Lubos Kardos 4.13.0-0.rc1.27 -- Add posix.redirect2null (#1287918) - -* Fri Feb 26 2016 Florian Festi - 4.13.0-0.rc1.26 -- Fix ExclusiveArch/ExcludeArch for noarch packages (#1298668) - -* Thu Feb 25 2016 Florian Festi - 4.13.0-0.rc1.25 -- Fix dependencies for RemovePathPostfixes (#1306559) - -* Fri Feb 19 2016 Florian Festi - 4.13.0-0.rc1.24 -- Also block idle and sleep in the systemd-inhibit plugin (#1297984) -- Add support for MIPS release 6 -- Add mips32 mips64 mipsel and mipseb macros (#1285116) - -* Tue Feb 02 2016 Lubos Kardos - 4.13.0-0.rc1.23 -- Remove size limit when expanding macros (#1301677) - -* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.22 -- Harden rpm package again, previous attempt had to be reverted (#1289734) - -* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.21 -- Remove setting %%_gnu macro explictly, no more needed (#1303265) - -* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.20 -- Revert using %%configure, it causes problems -- Temporary set %%_gnu macro explictly, just for one build (#1303265) - -* Fri Jan 29 2016 Lubos Kardos - 4.13.0-0.rc1.19 -- Use %%configure macro, harden rpm package (#1289734) - -* Tue Jan 19 2016 Lubos Kardos - 4.13.0-0.rc1.18 -- Escape %%autosetup in previous changelog record - -* Tue Jan 19 2016 Lubos Kardos - 4.13.0-0.rc1.17 -- Fix %%autosetup not to cause errors during run of rpmspec tool (#1293687) - -* Fri Jan 15 2016 Lubos Kardos - 4.13.0-0.rc1.16 -- Fix recursive calling of rpmdeps tool (#1297557) - -* Fri Jan 15 2016 Florian Festi - 4.13.0-0.rc1.15 -- Add support for missingok file attribute - -* Fri Jan 15 2016 Lubos Kardos - 4.13.0-0.rc1.14 -- Fix not chrooting transaction file triggers - -* Mon Nov 23 2015 Lubos Kardos - 4.13.0-0.rc1.13 -- Add possibility to disable file triggers -- Fix unwanted multiple execution of filetriggers in dnf (#1282115) - -* Thu Nov 12 2015 Fedora Release Engineering - 4.13.0-0.rc1.12 -- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5 - -* Fri Nov 06 2015 Lubos Kardos - 4.13.0-0.rc1.11 -- Fix crash when parsing corrupted RPM file (#1273360) - -* Fri Nov 06 2015 Lubos Kardos - 4.13.0-0.rc1.10 -- Fix SIGSEGV in case of old unsupported gpg keys (#1277464) - -* Fri Oct 30 2015 Lubos Kardos - 4.13.0-0.rc1.9 -- Ignore SIGPIPE signals during execucton of scriptlets (#1264198) - -* Fri Oct 30 2015 Florian Festi - 4.13.0-0.rc1.8 -- Move /usr/lib/rpm/fileattrs directory from rpm-build to rpm (#1272766) - -* Fri Oct 23 2015 Lubos Kardos - 4.13-0.rc1.7 -- Fix reading a memory right after the end of an allocated area (#1260248) -- Add support for various types of dependencies to rpmdeps tool (#1247092) -- fix %%autopatch when patch do not exist (#1244172) - -* Fri Oct 23 2015 Lubos Kardos - 4.13-0.rc1.6 -- If %%_wrong_version_format_terminate_build is 1 then terminate build in case - that version format is wrong i. e. epoch is not unsigned integer or version - contains more separators (":", "-"). %%_wrong_version_format_terminate_build - is 1 by deafault (#1265700) - -* Wed Oct 14 2015 Robert Kuska - 4.13.0-0.rc1.5 -- Rebuilt for Python3.5 rebuild - -* Mon Oct 12 2015 Florian Festi - 4.13.0-0.rc1.4 -- Fix selinux plugin for permissive mode - -* Mon Sep 07 2015 Florian Festi - 4.13.0-0.rc1.3 -- Fix new rich dependency syntax - -* Sat Sep 05 2015 Kalev Lember - 4.13.0-0.rc1.2 -- Obsolete compat-librpm3 - -* Wed Sep 02 2015 Florian Festi - 4.13.0-0.rc1.1 -- Update to upstream rc1 release - -* Mon Aug 10 2015 Lubos Kardos - 4.12.90-7 -- Fix last occurence of PyString - -* Thu Aug 06 2015 Lubos Kardos - 4.12.90-6 -- Add --filetriggers option to show info about file triggers. - -* Mon Aug 03 2015 Lubos Kardos - 4.12.90-5 -- If globbing of a filename fails, try use the filename without globbing. - (#1246743) -- Modify rpmIsGlob() to be more precise and compatible with glob(). - (#1246743) - -* Thu Jul 30 2015 Lubos Kardos - 4.12.90-4 -- Don't warn when an escaped macro is in a comment (#1224660) - -* Mon Jul 27 2015 Florian Festi - 4.12.90-3 -- Fix compressed patches (#1247248) - -* Mon Jul 27 2015 Lubos Kardos - 4.12.90-2 -- Enable braces expansion in rpmGlob() (#1246743) - -* Fri Jul 24 2015 Florian Festi - 4.12.90-1 -- Update to upstream alpha release - -* Tue Jul 14 2015 Michal Toman - 4.12.0.1-18 -- Add support for MIPS platform - -* Mon Jun 29 2015 Florian Festi - 4.12.0.1-17 -- Fix Python import directive for more strict Python3 search rules (#1236493) - -* Fri Jun 19 2015 Lubos Kardos 4.12.0.1-16 -- Allow gpg to get passphrase by itself (#1228234) - -* Thu Jun 18 2015 Fedora Release Engineering - 4.12.0.1-15.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild - -* Fri Jun 12 2015 Florian Festi - 4.12.0.1-15 -- Add --whatrecommends and friends (#1231247) - -* Wed Apr 15 2015 Florian Festi - 4.12.0.1-14 -- Fix references to sources in golang debuginfo packages (#1184221) - -* Tue Mar 31 2015 Lubos Kardos 4.12.0-13 -- Fix wrong use of variable strip_g in find-debuginfo.sh (#1207434) - -* Mon Mar 30 2015 Lubos Kardos 4.12.0-12 -- Fix segmentation fault (#1206750) - -* Fri Mar 27 2015 Lubos Kardos 4.12.0-11 -- Pass _find_debuginfo_opts -g to eu-strip for executables (#1186563) -- add_minidebug is not ran when strip_g is set (#1186563) - -* Fri Mar 20 2015 Lubos Kardos 4.12.0-10 -- Fix "--excludedocs" option (#1192625) - -* Fri Mar 20 2015 Florian Festi - 4.12.0.1-9 -- Fix spec to allow building without plugins (#1182385) - -* Mon Mar 16 2015 Than Ngo - 4.12.0.1-8 -- bump release and rebuild so that koji-shadow can rebuild it - against new gcc on secondary arch - -* Sat Feb 21 2015 Till Maas - 4.12.0.1-7.1 -- Rebuilt for Fedora 23 Change - https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code - -* Tue Feb 17 2015 Richard W.M. Jones - 4.12.0.1-7 -- Include upstream patch to fix find-debuginfo (http://www.rpm.org/ticket/887). - -* Fri Jan 16 2015 Tom Callaway - 4.12.0.1-6 -- rebuild against lua 5.3 - -* Fri Dec 12 2014 Lubos Kardos - 4.12.0.1-5 -- Add check against malicious CPIO file name size (#1168715) -- Fixes CVE-2014-8118 -- Fix race condidition where unchecked data is exposed in the file system - (#1039811) -- Fixes CVE-2013-6435 - -* Thu Oct 30 2014 Panu Matilainen - 4.12.0.1-4 -- Axe unused generator scripts forcing a perl dependency (#1158580, #1158583) - -* Tue Oct 28 2014 Panu Matilainen - 4.12.0.1-3 -- Skip ghost files in payload (#1156497) -- Fix size and archice size tag generation on big-endian systems - -* Wed Oct 01 2014 Panu Matilainen - 4.12.0.1-2 -- Dont wait for transaction lock inside scriptlets (#1135596) - -* Thu Sep 18 2014 Panu Matilainen - 4.12.0.1-1 -- Update to rpm-4.12.0.1 final (http://rpm.org/wiki/Releases/4.12.0.1) -- Temporary workaround payload size mismatch issue in rpm2cpio (#1142949) - -* Wed Sep 17 2014 Panu Matilainen - 4.12.0-2 -- Reduce the double separator spec parse error into a warning (#1065563) - -* Tue Sep 16 2014 Panu Matilainen - 4.12.0-1 -- Update to rpm-4.12.0 final (http://rpm.org/wiki/Releases/4.12.0) - -* Tue Sep 02 2014 Panu Matilainen - 4.12.0-0.rc1.2 -- Resurrect payload and tilde rpmlib() dependencies - -* Wed Aug 27 2014 Panu Matilainen - 4.12.0-0.rc1.1 -- Update to rpm-4.12.0-rc1 - -* Mon Aug 25 2014 Panu Matilainen - 4.12.0-0.beta1.6 -- Resurrect dependency logging on package build -- Resurrect rpmlib() dependencies in src.rpms - -* Wed Aug 20 2014 Panu Matilainen - 4.12.0-0.beta1.5 -- Fix duplicate trigger indexes caused by beta1.3 fix (#1131960) - -* Wed Aug 20 2014 Panu Matilainen - 4.12.0-0.beta1.4 -- Emergency hack for #1131892 - -* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.3 -- Fix regression on rpmspec dependency queries - -* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.2 -- Fix regression on BuildRequires checking - -* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.1 -- Update to 4.12.0-beta1 (http://rpm.org/wiki/Releases/4.12.0) -- Fixes #1122004, #1111349, #1117912, #1123722 -- Drop upstreamed patches - -* Mon Aug 18 2014 Fedora Release Engineering - 4.11.90-0.git12844.5.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild - -* Thu Jul 03 2014 Panu Matilainen - 4.11.90-0.git12844.5 -- Fix wildcard database iterator (#1115824) - -* Wed Jul 02 2014 Panu Matilainen - 4.11.90-0.git12844.4 -- Use autosetup for building rpm itself -- Hopefully fix armv7 vfp/neon detection - -* Tue Jul 01 2014 Panu Matilainen - 4.11.90-0.git12844.3 -- Drop no longer needed temporary UsrMove patch -- Macro-expand load macro argument - -* Mon Jun 30 2014 Panu Matilainen - 4.11.90-0.git12844.2 -- Fix multiple interleaved hardlink groups during build - -* Mon Jun 30 2014 Panu Matilainen - 4.11.90-0.git12844.1 -- Update to rpm 4.12-alpha ((http://rpm.org/wiki/Releases/4.12.0) -- Drop/adjust patches as appropriate -- New sub-package(s) for plugins - -* Thu Jun 26 2014 Panu Matilainen - 4.11.2-17 -- Clean up old, no longer needed cruft from spec - -* Thu Jun 26 2014 Panu Matilainen - 4.11.2-16 -- Mark licenses as such, not documentation - -* Wed Jun 25 2014 Panu Matilainen - 4.11.2-15 -- Perl dependency generators live in perl-generators (#1110823) now - -* Wed Jun 18 2014 Lubomir Rintel - 4.11.2-14 -- Fix the armhfp patch for armv6hl - -* Tue Jun 10 2014 Panu Matilainen - 4.11.2-13 -- Rawhide broke our test-suite, disable for now to allow builds to be done - -* Sun Jun 08 2014 Fedora Release Engineering - 4.11.2-12.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild - -* Sat May 31 2014 Peter Robinson 4.11.2-12 -- Drop ChangeLog.bz2 (it's in the source, and it's large) - -* Thu May 15 2014 Bohuslav Kabrda - 4.11.2-11 -- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 - -* Mon Apr 21 2014 Tom Callaway - 4.11.2-10 -- remove _isa from all BuildRequires (bz 554854) - See: https://fedoraproject.org/wiki/Packaging:Guidelines#BuildRequires_and_.25.7B_isa.7D - -* Tue Apr 15 2014 Panu Matilainen - 4.11.2-9 -- move kmod and libsymlink dependency generators to redhat-rpm-config - -* Mon Apr 14 2014 Panu Matilainen - 4.11.2-8 -- fix appdata.prov script missing from package - -* Fri Apr 11 2014 Panu Matilainen - 4.11.2-7 -- disable sanitizers for now, needs more work... - -* Fri Apr 11 2014 Panu Matilainen - 4.11.2-6 -- build with -fsanitize=address and -fsanitize=undefined for now -- add spec build conditional for sanitizer build - -* Tue Apr 08 2014 Panu Matilainen - 4.11.2-5 -- replace unmaintained dependency generator scripts with rpmdeps wrappers - -* Thu Mar 27 2014 Panu Matilainen - 4.11.2-4 -- revert #1045723 fix for now, it breaks some java package macros - -* Wed Mar 26 2014 Panu Matilainen - 4.11.2-3 -- dont eat newlines on parametrized macro invocations (#1045723) -- fully reset file actions between rpmtsRun() calls (#1076552) -- fix build and sign module initialization in python3 (#1064758) - -* Tue Feb 18 2014 Panu Matilainen - 4.11.2-2 -- reduce the double separator spec parse error into a warning (#1065563) - -* Thu Feb 13 2014 Panu Matilainen - 4.11.2-1 -- update to 4.11.2 final (http://rpm.org/wiki/Releases/4.11.2) - -* Thu Feb 06 2014 Panu Matilainen - 4.11.2-0.rc2.1 -- update to 4.11.2-rc2 (http://rpm.org/wiki/Releases/4.11.2) - -* Mon Jan 20 2014 Panu Matilainen - 4.11.2-0.rc1.1 -- update to 4.11.2-rc1 (http://rpm.org/wiki/Releases/4.11.2) -- drop upstreamed patches, adjust others as needed -- handle python egg-info's version munging in file lists - -* Wed Jan 15 2014 Panu Matilainen - 4.11.1-12 -- include ppc64le in %%power64 macro (#1052930) - -* Tue Dec 03 2013 Panu Matilainen - 4.11.1-11 -- generate kmod(module.ko) provides for kernel (#1025513) -- dont override CONFIG_SITE if already set (related to #962837) - -* Mon Nov 18 2013 Panu Matilainen - 4.11.1-10 -- python 3 string and file compatibility fixes - -* Mon Oct 14 2013 Panu Matilainen - 4.11.1-9 -- generate application() provides for gnome-software - -* Tue Oct 01 2013 Panu Matilainen - 4.11.1-8 -- add support for ppc64le architecture - -* Mon Sep 09 2013 Panu Matilainen - 4.11.1-7 -- fix build-time double-free on file capability processing (#956190) -- fix relocation related regression on file sanity check (#1001553) -- fix segfault on empty -p scriptlet body (#1004062) -- fix source url, once again - -* Wed Aug 21 2013 Panu Matilainen - 4.11.1-6 -- add python3 sub-package, based on patch by Bohuslav Kabrda - -* Sat Aug 03 2013 Petr Pisar - 4.11.1-5.1 -- Perl 5.18 rebuild - -* Fri Aug 02 2013 Panu Matilainen - 4.11.1-5 -- add missing dependency on tar to rpm-build (#986539) - -* Tue Jul 30 2013 Florian Festi - 4.11.1-4 -- Do not filter out lib64.* dependencies (#988373) - -* Wed Jul 17 2013 Petr Pisar - 4.11.1-3.1 -- Perl 5.18 rebuild - -* Fri Jul 05 2013 Panu Matilainen - 4.11.1-3 -- ensure relocatable packages always get install-prefix(es) set (#979443) - -* Thu Jul 04 2013 Panu Matilainen - 4.11.1-2 -- fix .gnu_debuglink CRC32 after dwz, buildrequire binutils-devel (#971119) - -* Thu Jun 27 2013 Panu Matilainen - 4.11.1-1 -- update to 4.11.1 final (http://rpm.org/wiki/Releases/4.11.1) - -* Thu Jun 20 2013 Panu Matilainen - 4.11.1-0.rc2.1 -- update to 4.11.2-rc2 (http://rpm.org/wiki/Releases/4.11.1) -- drop upstreamed patches - -* Mon Jun 17 2013 Panu Matilainen - 4.11.1-0.rc1.4 -- handle aarch64 debug_info relocations in debugedit (#974860) - -* Tue Jun 11 2013 Panu Matilainen - 4.11.1-0.rc1.3 -- disable autoconf config.site processing in builds (#962837) - -* Tue Jun 11 2013 Panu Matilainen - 4.11.1-0.rc1.2 -- fix regression on addressing main package by its name (#972994) - -* Mon Jun 10 2013 Panu Matilainen - 4.11.1-0.rc1.1 -- update to 4.11.1-rc1 (http://rpm.org/wiki/Releases/4.11.1) - -* Tue May 28 2013 Panu Matilainen - - 4.11.0.1-7 -- serialize BDB environment open/close (#924417) - -* Wed May 22 2013 Panu Matilainen - - 4.11.0.1-6 -- only consider files with .pm suffix as perl modules (#927211) - -* Fri May 17 2013 Panu Matilainen - - 4.11.0.1-5 -- filter out non-library soname dependencies - -* Thu May 16 2013 Panu Matilainen - - 4.11.0.1-4 -- check for stale locks when opening write-cursors (#860500, #962750...) - -* Fri May 10 2013 Tom Callaway - 4.11.0.1-3 -- lua 5.2 fix from upstream - -* Mon Mar 25 2013 Panu Matilainen - 4.11.0.1-2 -- make rpm-build depend on virtual system-rpm-config provide - -* Mon Feb 04 2013 Panu Matilainen - 4.11.0.1-1 -- update to 4.11.0.1 (http://rpm.org/wiki/Releases/4.11.0.1) - -* Tue Jan 29 2013 Panu Matilainen - 4.11.0-0.beta1.3 -- revert yesterdays ghost-fix, it eats rpmdb's on upgrades - -* Mon Jan 28 2013 Panu Matilainen - 4.11.0-0.beta1.2 -- armv7hl and armv7hnl should not have -mthumb (#901901) -- fix duplicate directory ownership between rpm and rpm-build (#894201) -- fix regression on paths shared between a real file/dir and a ghost - -* Mon Dec 10 2012 Panu Matilainen - 4.11.0-0.beta1.1 -- update to 4.11 beta - -* Mon Nov 19 2012 Panu Matilainen - 4.10.90-0.git11989.3 -- package /usr/lib/rpm/macros.d directory (related to #846679) -- fixup a bunch of old incorrect dates in spec changelog - -* Sat Nov 17 2012 Panu Matilainen - 4.10.90-0.git11989.2 -- fix double-free on %%caps in spec (#877512) - -* Thu Nov 15 2012 Panu Matilainen - 4.10.90-0.git11989.1 -- update to 4.11 (http://rpm.org/wiki/Releases/4.11.0) post-alpha snapshot -- drop/adjust patches as necessary - -* Thu Oct 11 2012 Panu Matilainen - 4.10.1-3 -- fix noarch __isa_* macro filter in installplatform (#865436) - -* Wed Oct 10 2012 Panu Matilainen - 4.10.1-2 -- account for intentionally skipped files when verifying hardlinks (#864622) - -* Wed Oct 03 2012 Panu Matilainen - 4.10.1-1 -- update to 4.10.1 ((http://rpm.org/wiki/Releases/4.10.1) - -* Mon Jul 30 2012 Panu Matilainen - 4.10.0-6 -- move our tmpfiles config to more politically correct location (#840192) - -* Sat Jul 21 2012 Fedora Release Engineering - 4.10.0-5.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild - -* Mon Jul 02 2012 Panu Matilainen - 4.10.0-5 -- force _host_vendor to redhat to better match toolchain etc (#485203) - -* Thu Jun 28 2012 Panu Matilainen - 4.10.0-4 -- merge ppc64p7 related fixes that only went into f17 (#835978) - -* Wed Jun 27 2012 Panu Matilainen - 4.10.0-3 -- add support for minidebuginfo generation (#834073) - -* Mon Jun 25 2012 Panu Matilainen - 4.10.0-2 -- add dwarf compression support to debuginfo generation (#833311) - -* Thu May 24 2012 Panu Matilainen - 4.10.0-1 -- update to 4.10.0 final - -* Mon Apr 23 2012 Panu Matilainen - 4.10.0-0.beta1.1 -- update to 4.10.0-beta1 - -* Mon Apr 16 2012 Panu Matilainen - 4.9.90-0.git11536.1 -- newer git snapshot (#809402, #808750) -- adjust posttrans script wrt bdb string change (#803866, #805613) - -* Thu Apr 05 2012 Panu Matilainen - 4.9.90-0.git11519.1 -- newer git snapshot to keep patch-count down -- fixes CVE-2012-0060, CVE-2012-0061 and CVE-2012-0815 -- fix obsoletes in installing set getting matched on provides (#810077) - -* Wed Apr 04 2012 Jindrich Novy - 4.9.90-0.git11505.12 -- rebuild against new libdb - -* Tue Apr 03 2012 Jindrich Novy - 4.9.90-0.git11505.11 -- build with internal libdb to allow libdb build with higher soname - -* Fri Mar 30 2012 Panu Matilainen - 4.9.90-0.git11505.10 -- fix base arch macro generation (#808250) - -* Thu Mar 29 2012 Panu Matilainen - 4.9.90-0.git11505.9 -- accept files as command line arguments to rpmdeps again (#807767) - -* Mon Mar 26 2012 Panu Matilainen - 4.9.90-0.git11505.8 -- remove fake library provide hacks now that deltarpm got rebuilt - -* Fri Mar 23 2012 Panu Matilainen - 4.9.90-0.git11505.7 -- fix header data length calculation breakage - -* Thu Mar 22 2012 Panu Matilainen - 4.9.90-0.git11505.6 -- fix keyid size bogosity causing breakage on 32bit systems - -* Wed Mar 21 2012 Panu Matilainen - 4.9.90-0.git11505.5 -- add temporary fake library provides to get around deltarpm "bootstrap" - dependency (yes its dirty) - -* Wed Mar 21 2012 Panu Matilainen - 4.9.90-0.git11505.4 -- fix overzealous sanity check breaking posttrans scripts - -* Tue Mar 20 2012 Panu Matilainen - 4.9.90-0.git11505.3 -- fix bad interaction with yum's test-transaction and pretrans scripts - -* Tue Mar 20 2012 Jindrich Novy - 4.9.90-0.git11505.2 -- rebuild - -* Tue Mar 20 2012 Panu Matilainen - 4.9.90-0.git11505.1 -- update to 4.10.0 alpha (http://rpm.org/wiki/Releases/4.10.0) -- drop/adjust patches as necessary - -* Wed Mar 07 2012 Panu Matilainen - 4.9.1.2-14 -- fix backport thinko in the exclude patch - -* Wed Mar 07 2012 Panu Matilainen - 4.9.1.2-13 -- fix memory corruption on rpmdb size estimation (#766260) -- fix couple of memleaks in python bindings (#782147) -- fix regression in verify output formatting (#797964) -- dont process spec include in false branch of if (#782970) -- only warn on missing excluded files on build (#745629) -- dont free up file info sets on test transactions - -* Thu Feb 09 2012 Panu Matilainen - 4.9.1.2-12 -- switch back to smaller BDB cache default (#752897) - -* Sun Jan 15 2012 Dennis Gilmore - 4.9.1.2-11 -- always apply arm hfp macros, conditionally apply the logic to detect hfp - -* Tue Jan 10 2012 Panu Matilainen - 4.9.1.2-10 -- adjust perl and python detection rules for libmagic change (#772699) - -* Mon Jan 09 2012 Jindrich Novy - 4.9.1.2-9 -- recognize perl script as perl code (#772632) - -* Tue Dec 20 2011 Kay Sievers - 4.9.1.2-8 -- add temporary rpmlib patch to support filesystem transition - https://fedoraproject.org/wiki/Features/UsrMove - -* Fri Dec 02 2011 Panu Matilainen - 4.9.1.2-7 -- switch over to libdb, aka Berkeley DB 5.x - -* Thu Dec 01 2011 Panu Matilainen - 4.9.1.2-6 -- fix classification of ELF binaries with setuid/setgid bit (#758251) - -* Fri Nov 25 2011 Panu Matilainen - 4.9.1.2-5 -- adjust font detection rules for libmagic change (#757105) - -* Wed Nov 09 2011 Dennis Gilmore - 4.9.1.2-4 -- conditionally apply arm patch for hardfp on all arches but arm softfp ones - -* Fri Oct 28 2011 Panu Matilainen - 4.9.1.2-3 -- adjust db util prefix & dependency due to #749293 -- warn but dont fail the build if STABS encountered by debugedit (#725378) - -* Wed Oct 12 2011 Panu Matilainen - 4.9.1.2-2 -- try teaching find-lang about the new gnome help layout (#736523) - -* Thu Sep 29 2011 Panu Matilainen - 4.9.1.2-1 -- update to 4.9.1.2 (CVE-2011-3378) -- drop upstreamed rpmdb signal patch - -* Mon Sep 19 2011 Panu Matilainen - 4.9.1.1-3 -- fix signal blocking/unblocking regression on rpmdb open/close (#739492) - -* Mon Aug 08 2011 Adam Jackson 4.9.1.1-2 -- Add RPM_LD_FLAGS to build environment (#728974) - -* Tue Aug 02 2011 Panu Matilainen - 4.9.1.1-1 -- update to 4.9.1.1 - -* Tue Jul 19 2011 Panu Matilainen - 4.9.1-2 -- fix recursion of directories with trailing slash in file list (#722474) - -* Fri Jul 15 2011 Panu Matilainen - 4.9.1-1 -- update to 4.9.1 (http://rpm.org/wiki/Releases/4.9.1) -- drop no longer needed patches - -* Thu Jun 16 2011 Panu Matilainen - 4.9.0-10 -- rebuild to fix a missing interpreter dependency due to bug #712251 - -* Fri Jun 10 2011 Panu Matilainen - 4.9.0-9 -- fix crash if prep or changelog section in spec is empty (#706959) -- fix crash on macro which undefines itself -- fix script dependency generation with file 5.07 string changes (#712251) - -* Thu May 26 2011 Panu Matilainen - 4.9.0-8 -- add dwarf-4 support to debugedit (#707677) -- generate build-id symlinks for all filenames sharing a build-id (#641377) - -* Thu Apr 07 2011 Panu Matilainen - 4.9.0-7 -- add missing ldconfig calls to build-libs sub-package -- fix source url - -* Thu Apr 07 2011 Panu Matilainen - 4.9.0-6 -- revert the spec query change (#693338) for now, it breaks fedpkg - -* Tue Apr 05 2011 Panu Matilainen - 4.9.0-5 -- verify some properties of replaced and wrong-colored files (#528383) -- only list packages that would be generated on spec query (#693338) -- preferred color packages should be erased last (#680261) -- fix leaks when freeing a populated transaction set -- take file state into account for file dependencies - -* Tue Mar 22 2011 Panu Matilainen - 4.9.0-4 -- fix classification of elf executables with sticky bit set (#689182) - -* Wed Mar 16 2011 Jindirch Novy - 4.9.0-3 -- fix crash in package manifest check (#688091) - -* Fri Mar 04 2011 Panu Matilainen - 4.9.0-2 -- fix duplicate rpmsign binary in rpm main package dragging in build-libs - -* Wed Mar 02 2011 Panu Matilainen - 4.9.0-1 -- update to 4.9.0 final -- drop upstreamed patches - -* Tue Mar 01 2011 Panu Matilainen - 4.9.0-0.rc1.4 -- spec cosmetics clean up extra whitespace + group more logically -- wipe out BDB environment at boot via tmpfiles.d - -* Mon Feb 21 2011 Panu Matilainen - 4.9.0-0.rc1.3 -- fix erronous double cursor open, causing yum reinstall hang (#678644) - -* Mon Feb 21 2011 Panu Matilainen - 4.9.0-0.rc1.2 -- fix broken logic in depgen collector, hopefully curing #675002 - -* Tue Feb 15 2011 Panu Matilainen - 4.9.0-0.rc1.1 -- update to 4.9.0-rc1 -- drop upstream patches -- nss packaging has changed, buildrequire nss-softokn-freebl-devel - -* Wed Feb 09 2011 Fedora Release Engineering - 4.9.0-0.beta1.7.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Mon Feb 07 2011 Panu Matilainen - 4.9.0-0.beta1.7 -- fix segfault when building more than one package at a time (#675565) - -* Sun Feb 06 2011 Panu Matilainen - 4.9.0-0.beta1.6 -- adjust ocaml rule for libmagic string change - -* Mon Jan 31 2011 Panu Matilainen - 4.9.0-0.beta1.5 -- dont try to remove environment files if private env used (related to #671200) -- unbreak mono dependency extraction (#673663) -- complain instead of silent abort if cwd is not readable (#672576) - -* Tue Jan 25 2011 Panu Matilainen - 4.9.0-0.beta1.4 -- add support for Requires(posttrans) dependencies - -* Fri Jan 21 2011 Panu Matilainen - 4.9.0-0.beta1.3 -- avoid division by zero in rpmdb size calculation (#671056) -- fix secondary index iteration returing duplicate at end (#671149) -- fix rebuilddb creating duplicate indexes for first header - -* Fri Jan 21 2011 Panu Matilainen - 4.9.0-0.beta1.2 -- permit queries from rpmdb on read-only media (#671200) - -* Tue Jan 18 2011 Panu Matilainen - 4.9.0-0.beta1.1 -- rpm 4.9.0-beta1 (http://rpm.org/wiki/Releases/4.9.0) - - drop no longer needed patches - - adjust requires + buildrequires to match current needs - - adjust rpmdb index ghosts to match the new release - - split librpmbuild and librpmsign to a separate rpm-build-libs package - - split rpmsign to its own package to allow signing without all the build goo - - build-conditionalize plugins, disabled for now - - gstreamer and printer dependency generation moving out - - handle .so symlink dependencies with fileattrs - - use gnupg2 for signing as that's what typically installed by default - -* Tue Jan 18 2011 Panu Matilainen - 4.8.1-7 -- bunch of spec tweaks, cleanups + corrections: - - shorten rpm-build filelist a bit with glob use, reorder for saner grouping - - missing isa in popt version dependency - - only add rpmdb_foo symlinks for actually relevant db_* utils - - drop no longer necessary file-devel dependency from rpm-devel - - drop sqlite backend build-conditional - - preliminaries for moving from db4 to libdb -- use gnupg2 for signing as that's more likely to be installed by default - -* Mon Oct 25 2010 Jindrich Novy - 4.8.1-6 -- rebuild with new xz-5.0.0 - -* Tue Aug 10 2010 Panu Matilainen - 4.8.1-5 -- create gdb index on debuginfo generation (#617166) -- rpm-build now requires /usr/bin/gdb-add-index for consistent index creation -- include COPYING in -apidocs for licensing guidelines compliance - -* Thu Jul 22 2010 David Malcolm - 4.8.1-4 -- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild - -* Fri Jul 02 2010 Panu Matilainen - 4.8.1-3 -- ugh, reversed condition braindamage in the font provide extractor "fix" - -* Wed Jun 30 2010 Panu Matilainen - 4.8.1-2 -- fix a potential getOutputFrom() error from font provide extraction -- debug-friendlier message to aid finding other similar cases (#565223) - -* Fri Jun 11 2010 Panu Matilainen - 4.8.1-1 -- update to 4.8.1 (http://rpm.org/wiki/Releases/4.8.1) -- drop no longer needed patches -- fix source url pointing to testing directory - -* Thu Jun 03 2010 Panu Matilainen - 4.8.0-19 -- also strip POSIX file capabilities from hardlinks on upgrade/erase (#598775) - -* Wed Jun 02 2010 Panu Matilainen - 4.8.0-18 -- remove s-bits on upgrade too (#598775) - -* Thu May 27 2010 Panu Matilainen - 4.8.0-17 -- fix segfault in spec parser (#597835) - -* Thu May 27 2010 Panu Matilainen - 4.8.0-16 -- adjust to new pkg-config behavior wrt private dependencies (#596433) -- rpm-build now requires pkgconfig >= 0.24 - -* Fri May 21 2010 Panu Matilainen - 4.8.0-15 -- handle non-existent dependency sets correctly in python (#593553) -- make find-lang look in all locale dirs (#584866) - -* Fri Apr 23 2010 Panu Matilainen - 4.8.0-14 -- lose dangling symlink to extinct (and useless) berkeley_db_svc (#585174) - -* Wed Mar 24 2010 Panu Matilainen - 4.8.0-13 -- fix python match iterator regression wrt boolean representation - -* Wed Mar 17 2010 Panu Matilainen - 4.8.0-12 -- unbreak find-lang --with-man from yesterdays braindamage - -* Tue Mar 16 2010 Panu Matilainen - 4.8.0-11 -- support single PPD providing driver for devices (#568351) -- merge the psdriver patch pile into one -- preserve empty lines in spec prep section (#573339) -- teach python bindings about RPMTRANS_FLAG_NOCONTEXTS (related to #573111) -- dont own localized man directories through find_lang (#569536) - -* Mon Feb 15 2010 Panu Matilainen - 4.8.0-10 -- drop bogus dependency on lzma, xz is used to handle the lzma format too - -* Fri Feb 05 2010 Panu Matilainen - 4.8.0-9 -- unbreak python(abi) requires generation (#562906) - -* Fri Feb 05 2010 Panu Matilainen - 4.8.0-8 -- more fixes to postscript provides extractor (#562228) -- avoid accessing unrelated mount points in disk space checking (#547548) -- fix disk space checking with erasures present in transaction (#561160) - -* Fri Feb 05 2010 Panu Matilainen - 4.8.0-7 -- couple of fixes to the postscript provides extractor (#538101) - -* Thu Feb 04 2010 Panu Matilainen - 4.8.0-6 -- extract provides for postscript printer drivers (#538101) - -* Wed Feb 03 2010 Panu Matilainen - 4.8.0-5 -- python byte-compilation fixes + improvements (#558997) - -* Sat Jan 30 2010 Panu Matilainen - 4.8.0-4 -- support parallel python versions in python dependency extractor (#532118) - -* Thu Jan 21 2010 Panu Matilainen - 4.8.0-3 -- fix segfault on failed url retrieval -- fix verification error code depending on verbosity level -- if anything in testsuite fails, dump out the log - -* Fri Jan 08 2010 Panu Matilainen - 4.8.0-2 -- put disttag back, accidentally nuked in 4.8.0 final update - -* Fri Jan 08 2010 Panu Matilainen - 4.8.0-1 -- update to 4.8.0 final (http://rpm.org/wiki/Releases/4.8.0) - -* Thu Jan 07 2010 Panu Matilainen - 4.8.0-0.beta1.6 -- pull out macro scoping "fix" for now, it breaks font package macros - -* Mon Jan 04 2010 Panu Matilainen - 4.8.0-0.beta1.5 -- always clear locally defined macros when they go out of scope - -* Thu Dec 17 2009 Panu Matilainen - 4.8.0-0.beta1.4 -- permit unexpanded macros when parsing spec (#547997) - -* Wed Dec 09 2009 Panu Matilainen - 4.8.0-0.beta1.3 -- fix a bunch of python refcount-errors causing major memory leaks - -* Mon Dec 07 2009 Panu Matilainen - 4.8.0-0.beta1.2 -- fix noise from python bytecompile on non-python packages (#539635) -- make all our -devel [build]requires isa-specific -- trim out superfluous -devel dependencies from rpm-devel - -* Mon Dec 07 2009 Panu Matilainen - 4.8.0-0.beta1.1 -- update to 4.8.0-beta1 (http://rpm.org/wiki/Releases/4.8.0) -- rpm-build conflicts with current ocaml-runtime - -* Fri Dec 04 2009 Panu Matilainen - 4.7.2-2 -- missing error exit code from signing password checking (#496754) -- dont fail build on unrecognized data files (#532489) -- dont try to parse subkeys and secret keys (#436812) -- fix chmod test on selinux, breaking %%{_fixperms} macro (#543035) - -* Wed Nov 25 2009 Panu Matilainen - 4.7.2-1 -- update to 4.7.2 (http://rpm.org/wiki/Releases/4.7.2) -- fixes #464750, #529214 - -* Wed Nov 18 2009 Jindrich Novy - 4.7.1-10 -- rebuild against BDB-4.8.24 - -* Wed Nov 18 2009 Jindrich Novy - 4.7.1-9 -- drop versioned dependency to BDB - -* Wed Oct 28 2009 Panu Matilainen - 4.7.1-8 -- support multiple python implementations in brp-python-bytecompile (#531117) -- make disk space problem reporting a bit saner (#517418) - -* Tue Oct 06 2009 Panu Matilainen - 4.7.1-7 -- fix build with BDB 4.8.x by removing XA "support" from BDB backend -- perl dep extractor heredoc parsing improvements (#524929) - -* Mon Sep 21 2009 Panu Matilainen - 4.7.1-6 -- use relative paths within db environment (related to #507309, #507309...) -- remove db environment on close in chrooted operation (related to above) -- initialize rpmlib earlier in rpm2cpio (#523260) -- fix file dependency tag extension formatting (#523282) - -* Tue Sep 15 2009 Panu Matilainen - 4.7.1-5 -- fix duplicate dependency filtering on build (#490378) -- permit absolute paths in file lists again (#521760) -- use permissions 444 for all .debug files (#522194) -- add support for optional bugurl tag (#512774) - -* Fri Aug 14 2009 Jesse Keating - 4.7.1-4 -- Patch to make geode appear as i686 (#517475) - -* Thu Aug 06 2009 Jindrich Novy - 4.7.1-3 -- rebuild because of the new xz - -* Sun Jul 26 2009 Fedora Release Engineering - 4.7.1-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Tue Jul 21 2009 Panu Matilainen - 4.7.1-1 -- update to 4.7.1 ((http://rpm.org/wiki/Releases/4.7.1) -- fix source url - -* Mon Jul 20 2009 Bill Nottingham - 4.7.0-9 -- enable XZ support - -* Thu Jun 18 2009 Panu Matilainen - 4.7.0-8 -- updated OSGi dependency extractor (#506471) -- fix segfault in symlink fingerprinting (#505777) -- fix invalid memory access causing bogus file dependency errors (#506323) - -* Tue Jun 16 2009 Panu Matilainen - 4.7.0-7 -- add dwarf-3 support to debugedit (#505774) - -* Fri Jun 12 2009 Stepan Kasal - 4.7.0-6 -- require libcap >= 2.16 (#505596) - -* Wed Jun 03 2009 Panu Matilainen - 4.7.0-5 -- don't mess up problem altNEVR in python ts.check() (#501068) -- fix hardlink size calculation on build (#503020) - -* Thu May 14 2009 Panu Matilainen - 4.7.0-4 -- split cron-job into a sub-package to avoid silly deps on core rpm (#500722) -- rpm requires coreutils but not in %%post -- build with libcap and libacl -- fix pgp pubkey signature tag parsing - -* Tue Apr 21 2009 Panu Matilainen - 4.7.0-3 -- couple of merge-review fixes (#226377) - - eliminate bogus leftover rpm:rpm rpmdb ownership - - unescaped macro in changelog -- fix find-lang --with-kde with KDE3 (#466009) -- switch back to default file digest algorithm - -* Fri Apr 17 2009 Panu Matilainen - 4.7.0-2 -- file classification tweaks for text files (#494817) - - disable libmagic text token checks, it's way too error-prone - - consistently classify all text as such and include description - -* Thu Apr 16 2009 Panu Matilainen - 4.7.0-1 -- update to 4.7.0 final (http://rpm.org/wiki/Releases/4.7.0) -- fixes #494049, #495429 -- dont permit test-suite failure anymore - -* Thu Apr 09 2009 Panu Matilainen - 4.7.0-0.rc1.1 -- update to 4.7.0-rc1 -- fixes #493157, #493777, #493696, #491388, #487597, #493162 - -* Fri Apr 03 2009 Panu Matilainen - 4.7.0-0.beta1.9 -- fix recorded file state of otherwise skipped files (#492947) -- compress ChangeLog, drop old CHANGES file (#492440) - -* Thu Apr 2 2009 Tom "spot" Callaway - 4.7.0-0.beta1.8 -- Fix sparcv9v and sparc64v targets - -* Tue Mar 24 2009 Panu Matilainen - 4.7.0-0.beta1.7 -- prefer more specific types over generic "text" in classification (#491349) - -* Mon Mar 23 2009 Panu Matilainen - 4.7.0-0.beta1.6 -- with the fd leak gone, let libmagic look into compressed files again (#491596) - -* Mon Mar 23 2009 Panu Matilainen - 4.7.0-0.beta1.5 -- fix font provide generation on filenames with whitespace (#491597) - -* Thu Mar 12 2009 Panu Matilainen - 4.7.0-0.beta1.4 -- handle RSA V4 signatures (#436812) -- add alpha arch ISA-bits -- enable internal testsuite on build - -* Mon Mar 09 2009 Panu Matilainen - 4.7.0-0.beta1.3 -- fix _install_langs behavior (#489235) -- fix recording of file states into rpmdb on install - -* Sun Mar 08 2009 Panu Matilainen - 4.7.0-0.beta1.2 -- load macros before creating directories on src.rpm install (#489104) - -* Fri Mar 06 2009 Panu Matilainen - 4.7.0-0.beta1.1 -- update to 4.7.0-beta1 (http://rpm.org/wiki/Releases/4.7.0) - -* Fri Feb 27 2009 Panu Matilainen - 4.6.0-11 -- build rpm itself with md5 file digests for now to ensure upgradability - -* Thu Feb 26 2009 Panu Matilainen - 4.6.0-10 -- handle NULL passed as EVR in rpmdsSingle() again (#485616) - -* Wed Feb 25 2009 Panu Matilainen - 4.6.0-9 -- pull out python byte-compile syntax check for now - -* Mon Feb 23 2009 Panu Matilainen - 4.6.0-8 -- make -apidocs sub-package noarch -- fix source URL - -* Sat Feb 21 2009 Panu Matilainen - 4.6.0-7 -- loosen up restrictions on dependency names (#455119) -- handle inter-dependent pkg-config files for requires too (#473814) -- error/warn on elf binaries in noarch package in build - -* Fri Feb 20 2009 Panu Matilainen - 4.6.0-6 -- error out on uncompilable python code (Tim Waugh) - -* Tue Feb 17 2009 Jindrich Novy - 4.6.0-5 -- remove two offending hunks from anyarch patch causing that - RPMTAG_BUILDARCHS isn't written to SRPMs - -* Mon Feb 16 2009 Jindrich Novy - 4.6.0-4 -- inherit group tag from the main package (#470714) -- ignore BuildArch tags for anyarch actions (#442105) -- don't check package BuildRequires when doing --rmsource (#452477) -- don't fail because of missing sources when only spec removal - is requested (#472427) - -* Mon Feb 16 2009 Panu Matilainen - 4.6.0-3 -- updated fontconfig provide script - fc-query does all the hard work now - -* Mon Feb 09 2009 Panu Matilainen - 4.6.0-2 -- build against db 4.7.x - -* Fri Feb 06 2009 Panu Matilainen - 4.6.0-1 -- update to 4.6.0 final -- revert libmagic looking into compressed files for now, breaks ooffice build - -* Fri Feb 06 2009 Panu Matilainen - 4.6.0-0.rc4.5 -- enable fontconfig provides generation - -* Thu Feb 05 2009 Panu Matilainen - 4.6.0-0.rc4.4 -- fixup rpm translation lookup to match Fedora specspo (#436941) - -* Wed Feb 04 2009 Panu Matilainen - 4.6.0-0.rc4.3 -- extract mimehandler provides from .desktop files -- preliminaries for extracting font provides (not enabled yet) -- dont classify font metrics data as fonts -- only run script dep extraction once per file, duh - -* Sat Jan 31 2009 Panu Matilainen - 4.6.0-0.rc4.2 -- change platform sharedstatedir to something more sensible (#185862) -- add rpmdb_foo links to db utils for documentation compatibility - -* Fri Jan 30 2009 Panu Matilainen - 4.6.0-0.rc4.1 -- update to 4.6.0-rc4 -- fixes #475582, #478907, #476737, #479869, #476201 - -* Fri Dec 12 2008 Panu Matilainen - 4.6.0-0.rc3.2 -- add back defaultdocdir patch which hadn't been applied on 4.6.x branch yet - -* Fri Dec 12 2008 Panu Matilainen - 4.6.0-0.rc3.1 -- add dist-tag, rebuild - -* Tue Dec 09 2008 Panu Matilainen - 4.6.0-0.rc3.1 -- update to rpm 4.6.0-rc3 -- fixes #475214, #474550, #473239 - -* Wed Dec 3 2008 Jeremy Katz - 4.6.0-0.rc2.9 -- I built into the wrong place - -* Wed Dec 3 2008 Jeremy Katz - 4.6.0-0.rc2.8 -- python 2.6 rebuild again - -* Wed Dec 03 2008 Panu Matilainen -- make rpm-build require pkgconfig (#473978) - -* Tue Dec 02 2008 Panu Matilainen -- fix pkg-config provide generation when pc's depend on each other (#473814) - -* Mon Dec 01 2008 Jindrich Novy -- include rpmfileutil.h from rpmmacro.h, unbreaks - net-snmp (#473420) - -* Sun Nov 30 2008 Panu Matilainen -- rebuild for python 2.6 - -* Sat Nov 29 2008 Panu Matilainen -- update to 4.6.0-rc2 -- fixes #471820, #473167, #469355, #468319, #472507, #247374, #426672, #444661 -- enable automatic generation of pkg-config and libtool dependencies #465377 - -* Fri Oct 31 2008 Panu Matilainen -- adjust find-debuginfo for "file" output change (#468129) - -* Tue Oct 28 2008 Panu Matilainen -- Florian's improved fingerprinting hash algorithm from upstream - -* Sat Oct 25 2008 Panu Matilainen -- Make noarch sub-packages actually work -- Fix defaultdocdir logic in installplatform to avoid hardwiring mandir - -* Fri Oct 24 2008 Jindrich Novy -- update compat-db dependencies (#459710) - -* Wed Oct 22 2008 Panu Matilainen -- never add identical NEVRA to transaction more than once (#467822) - -* Sun Oct 19 2008 Panu Matilainen -- permit tab as macro argument separator (#467567) - -* Thu Oct 16 2008 Panu Matilainen -- update to 4.6.0-rc1 -- fixes #465586, #466597, #465409, #216221, #466503, #466009, #463447... -- avoid using %%configure macro for now, it has unwanted side-effects on rpm - -* Wed Oct 01 2008 Panu Matilainen -- update to official 4.5.90 alpha tarball -- a big pile of misc bugfixes + translation updates -- isa-macro generation fix for ppc (#464754) -- avoid pulling in pile of perl dependencies for an unused script -- handle both "invalid argument" and clear env version mismatch on posttrans - -* Thu Sep 25 2008 Jindrich Novy -- don't treat %%patch numberless if -P parameter is present (#463942) - -* Thu Sep 11 2008 Panu Matilainen -- add hack to support extracting gstreamer plugin provides (#438225) -- fix another macro argument handling regression (#461180) - -* Thu Sep 11 2008 Jindrich Novy -- create directory structure for rpmbuild prior to build if it doesn't exist (#455387) -- create _topdir if it doesn't exist when installing SRPM -- don't generate broken cpio in case of hardlink pointing on softlink, - thanks to pixel@mandriva.com - -* Sat Sep 06 2008 Jindrich Novy -- fail hard if patch isn't found (#461347) - -* Mon Sep 01 2008 Jindrich Novy -- fix parsing of boolean expressions in spec (#456103) - (unbreaks pam, jpilot and maybe other builds) - -* Tue Aug 26 2008 Jindrich Novy -- add support for noarch subpackages -- fix segfault in case of insufficient disk space detected (#460146) - -* Wed Aug 13 2008 Panu Matilainen -- 4.5.90-0.git8461.2 -- fix archivesize tag generation on ppc (#458817) - -* Fri Aug 08 2008 Panu Matilainen -- 4.5.90-0.git8461.1 -- new snapshot from upstream -- fixes #68290, #455972, #446202, #453364, #456708, #456103, #456321, #456913, - #458260, #458261 -- partial fix for #457360 - -* Thu Jul 31 2008 Florian Festi -- 4.5.90-0.git8427.1 -- new snapshot from upstream - -* Thu Jul 31 2008 Florian Festi -- 4.5.90-0.git8426.10 -- rpm-4.5.90-posttrans.patch -- use header from rpmdb in posttrans to make anaconda happy - -* Sat Jul 19 2008 Panu Matilainen -- 4.5.90-0.git8426.9 -- fix regression in patch number handling (#455872) - -* Tue Jul 15 2008 Panu Matilainen -- 4.5.90-0.git8426.8 -- fix regression in macro argument handling (#455333) - -* Mon Jul 14 2008 Panu Matilainen -- 4.5.90-0.git8426.7 -- fix mono dependency extraction (adjust for libmagic string change) - -* Sat Jul 12 2008 Panu Matilainen -- 4.5.90-0.git8426.6 -- fix type mismatch causing funky breakage on ppc64 - -* Fri Jul 11 2008 Panu Matilainen -- 4.5.90-0.git8426.5 -- flip back to external bdb -- fix tab vs spaces complaints from rpmlint -- add dep for lzma and require unzip instead of zip in build (#310694) -- add pkgconfig dependency to rpm-devel -- drop ISA-dependencies for initial introduction -- new snapshot from upstream for documentation fixes - -* Thu Jul 10 2008 Panu Matilainen -- 4.5.90-0.git8424.4 -- handle int vs external db in posttrans too - -* Wed Jul 09 2008 Panu Matilainen -- 4.5.90-0.git8424.3 -- require curl as external url helper - -* Wed Jul 09 2008 Panu Matilainen -- 4.5.90-0.git8424.2 -- add support for building with or without internal db - -* Wed Jul 09 2008 Panu Matilainen -- rpm 4.5.90-0.git8424.1 (alpha snapshot) -- adjust to build against Berkeley DB 4.5.20 from compat-db for now -- add posttrans to clean up db environment mismatch after upgrade -- forward-port devel autodeps patch - -* Tue Jul 08 2008 Panu Matilainen -- adjust for rpmdb index name change -- drop unnecessary vendor-macro patch for real -- add ISA-dependencies among rpm subpackages -- make lzma and sqlite deps conditional and disabled by default for now - -* Fri Feb 01 2008 Panu Matilainen -- spec largely rewritten, truncating changelog diff --git a/compile-with-Platform-Python-binary-where-relevant.patch b/compile-with-Platform-Python-binary-where-relevant.patch new file mode 100644 index 0000000..7b0da28 --- /dev/null +++ b/compile-with-Platform-Python-binary-where-relevant.patch @@ -0,0 +1,26 @@ +From 682397a8e2758058f780cccd51b570d39415b9b2 Mon Sep 17 00:00:00 2001 +From: Tomas Orsava +Date: Tue, 3 Jul 2018 14:58:32 +0200 +Subject: [PATCH] Compile with Platform-Python binary where relevant + +--- + scripts/brp-python-bytecompile | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile +index 7ed1d7f..9d0a421 100644 +--- a/scripts/brp-python-bytecompile ++++ b/scripts/brp-python-bytecompile +@@ -60,6 +60,9 @@ shopt -s nullglob + 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 ++ python_binary=/usr/libexec/platform-python ++ fi + real_libdir=${python_libdir/$RPM_BUILD_ROOT/} + echo "Bytecompiling .py files below $python_libdir using $python_binary" + +-- +2.14.4 + diff --git a/disable-python-extra.patch b/disable-python-extra.patch new file mode 100644 index 0000000..8cb7595 --- /dev/null +++ b/disable-python-extra.patch @@ -0,0 +1,11 @@ +--- a/platform.in 2018-07-19 17:24:58.737922904 +0200 ++++ b/platform.in 2018-07-19 17:25:25.480028741 +0200 +@@ -65,7 +65,7 @@ + + %__arch_install_post @ARCH_INSTALL_POST@ + %_python_bytecompile_errors_terminate_build 0 +-%_python_bytecompile_extra 1 ++%_python_bytecompile_extra 0 + + # Standard brp-macro naming: + # convert all '-' in basename to '_', add two leading underscores. diff --git a/measure.patch b/measure.patch new file mode 100644 index 0000000..b0c580f --- /dev/null +++ b/measure.patch @@ -0,0 +1,279 @@ +From 517a37ae7beeb77e2b4870be11611f82c1200b3c Mon Sep 17 00:00:00 2001 +From: Matthew Almond +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 ++#include ++#include ++#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 + diff --git a/ndb_query_ro_media.patch b/ndb_query_ro_media.patch new file mode 100644 index 0000000..92393eb --- /dev/null +++ b/ndb_query_ro_media.patch @@ -0,0 +1,23 @@ +From 93e482be29ee683011c71f23b3b0096889e50331 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +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; diff --git a/rpm-4-14.3-selinux-log-error.patch b/rpm-4-14.3-selinux-log-error.patch new file mode 100644 index 0000000..f16a908 --- /dev/null +++ b/rpm-4-14.3-selinux-log-error.patch @@ -0,0 +1,11 @@ +--- rpm-4.14.3/plugins/selinux.c.orig 2020-05-11 16:07:22.873791795 +0200 ++++ rpm-4.14.3/plugins/selinux.c 2020-05-11 16:10:11.701771157 +0200 +@@ -47,7 +47,7 @@ + + sehandle = selabel_open(SELABEL_CTX_FILE, opts, 1); + +- rpmlog(RPMLOG_DEBUG, "selabel_open: (%s) %s\n", ++ rpmlog((sehandle == NULL) ? RPMLOG_ERR : RPMLOG_DEBUG, "selabel_open: (%s) %s\n", + path, (sehandle == NULL ? strerror(errno) : "")); + + return (sehandle != NULL) ? RPMRC_OK : RPMRC_FAIL; diff --git a/rpm-4.11.x-siteconfig.patch b/rpm-4.11.x-siteconfig.patch new file mode 100644 index 0000000..f32f859 --- /dev/null +++ b/rpm-4.11.x-siteconfig.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.11.1-rc1/macros.in.siteconfig rpm-4.11.1-rc1/macros.in +--- rpm-4.11.1-rc1/macros.in.siteconfig 2013-06-07 13:19:21.000000000 +0300 ++++ rpm-4.11.1-rc1/macros.in 2013-06-11 15:06:59.525747503 +0300 +@@ -647,6 +647,8 @@ package or when debugging this package.\ + export CLASSPATH}\ + PKG_CONFIG_PATH=\"${PKG_CONFIG_PATH}:%{_libdir}/pkgconfig:%{_datadir}/pkgconfig\"\ + export PKG_CONFIG_PATH\ ++ CONFIG_SITE=${CONFIG_SITE:-NONE}\ ++ export CONFIG_SITE\ + \ + %{verbose:set -x}%{!verbose:exec > /dev/null}\ + umask 022\ diff --git a/rpm-4.12.0-rpm2cpio-hack.patch b/rpm-4.12.0-rpm2cpio-hack.patch new file mode 100644 index 0000000..38c7dbd --- /dev/null +++ b/rpm-4.12.0-rpm2cpio-hack.patch @@ -0,0 +1,18 @@ +diff --git a/rpm2cpio.c b/rpm2cpio.c +index 89ebdfa..ae999ff 100644 +--- a/rpm2cpio.c ++++ b/rpm2cpio.c +@@ -84,7 +84,12 @@ int main(int argc, char *argv[]) + exit(EXIT_FAILURE); + } + +- rc = (ufdCopy(gzdi, fdo) == payload_size) ? EXIT_SUCCESS : EXIT_FAILURE; ++ /* ++ * XXX HACK for #1142949: should be equality test, but archive size ++ * short by cpio trailer size in packages built with rpm 4.12.0 ++ * and its pre-releases. ++ */ ++ rc = (ufdCopy(gzdi, fdo) >= payload_size) ? EXIT_SUCCESS : EXIT_FAILURE; + + Fclose(fdo); + diff --git a/rpm-4.13.0-fedora-specspo.patch b/rpm-4.13.0-fedora-specspo.patch new file mode 100644 index 0000000..64416c7 --- /dev/null +++ b/rpm-4.13.0-fedora-specspo.patch @@ -0,0 +1,95 @@ +diff --git a/lib/tagexts.c b/lib/tagexts.c +index f72ff60..2c0b179 100644 +--- a/lib/tagexts.c ++++ b/lib/tagexts.c +@@ -535,15 +535,6 @@ static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags) + return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags); + } + +-/* I18N look aside diversions */ +- +-#if defined(ENABLE_NLS) +-extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ +-#endif +-static const char * const language = "LANGUAGE"; +- +-static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; +- + /** + * Retrieve i18n text. + * @param h header +@@ -554,59 +545,30 @@ static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; + */ + static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags) + { +- int rc; ++ int rc = headerGet(h, tag, td, HEADERGET_ALLOC); + #if defined(ENABLE_NLS) +- char * dstring = rpmExpand(_macro_i18ndomains, NULL); +- +- td->type = RPM_STRING_TYPE; +- td->data = NULL; +- td->count = 0; +- +- if (dstring && *dstring) { +- char *domain, *de; +- const char * langval; +- char * msgkey; +- const char * msgid; ++ if (rc) { ++ static const char * const _macro_i18ndomains = "%{?_i18ndomains}"; ++ char *de, *dstring = rpmExpand(_macro_i18ndomains, NULL); ++ const char *domain; + +- rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME), +- rpmTagGetName(tag)); +- +- /* change to en_US for msgkey -> msgid resolution */ +- langval = getenv(language); +- (void) setenv(language, "en_US", 1); +- ++_nl_msg_cat_cntr; +- +- msgid = NULL; + for (domain = dstring; domain != NULL; domain = de) { ++ const char *msgid = td->data; ++ const char *msg = NULL; ++ + de = strchr(domain, ':'); + if (de) *de++ = '\0'; +- msgid = dgettext(domain, msgkey); +- if (msgid != msgkey) break; +- } +- +- /* restore previous environment for msgid -> msgstr resolution */ +- if (langval) +- (void) setenv(language, langval, 1); +- else +- unsetenv(language); +- ++_nl_msg_cat_cntr; +- +- if (domain && msgid) { +- td->data = dgettext(domain, msgid); +- td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */ +- td->count = 1; +- td->flags = RPMTD_ALLOCED; ++ msg = dgettext(domain, td->data); ++ if (msg != msgid) { ++ free(td->data); ++ td->data = xstrdup(msg); ++ break; ++ } + } +- dstring = _free(dstring); +- free(msgkey); +- if (td->data) +- return 1; ++ free(dstring); + } +- +- free(dstring); + #endif + +- rc = headerGet(h, tag, td, HEADERGET_ALLOC); + return rc; + } + diff --git a/rpm-4.13.90-ldflags.patch b/rpm-4.13.90-ldflags.patch new file mode 100644 index 0000000..99152e8 --- /dev/null +++ b/rpm-4.13.90-ldflags.patch @@ -0,0 +1,16 @@ +diff -up rpm-4.9.1.1/macros.in.jx rpm-4.9.1.1/macros.in +--- rpm-4.9.1.1/macros.in.jx 2011-08-03 16:19:05.000000000 -0400 ++++ rpm-4.9.1.1/macros.in 2011-08-08 09:41:52.981064316 -0400 +@@ -674,10 +674,11 @@ print (t)\ + RPM_SOURCE_DIR=\"%{u2p:%{_sourcedir}}\"\ + RPM_BUILD_DIR=\"%{u2p:%{_builddir}}\"\ + RPM_OPT_FLAGS=\"%{optflags}\"\ ++ RPM_LD_FLAGS=\"%{?__global_ldflags}\"\ + RPM_ARCH=\"%{_arch}\"\ + RPM_OS=\"%{_os}\"\ + RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\ +- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ ++ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_LD_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\ + RPM_DOC_DIR=\"%{_docdir}\"\ + export RPM_DOC_DIR\ + RPM_PACKAGE_NAME=\"%{NAME}\"\ diff --git a/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch b/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch new file mode 100644 index 0000000..361e1a4 --- /dev/null +++ b/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch @@ -0,0 +1,28 @@ +From bf636421120aa2c97f9e0fdcee3c211b4241bd86 Mon Sep 17 00:00:00 2001 +From: Tomas Orsava +Date: Mon, 29 Jan 2018 16:13:18 +0100 +Subject: [PATCH] Add envvar that will be present during RPM build + +Part of a Fedora Change for F28: +"Avoid /usr/bin/python in RPM build" +https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build +--- + macros.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/macros.in b/macros.in +index dd6ef67..68449e3 100644 +--- a/macros.in ++++ b/macros.in +@@ -804,6 +804,8 @@ package or when debugging this package.\ + export PKG_CONFIG_PATH\ + CONFIG_SITE=${CONFIG_SITE:-NONE}\ + export CONFIG_SITE\ ++ PYTHON_DISALLOW_AMBIGUOUS_VERSION=warn\ ++ export PYTHON_DISALLOW_AMBIGUOUS_VERSION\ + \ + %{verbose:set -x}%{!verbose:exec > /dev/null}\ + umask 022\ +-- +2.13.6 + diff --git a/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch b/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch new file mode 100644 index 0000000..4c7c52c --- /dev/null +++ b/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch @@ -0,0 +1,107 @@ +From 8390fa8515f499994646cf3bd113423744dc7bd9 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Fri, 30 Nov 2018 11:02:52 +0100 +Subject: [PATCH] Add RPMTAG_MODULARITYLABEL to distinguish packages build for + modularity + +Tag can be set with a ModularityLabel: statement in the spec file preamble or +via the modularitylabel macro +--- + build/parsePreamble.c | 4 ++++ + build/parseSpec.c | 1 + + lib/rpmtag.h | 1 + + macros.in | 5 +++++ + tests/rpmgeneral.at | 1 + + 5 files changed, 12 insertions(+) + +diff --git a/build/parsePreamble.c b/build/parsePreamble.c +index f5e06bac8..e340e5c7a 100644 +--- a/build/parsePreamble.c ++++ b/build/parsePreamble.c +@@ -43,6 +43,7 @@ static const rpmTagVal copyTagsDuringParse[] = { + RPMTAG_DISTTAG, + RPMTAG_BUGURL, + RPMTAG_GROUP, ++ RPMTAG_MODULARITYLABEL, + 0 + }; + +@@ -526,6 +527,7 @@ static struct optionalTag { + { RPMTAG_DISTURL, "%{disturl}" }, + { RPMTAG_DISTTAG, "%{disttag}" }, + { RPMTAG_BUGURL, "%{bugurl}" }, ++ { RPMTAG_MODULARITYLABEL, "%{modularitylabel}"}, + { -1, NULL } + }; + +@@ -779,6 +781,7 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, + case RPMTAG_URL: + case RPMTAG_DISTTAG: + case RPMTAG_BUGURL: ++ case RPMTAG_MODULARITYLABEL: + /* XXX TODO: validate format somehow */ + case RPMTAG_VCS: + SINGLE_TOKEN_ONLY; +@@ -1018,6 +1021,7 @@ static struct PreambleRec_s const preambleList[] = { + {RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")}, + {RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")}, + {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")}, ++ {RPMTAG_MODULARITYLABEL, 0, 0, LEN_AND_STR("modularitylabel")}, + {0, 0, 0, 0} + }; + +diff --git a/build/parseSpec.c b/build/parseSpec.c +index bf4789942..c80802baf 100644 +--- a/build/parseSpec.c ++++ b/build/parseSpec.c +@@ -517,6 +517,7 @@ static const rpmTagVal sourceTags[] = { + RPMTAG_BUGURL, + RPMTAG_HEADERI18NTABLE, + RPMTAG_VCS, ++ RPMTAG_MODULARITYLABEL, + 0 + }; + +diff --git a/lib/rpmtag.h b/lib/rpmtag.h +index 973a6b69d..b9623ef24 100644 +--- a/lib/rpmtag.h ++++ b/lib/rpmtag.h +@@ -368,6 +368,7 @@ + RPMTAG_FILESIGNATURELENGTH = 5091, /* i */ + RPMTAG_PAYLOADDIGEST = 5092, /* s[] */ + RPMTAG_PAYLOADDIGESTALGO = 5093, /* i */ ++ RPMTAG_MODULARITYLABEL = 5096, /* s */ + + RPMTAG_FIRSTFREE_TAG /*!< internal */ + } rpmTag; +diff --git a/macros.in b/macros.in +index e0a1aea4e..cb4929c10 100644 +--- a/macros.in ++++ b/macros.in +@@ -357,6 +357,11 @@ package or when debugging this package.\ + %_javadir %{_datadir}/java + %_javadocdir %{_datadir}/javadoc + ++ ++# Set ModularityLabel: for packages being build ++# ++#%modularitylabel ++ + # A colon separated list of paths where files should *not* be installed. + # Usually, these are network file system mount points. + # +diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at +index 509277f2c..45d38698b 100644 +--- a/tests/rpmgeneral.at ++++ b/tests/rpmgeneral.at +@@ -150,6 +150,7 @@ LONGARCHIVESIZE + LONGFILESIZES + LONGSIGSIZE + LONGSIZE ++MODULARITYLABEL + N + NAME + NEVR +-- +2.17.2 + diff --git a/rpm-4.14.2-audit-3.patch b/rpm-4.14.2-audit-3.patch new file mode 100644 index 0000000..65a2b3f --- /dev/null +++ b/rpm-4.14.2-audit-3.patch @@ -0,0 +1,275 @@ +From 820dcc1db9f2130a21fdaf721217034376eb8e38 Mon Sep 17 00:00:00 2001 +Message-Id: <820dcc1db9f2130a21fdaf721217034376eb8e38.1544785848.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Fri, 30 Nov 2018 13:10:44 +0200 +Subject: [PATCH] Add support for logging audit events for package installs as + per OSPP v4.2 + +If enabled at build-time, log audit events for package install, update +and remove. The log includes the operation, package nevra, signature +check result, whether signatures are being enforced enforced and overall +success result. Package install/update/remove are logged as such, +obsoletion is logged as install + remove (whereas the erasure element +on updates is silent) + +Loosely based on initial RHEL 7-8 implementations by Pavlina Moravcova +Varekova and Florian Festi (RhBug:1555326, RhBug:1607612) + +(cherry picked from commit cfc9dde70fe65e91c83e03e9a9441e627b741489) +--- + configure.ac | 21 +++++++++ + lib/Makefile.am | 1 + + lib/rpmte.c | 11 +++++ + lib/rpmte_internal.h | 6 +++ + lib/transaction.c | 104 +++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 143 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 34ea85f9f..ab8a368d3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -312,6 +312,27 @@ fi + AC_SUBST(WITH_BEECRYPT_LIB) + AC_SUBST(WITH_BEECRYPT_INCLUDE) + ++ ++#================= ++# Check for audit library. ++AC_ARG_WITH(audit, ++AS_HELP_STRING([--with-audit],[log results using Linux Audit]), ++with_audit=$withval, ++with_audit=auto) ++ ++WITH_AUDIT_LIB= ++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]) ++ ], ++ [if test "x$with_audit" != xauto; then ++ AC_MSG_ERROR([missing audit library]) ++ fi ++ ]) ++]) ++AC_SUBST(WITH_AUDIT_LIB) ++ + #================= + # Check for OpenSSL library. + # We need evp.h from OpenSSL. +diff --git a/lib/Makefile.am b/lib/Makefile.am +index baf3238ee..c055962a3 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -51,6 +51,7 @@ librpm_la_LIBADD = \ + @WITH_POPT_LIB@ \ + @WITH_CAP_LIB@ \ + @WITH_ACL_LIB@ \ ++ @WITH_AUDIT_LIB@ \ + @LIBINTL@ + + if WITH_LUA +diff --git a/lib/rpmte.c b/lib/rpmte.c +index d980a37a4..bd5d53edc 100644 +--- a/lib/rpmte.c ++++ b/lib/rpmte.c +@@ -69,6 +69,7 @@ struct rpmte_s { + int nrelocs; /*!< (TR_ADDED) No. of relocations. */ + uint8_t *badrelocs; /*!< (TR_ADDED) Bad relocations (or NULL) */ + FD_t fd; /*!< (TR_ADDED) Payload file descriptor. */ ++ int verified; /*!< (TR_ADDED) Verification status */ + + #define RPMTE_HAVE_PRETRANS (1 << 0) + #define RPMTE_HAVE_POSTTRANS (1 << 1) +@@ -753,6 +754,16 @@ rpmfs rpmteGetFileStates(rpmte te) + return te->fs; + } + ++void rpmteSetVerified(rpmte te, int verified) ++{ ++ te->verified = verified; ++} ++ ++int rpmteGetVerified(rpmte te) ++{ ++ return te->verified; ++} ++ + int rpmteProcess(rpmte te, pkgGoal goal, int num) + { + /* Only install/erase resets pkg file info */ +diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h +index a5a991ec5..2895925ce 100644 +--- a/lib/rpmte_internal.h ++++ b/lib/rpmte_internal.h +@@ -86,6 +86,12 @@ int rpmteHaveTransScript(rpmte te, rpmTagVal tag); + /* XXX should be internal too but build code needs for now... */ + rpmfs rpmteGetFileStates(rpmte te); + ++RPM_GNUC_INTERNAL ++void rpmteSetVerified(rpmte te, int verified); ++ ++RPM_GNUC_INTERNAL ++int rpmteGetVerified(rpmte te); ++ + /** \ingroup rpmte + * Retrieve size in bytes of package header. + * @param te transaction element +diff --git a/lib/transaction.c b/lib/transaction.c +index 67b9db579..866e87fc2 100644 +--- a/lib/transaction.c ++++ b/lib/transaction.c +@@ -7,6 +7,10 @@ + #include + #include + ++#if WITH_AUDIT ++#include ++#endif ++ + #include /* rpmMachineScore, rpmReadPackageFile */ + #include /* XXX for rpmExpand */ + #include +@@ -1195,12 +1199,17 @@ static rpm_loff_t countPkgs(rpmts ts, rpmElementTypes types) + + struct vfydata_s { + char *msg; ++ int signature; + int vfylevel; + }; + + static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata) + { + struct vfydata_s *vd = cbdata; ++ ++ if (sinfo->type == RPMSIG_SIGNATURE_TYPE && sinfo->rc == RPMRC_OK) ++ vd->signature = RPMRC_OK; ++ + switch (sinfo->rc) { + case RPMRC_OK: + break; +@@ -1241,6 +1250,7 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) + struct rpmvs_s *vs = rpmvsCreate(vfylevel, vsflags, keyring); + struct vfydata_s vd = { + .msg = NULL, ++ .signature = RPMRC_NOTFOUND, + .vfylevel = vfylevel, + }; + rpmRC prc = RPMRC_FAIL; +@@ -1255,6 +1265,9 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) + if (prc == RPMRC_OK) + prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); + ++ /* Record verify result, signatures only for now */ ++ rpmteSetVerified(p, vd.signature == RPMRC_OK); ++ + if (prc) + rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0); + +@@ -1619,6 +1632,95 @@ rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes, + return rc; + } + ++#if WITH_AUDIT ++struct teop { ++ rpmte te; ++ const char *op; ++}; ++ ++/* ++ * Figure out the actual operations: ++ * Install and remove are straightforward. Updates need to discovered ++ * via their erasure element: locate the updating element, adjust it's ++ * op to update and silence the erasure part. Obsoletion is handled as ++ * as install + remove, which it technically is. ++ */ ++static void getAuditOps(rpmts ts, struct teop *ops, int nelem) ++{ ++ rpmtsi pi = rpmtsiInit(ts); ++ rpmte p; ++ int i = 0; ++ while ((p = rpmtsiNext(pi, 0)) != NULL) { ++ const char *op = NULL; ++ if (rpmteType(p) == TR_ADDED) { ++ op = "install"; ++ } else { ++ op = "remove"; ++ rpmte d = rpmteDependsOn(p); ++ /* Fixup op on updating elements, silence the cleanup stage */ ++ if (d != NULL && rstreq(rpmteN(d), rpmteN(p))) { ++ /* Linear lookup, but we're only dealing with a few thousand */ ++ for (int x = 0; x < i; x++) { ++ if (ops[x].te == d) { ++ ops[x].op = "update"; ++ op = NULL; ++ break; ++ } ++ } ++ } ++ } ++ ops[i].te = p; ++ ops[i].op = op; ++ i++; ++ } ++ rpmtsiFree(pi); ++} ++ ++/* ++ * If enabled, log audit events for the operations in this transaction. ++ * In the event values, 1 means true/success and 0 false/failure. Shockingly. ++ */ ++static void rpmtsAudit(rpmts ts) ++{ ++ int auditFd = audit_open(); ++ if (auditFd < 0) ++ return; ++ ++ int nelem = rpmtsNElements(ts); ++ struct teop *ops = xcalloc(nelem, sizeof(*ops)); ++ char *dir = audit_encode_nv_string("root_dir", rpmtsRootDir(ts), 0); ++ int enforce = (rpmtsVfyLevel(ts) & RPMSIG_SIGNATURE_TYPE) != 0; ++ ++ getAuditOps(ts, ops, nelem); ++ ++ for (int i = 0; i < nelem; i++) { ++ const char *op = ops[i].op; ++ if (op) { ++ rpmte p = ops[i].te; ++ char *nevra = audit_encode_nv_string("sw", rpmteNEVRA(p), 0); ++ char eventTxt[256]; ++ int verified = rpmteGetVerified(p); ++ int result = (rpmteFailed(p) == 0); ++ ++ snprintf(eventTxt, sizeof(eventTxt), ++ "op=%s %s sw_type=rpm key_enforce=%u gpg_res=%u %s", ++ op, nevra, enforce, verified, dir); ++ audit_log_user_comm_message(auditFd, AUDIT_SOFTWARE_UPDATE, ++ eventTxt, NULL, NULL, NULL, NULL, result); ++ free(nevra); ++ } ++ } ++ ++ free(dir); ++ free(ops); ++ audit_close(auditFd); ++} ++#else ++static void rpmtsAudit(rpmts ts) ++{ ++} ++#endif ++ + int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) + { + int rc = -1; /* assume failure */ +@@ -1732,6 +1834,8 @@ exit: + rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc); + + /* Finish up... */ ++ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) ++ rpmtsAudit(ts); + (void) umask(oldmask); + (void) rpmtsFinish(ts); + rpmpsFree(tsprobs); +-- +2.19.2 + diff --git a/rpm-4.14.2-unversioned-python.patch b/rpm-4.14.2-unversioned-python.patch new file mode 100644 index 0000000..7e9ba8d --- /dev/null +++ b/rpm-4.14.2-unversioned-python.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.14.2/macros.in.pyerror rpm-4.14.2/macros.in +--- rpm-4.14.2/macros.in.pyerror 2019-06-04 13:33:48.450727270 +0300 ++++ rpm-4.14.2/macros.in 2019-06-04 13:34:09.717695822 +0300 +@@ -50,7 +50,7 @@ + %__mv @__MV@ + %__patch @__PATCH@ + %__perl @__PERL@ +-%__python @__PYTHON@ ++%__python %{error:attempt to use unversioned python, define %%__python to %{_bindir}/python2 or %{_bindir}/python3 explicitly} + %__restorecon @__RESTORECON@ + %__rm @__RM@ + %__rsh @__RSH@ diff --git a/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch b/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch new file mode 100644 index 0000000..05ca170 --- /dev/null +++ b/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch @@ -0,0 +1,14 @@ +diff -up rpm-4.14.3/scripts/brp-strip.orig rpm-4.14.3/scripts/brp-strip +--- rpm-4.14.3/scripts/brp-strip.orig 2021-02-09 14:43:35.393940550 +0100 ++++ rpm-4.14.3/scripts/brp-strip 2021-02-09 14:43:49.459222054 +0100 +@@ -12,9 +12,8 @@ Darwin*) exit 0 ;; + esac + + # Strip ELF binaries +-for f in `find "$RPM_BUILD_ROOT" -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -exec file {} \; | \ ++for f in `find "$RPM_BUILD_ROOT" -type f -exec file {} \; | \ + grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \ +- grep -v ' shared object,' | \ + sed -n -e 's/^\(.*\):[ ]*ELF.*, not stripped.*/\1/p'`; do + $STRIP -g "$f" || : + done diff --git a/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch b/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch new file mode 100644 index 0000000..8e4e835 --- /dev/null +++ b/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch @@ -0,0 +1,186 @@ +diff -up rpm-4.14.3/sign/rpmgensig.c.orig rpm-4.14.3/sign/rpmgensig.c +--- rpm-4.14.3/sign/rpmgensig.c.orig 2020-06-26 15:57:43.781333983 +0200 ++++ rpm-4.14.3/sign/rpmgensig.c 2020-06-26 15:58:29.819229616 +0200 +@@ -8,7 +8,6 @@ + #include + #include + #include +-#include + + #include /* RPMSIGTAG & related */ + #include +@@ -33,68 +32,6 @@ typedef struct sigTarget_s { + rpm_loff_t size; + } *sigTarget; + +-/* +- * There is no function for creating unique temporary fifos so create +- * unique temporary directory and then create fifo in it. +- */ +-static char *mkTempFifo(void) +-{ +- char *tmppath = NULL, *tmpdir = NULL, *fifofn = NULL; +- mode_t mode; +- +- tmppath = rpmExpand("%{_tmppath}", NULL); +- if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1)) +- goto exit; +- +- +- tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL); +- mode = umask(0077); +- tmpdir = mkdtemp(tmpdir); +- umask(mode); +- if (tmpdir == NULL) { +- rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n"), +- tmpdir); +- tmpdir = _free(tmpdir); +- goto exit; +- } +- +- fifofn = rpmGetPath(tmpdir, "/fifo", NULL); +- if (mkfifo(fifofn, 0600) == -1) { +- rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n"), fifofn); +- fifofn = _free(fifofn); +- } +- +-exit: +- if (fifofn == NULL && tmpdir != NULL) +- unlink(tmpdir); +- +- free(tmppath); +- free(tmpdir); +- +- return fifofn; +-} +- +-/* Delete fifo and then temporary directory in which it was located */ +-static int rpmRmTempFifo(const char *fn) +-{ +- int rc = 0; +- char *dfn = NULL, *dir = NULL; +- +- if ((rc = unlink(fn)) != 0) { +- rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n"), fn); +- return rc; +- } +- +- dfn = xstrdup(fn); +- dir = dirname(dfn); +- +- if ((rc = rmdir(dir)) != 0) +- rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n"), dir); +- free(dfn); +- +- return rc; +-} +- + static int closeFile(FD_t *fdp) + { + if (fdp == NULL || *fdp == NULL) +@@ -241,27 +178,38 @@ exit: + static int runGPG(sigTarget sigt, const char *sigfile) + { + int pid = 0, status; +- FD_t fnamedPipe = NULL; +- char *namedPipeName = NULL; ++ int pipefd[2]; ++ FILE *fpipe = NULL; + unsigned char buf[BUFSIZ]; + ssize_t count; + ssize_t wantCount; + rpm_loff_t size; + int rc = 1; /* assume failure */ + +- namedPipeName = mkTempFifo(); ++ if (pipe(pipefd) < 0) { ++ rpmlog(RPMLOG_ERR, _("Could not create pipe for signing: %m\n")); ++ goto exit; ++ } + +- rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1); ++ rpmPushMacro(NULL, "__plaintext_filename", NULL, "-", -1); + rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1); + + if (!(pid = fork())) { + char *const *av; + char *cmd = NULL; +- const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); ++ const char *tty = ttyname(STDIN_FILENO); ++ const char *gpg_path = NULL; ++ ++ if (!getenv("GPG_TTY") && (!tty || setenv("GPG_TTY", tty, 0))) ++ rpmlog(RPMLOG_WARNING, _("Could not set GPG_TTY to stdin: %m\n")); + ++ gpg_path = rpmExpand("%{?_gpg_path}", NULL); + if (gpg_path && *gpg_path != '\0') + (void) setenv("GNUPGHOME", gpg_path, 1); + ++ dup2(pipefd[0], STDIN_FILENO); ++ close(pipefd[1]); ++ + unsetenv("MALLOC_CHECK_"); + cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); + rc = poptParseArgvString(cmd, NULL, (const char ***)&av); +@@ -276,9 +224,10 @@ static int runGPG(sigTarget sigt, const + rpmPopMacro(NULL, "__plaintext_filename"); + rpmPopMacro(NULL, "__signature_filename"); + +- fnamedPipe = Fopen(namedPipeName, "w"); +- if (!fnamedPipe) { +- rpmlog(RPMLOG_ERR, _("Fopen failed\n")); ++ close(pipefd[0]); ++ fpipe = fdopen(pipefd[1], "w"); ++ if (!fpipe) { ++ rpmlog(RPMLOG_ERR, _("Could not open pipe for writing: %m\n")); + goto exit; + } + +@@ -291,8 +240,8 @@ static int runGPG(sigTarget sigt, const + size = sigt->size; + wantCount = size < sizeof(buf) ? size : sizeof(buf); + while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) { +- Fwrite(buf, sizeof(buf[0]), count, fnamedPipe); +- if (Ferror(fnamedPipe)) { ++ fwrite(buf, sizeof(buf[0]), count, fpipe); ++ if (ferror(fpipe)) { + rpmlog(RPMLOG_ERR, _("Could not write to pipe\n")); + goto exit; + } +@@ -304,8 +253,13 @@ static int runGPG(sigTarget sigt, const + sigt->fileName, Fstrerror(sigt->fd)); + goto exit; + } +- Fclose(fnamedPipe); +- fnamedPipe = NULL; ++ ++exit: ++ ++ if (fpipe) ++ fclose(fpipe); ++ if (pipefd[1]) ++ close(pipefd[1]); + + (void) waitpid(pid, &status, 0); + pid = 0; +@@ -314,20 +268,6 @@ static int runGPG(sigTarget sigt, const + } else { + rc = 0; + } +- +-exit: +- +- if (fnamedPipe) +- Fclose(fnamedPipe); +- +- if (pid) +- waitpid(pid, &status, 0); +- +- if (namedPipeName) { +- rpmRmTempFifo(namedPipeName); +- free(namedPipeName); +- } +- + return rc; + } + diff --git a/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch b/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch new file mode 100644 index 0000000..3a9e808 --- /dev/null +++ b/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch @@ -0,0 +1,378 @@ +From c33faabc2d09b9ad8c80b941b6114c1e4c2be80f Mon Sep 17 00:00:00 2001 +Message-Id: +From: Radovan Sroka +Date: Tue, 27 Oct 2020 16:18:04 +0100 +Subject: [PATCH] Added fapolicyd rpm plugin + +Fapolicyd (File Access Policy Daemon) implements application whitelisting +to decide file access rights. Applications that are known via a reputation +source are allowed access while unknown applications are not. + +The rpm plugin allows us to use rpm database as a source of trust. +We used dnf plugin since the beggining but it only provides notification +when transaction ends. With "integrity checking" requirement we need +a continual addition of files which are installed during the system +update. With fapolicyd rpm plugin we can allow using of recently +added/updated files in scriptlets during rpm transaction. + +The fapolicyd plugin gathers metadata of currently installed files. +It sends the information about files and about ongoing rpm transaction +to the fapolicyd daemon. The information is written to Linux pipe which +is placed in /var/run/fapolicyd/fapolicyd.fifo. + +The data format is "%s %lu %64s\n". [path, size, sha256] + +The fapolicyd rpm plugin can be enabled with "--with-fapolicyd" +configure option. + +Related PRs: +https://github.com/linux-application-whitelisting/fapolicyd/pull/105 +https://github.com/linux-application-whitelisting/fapolicyd/pull/106 + +Signed-off-by: Radovan Sroka +(cherry picked from commit 39595ccee321497dc3b08c7cab8a10304345429c) + +Backported from commit 39595ccee321497dc3b08c7cab8a10304345429c +--- + Makefile.am | 1 + + configure.ac | 8 ++ + doc/Makefile.am | 2 +- + doc/rpm-plugin-fapolicyd.8 | 21 +++++ + macros.in | 1 + + plugins/Makefile.am | 6 ++ + plugins/fapolicyd.c | 189 +++++++++++++++++++++++++++++++++++++ + 7 files changed, 227 insertions(+), 1 deletion(-) + create mode 100644 doc/rpm-plugin-fapolicyd.8 + create mode 100644 plugins/fapolicyd.c + +diff --git a/Makefile.am b/Makefile.am +index 1f20f05b7..8e92f0cde 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -16,6 +16,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ + --with-selinux \ + --with-imaevm \ + --with-crypto=openssl \ ++ --with-fapolicyd \ + --disable-dependency-tracking + + include $(top_srcdir)/rpm.am +diff --git a/configure.ac b/configure.ac +index 3fcb3ff20..3d0e9ef91 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -983,6 +983,14 @@ AS_IF([test "$enable_inhibit_plugin" = yes],[ + ]) + AM_CONDITIONAL(ENABLE_INHIBIT_PLUGIN,[test "$enable_inhibit_plugin" = yes]) + ++#================= ++# Check for fapolicyd support ++AC_ARG_WITH(fapolicyd, ++AS_HELP_STRING([--with-fapolicyd],[build with File Access Policy Daemon support]), ++with_fapolicyd=$withval, ++with_fapolicyd=auto) ++AM_CONDITIONAL(FAPOLICYD,[test "$with_fapolicyd" = yes]) ++ + with_dbus=no + AS_IF([test "$enable_plugins" != no],[ + AS_IF([test "$enable_inhibit_plugin" != no],[ +diff --git a/doc/Makefile.am b/doc/Makefile.am +index d2f520d64..535ad3ec3 100644 +--- a/doc/Makefile.am ++++ b/doc/Makefile.am +@@ -9,7 +9,7 @@ EXTRA_DIST += $(man_man1_DATA) + man_man8dir = $(mandir)/man8 + man_man8_DATA = rpm.8 rpm-misc.8 rpmbuild.8 rpmdeps.8 rpmgraph.8 rpm2cpio.8 + man_man8_DATA += rpmdb.8 rpmkeys.8 rpmsign.8 rpmspec.8 +-man_man8_DATA += rpm-plugin-systemd-inhibit.8 ++man_man8_DATA += rpm-plugin-systemd-inhibit.8 rpm-plugin-fapolicyd.8 + EXTRA_DIST += $(man_man8_DATA) + + man_fr_man8dir = $(mandir)/fr/man8 +diff --git a/doc/rpm-plugin-fapolicyd.8 b/doc/rpm-plugin-fapolicyd.8 +new file mode 100644 +index 000000000..fe7a8c78e +--- /dev/null ++++ b/doc/rpm-plugin-fapolicyd.8 +@@ -0,0 +1,21 @@ ++'\" t ++.TH "RPM-FAPOLICYD" "8" "28 Jan 2021" "Red Hat, Inc." ++.SH NAME ++rpm-plugin-fapolicyd \- Fapolicyd plugin for the RPM Package Manager ++ ++.SH Description ++ ++The plugin gathers metadata of currently installed files. It sends the ++information about files and about ongoing rpm transaction to the fapolicyd daemon. ++The information is written to Linux pipe which is placed in ++/var/run/fapolicyd/fapolicyd.fifo. ++ ++.SH Configuration ++ ++There are currently no options for this plugin in particular. See ++.BR rpm-plugins (8) ++on how to control plugins in general. ++ ++.SH SEE ALSO ++.IR fapolicyd (8) ++.IR rpm-plugins (8) +diff --git a/macros.in b/macros.in +index a6069ee4d..2fbda64cc 100644 +--- a/macros.in ++++ b/macros.in +@@ -1173,6 +1173,7 @@ package or when debugging this package.\ + %__transaction_selinux %{__plugindir}/selinux.so + %__transaction_syslog %{__plugindir}/syslog.so + %__transaction_ima %{__plugindir}/ima.so ++%__transaction_fapolicyd %{__plugindir}/fapolicyd.so + %__transaction_prioreset %{__plugindir}/prioreset.so + + #------------------------------------------------------------------------------ +diff --git a/plugins/Makefile.am b/plugins/Makefile.am +index ab4eee34f..cbfb81e19 100644 +--- a/plugins/Makefile.am ++++ b/plugins/Makefile.am +@@ -42,3 +42,9 @@ ima_la_sources = ima.c + ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la + plugins_LTLIBRARIES += ima.la + endif ++ ++if FAPOLICYD ++fapolicyd_la_sources = fapolicyd.c ++fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la ++plugins_LTLIBRARIES += fapolicyd.la ++endif +diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c +new file mode 100644 +index 000000000..50f50155c +--- /dev/null ++++ b/plugins/fapolicyd.c +@@ -0,0 +1,189 @@ ++#include "system.h" ++ ++#include ++#include ++#include "lib/rpmplugin.h" ++ ++#include ++#include ++#include ++#include ++ ++struct fapolicyd_data { ++ int fd; ++ long changed_files; ++ const char * fifo_path; ++}; ++ ++static struct fapolicyd_data fapolicyd_state = { ++ .fd = -1, ++ .changed_files = 0, ++ .fifo_path = "/run/fapolicyd/fapolicyd.fifo", ++}; ++ ++static rpmRC open_fifo(struct fapolicyd_data* state) ++{ ++ int fd = -1; ++ struct stat s; ++ ++ fd = open(state->fifo_path, O_RDWR); ++ if (fd == -1) { ++ rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno)); ++ goto bad; ++ } ++ ++ if (stat(state->fifo_path, &s) == -1) { ++ rpmlog(RPMLOG_DEBUG, "Stat: %s -> %s\n", state->fifo_path, strerror(errno)); ++ goto bad; ++ } ++ ++ if (!S_ISFIFO(s.st_mode)) { ++ rpmlog(RPMLOG_DEBUG, "File: %s exists but it is not a pipe!\n", state->fifo_path); ++ goto bad; ++ } ++ ++ /* keep only file's permition bits */ ++ mode_t mode = s.st_mode & ~S_IFMT; ++ ++ /* we require pipe to have 0660 permission */ ++ if (mode != 0660) { ++ rpmlog(RPMLOG_ERR, "File: %s has %o instead of 0660 \n", ++ state->fifo_path, ++ mode ); ++ goto bad; ++ } ++ ++ state->fd = fd; ++ /* considering success */ ++ return RPMRC_OK; ++ ++ bad: ++ if (fd > 0) ++ close(fd); ++ return RPMRC_FAIL; ++} ++ ++static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) ++{ ++ ssize_t len = strlen(str); ++ ssize_t written = 0; ++ ssize_t n = 0; ++ ++ while (written < len) { ++ if ((n = write(state->fd, str + written, len - written)) < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ rpmlog(RPMLOG_DEBUG, "Write: %s -> %s\n", state->fifo_path, strerror(errno)); ++ goto bad; ++ } ++ written += n; ++ } ++ ++ return RPMRC_OK; ++ ++ bad: ++ return RPMRC_FAIL; ++} ++ ++static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) ++{ ++ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) ++ goto end; ++ ++ if (!rstreq(rpmtsRootDir(ts), "/")) ++ goto end; ++ ++ (void) open_fifo(&fapolicyd_state); ++ ++ end: ++ return RPMRC_OK; ++} ++ ++static void fapolicyd_cleanup(rpmPlugin plugin) ++{ ++ if (fapolicyd_state.fd > 0) ++ (void) close(fapolicyd_state.fd); ++ ++ fapolicyd_state.fd = -1; ++} ++ ++static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) ++{ ++ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) ++ goto end; ++ ++ /* we are ready */ ++ if (fapolicyd_state.fd > 0) { ++ /* send a signal that transaction is over */ ++ (void) write_fifo(&fapolicyd_state, "1\n"); ++ /* flush cache */ ++ (void) write_fifo(&fapolicyd_state, "2\n"); ++ } ++ ++ end: ++ return RPMRC_OK; ++} ++ ++static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name, ++ int type) ++{ ++ if (fapolicyd_state.fd == -1) ++ goto end; ++ ++ if (fapolicyd_state.changed_files > 0) { ++ /* send signal to flush cache */ ++ (void) write_fifo(&fapolicyd_state, "2\n"); ++ ++ /* optimize flushing */ ++ /* flush only when there was an actual change */ ++ fapolicyd_state.changed_files = 0; ++ } ++ ++ end: ++ return RPMRC_OK; ++} ++ ++static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, ++ const char *path, const char *dest, ++ mode_t file_mode, rpmFsmOp op) ++{ ++ /* not ready */ ++ if (fapolicyd_state.fd == -1) ++ goto end; ++ ++ rpmFileAction action = XFO_ACTION(op); ++ ++ /* Ignore skipped files and unowned directories */ ++ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) { ++ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping early: path %s dest %s\n", ++ path, dest); ++ goto end; ++ } ++ ++ if (!S_ISREG(rpmfiFMode(fi))) { ++ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping non regular: path %s dest %s\n", ++ path, dest); ++ goto end; ++ } ++ ++ fapolicyd_state.changed_files++; ++ ++ char buffer[4096]; ++ ++ rpm_loff_t size = rpmfiFSize(fi); ++ char * sha = rpmfiFDigestHex(fi, NULL); ++ ++ snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); ++ (void) write_fifo(&fapolicyd_state, buffer); ++ ++ end: ++ return RPMRC_OK; ++} ++ ++struct rpmPluginHooks_s fapolicyd_hooks = { ++ .init = fapolicyd_init, ++ .cleanup = fapolicyd_cleanup, ++ .scriptlet_pre = fapolicyd_scriptlet_pre, ++ .tsm_post = fapolicyd_tsm_post, ++ .fsm_file_prepare = fapolicyd_fsm_file_prepare, ++}; +-- +2.29.2 + +commit c66cee32e74ce1e507c031605e3d7b2c1391a52c +Author: Radovan Sroka +Date: Wed Feb 10 17:04:55 2021 +0100 + + Fixed issues find by coverity + + - enhance the check for the file descriptor fd because 0 is also a valid + descriptor + + - added free() for sha so it doesn't leak memory for every file that is + processed + + Signed-off-by: Radovan Sroka + +diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c +index 50f50155c..48f65ae11 100644 +--- a/plugins/fapolicyd.c ++++ b/plugins/fapolicyd.c +@@ -58,7 +58,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state) + return RPMRC_OK; + + bad: +- if (fd > 0) ++ if (fd >= 0) + close(fd); + return RPMRC_FAIL; + } +@@ -176,6 +176,8 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); + (void) write_fifo(&fapolicyd_state, buffer); + ++ free(sha); ++ + end: + return RPMRC_OK; + } diff --git a/rpm-4.14.3-add-path-query-option.patch b/rpm-4.14.3-add-path-query-option.patch new file mode 100644 index 0000000..0504ec8 --- /dev/null +++ b/rpm-4.14.3-add-path-query-option.patch @@ -0,0 +1,197 @@ +From 013cd4ba63c35fa75feeccde0022d56e68bc5845 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Mon, 16 Aug 2021 18:21:02 +0200 +Subject: [PATCH] Add support for RPMDBI_BASENAMES on file queries + +There are legitimate reasons (such as rhbz#1940895 or the included test) +for wanting the former behavior where all file states were considered in +file queries prior to commit 9ad57bda4a82b9847826daa766b4421d877bb3d9, +so celebrate the tenth anniversary of that commit by adding a CLI switch +(a new package selector --path), as contemplated back then. + +Update the man page for --file to reflect it's current behavior and make +--path that more obvious. + +Resolves: rhbz#1940895 + +Combined with: +d1aebda01033bc8ba0d748b49f6fad9a5c0caa3f +f62b6d27cd741406a52a7e9c5b1d6f581dbd3af8 + +Backported for 4.14.3. +--- + doc/rpm.8 | 9 ++++++-- + lib/poptQV.c | 6 +++++- + lib/query.c | 7 +++++-- + lib/rpmcli.h | 1 + + tests/rpmquery.at | 52 +++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 70 insertions(+), 5 deletions(-) + +diff --git a/doc/rpm.8 b/doc/rpm.8 +index 15a3db25f..74604c8ec 100644 +--- a/doc/rpm.8 ++++ b/doc/rpm.8 +@@ -57,7 +57,7 @@ rpm \- RPM Package Manager + .PP + + [\fB\fIPACKAGE_NAME\fB\fR] +- [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR] ++ [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR] [\fB--path \fIPATH\fB\fR] + [\fB-g,--group \fIGROUP\fB\fR] {\fB-p,--package \fIPACKAGE_FILE\fB\fR] + [\fB--hdrid \fISHA1\fB\fR] [\fB--pkgid \fIMD5\fB\fR] [\fB--tid \fITID\fB\fR] + [\fB--querybynumber \fIHDRNUM\fB\fR] [\fB--triggeredby \fIPACKAGE_NAME\fB\fR] +@@ -555,7 +555,7 @@ starts with "b". + List duplicated packages. + .TP + \fB-f, --file \fIFILE\fB\fR +-Query package owning \fIFILE\fR. ++Query package owning installed \fIFILE\fR. + .TP + \fB--filecaps\fR + List file names with POSIX1.e capabilities. +@@ -598,6 +598,11 @@ that will be expanded to paths that are substituted in place of + the package manifest as additional \fIPACKAGE_FILE\fR + arguments to the query. + .TP ++\fB--path \fIPATH\fB\fR ++Query package(s) owning \fIPATH\fR, whether the file is installed or not. ++Multiple packages may own a \fIPATH\fR, but the file is only owned by the ++package installed last. ++.TP + \fB--pkgid \fIMD5\fB\fR + Query package that contains a given package identifier, i.e. the + \fIMD5\fR digest of the combined header and +diff --git a/lib/poptQV.c b/lib/poptQV.c +index 9021d7b3c..f752d8b82 100644 +--- a/lib/poptQV.c ++++ b/lib/poptQV.c +@@ -27,6 +27,7 @@ struct rpmQVKArguments_s rpmQVKArgs; + #define POPT_WHATENHANCES -1014 + #define POPT_WHATOBSOLETES -1015 + #define POPT_WHATCONFLICTS -1016 ++#define POPT_QUERYBYPATH -1017 + + /* ========== Query/Verify/Signature source args */ + static void rpmQVSourceArgCallback( poptContext con, +@@ -58,6 +59,7 @@ static void rpmQVSourceArgCallback( poptContext con, + case POPT_WHATSUPPLEMENTS: qva->qva_source |= RPMQV_WHATSUPPLEMENTS; break; + case POPT_WHATENHANCES: qva->qva_source |= RPMQV_WHATENHANCES; break; + case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY; break; ++ case POPT_QUERYBYPATH: qva->qva_source |= RPMQV_PATH_ALL; break; + case POPT_QUERYBYPKGID: qva->qva_source |= RPMQV_PKGID; break; + case POPT_QUERYBYHDRID: qva->qva_source |= RPMQV_HDRID; break; + case POPT_QUERYBYTID: qva->qva_source |= RPMQV_TID; break; +@@ -80,7 +82,9 @@ struct poptOption rpmQVSourcePoptTable[] = { + { "checksig", 'K', POPT_ARGFLAG_DOC_HIDDEN, NULL, 'K', + N_("rpm checksig mode"), NULL }, + { "file", 'f', 0, 0, 'f', +- N_("query/verify package(s) owning file"), "FILE" }, ++ N_("query/verify package(s) owning installed file"), "FILE" }, ++ { "path", '\0', 0, 0, POPT_QUERYBYPATH, ++ N_("query/verify package(s) owning path, installed or not"), "PATH" }, + { "group", 'g', 0, 0, 'g', + N_("query/verify package(s) in group"), "GROUP" }, + { "package", 'p', 0, 0, 'p', +diff --git a/lib/query.c b/lib/query.c +index 26cdecf10..e6ea1fa2d 100644 +--- a/lib/query.c ++++ b/lib/query.c +@@ -440,6 +440,7 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar + } + /* fallthrough on absolute and relative paths */ + case RPMQV_PATH: ++ case RPMQV_PATH_ALL: + { char * fn; + + for (s = arg; *s != '\0'; s++) +@@ -458,8 +459,10 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar + fn = xstrdup(arg); + (void) rpmCleanPath(fn); + +- /* XXX Add a switch to enable former BASENAMES behavior? */ +- mi = rpmtsInitIterator(ts, RPMDBI_INSTFILENAMES, fn, 0); ++ rpmDbiTagVal tag = RPMDBI_INSTFILENAMES; ++ if (qva->qva_source == RPMQV_PATH_ALL) ++ tag = RPMDBI_BASENAMES; ++ mi = rpmtsInitIterator(ts, tag, fn, 0); + if (mi == NULL) + mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0); + +diff --git a/lib/rpmcli.h b/lib/rpmcli.h +index 99af2585a..c0d07d137 100644 +--- a/lib/rpmcli.h ++++ b/lib/rpmcli.h +@@ -102,6 +102,7 @@ enum rpmQVSources_e { + RPMQV_SPECBUILTRPMS, /*!< ... from pkgs which would be built from spec */ + RPMQV_WHATOBSOLETES, /*!< ... from obsoletes db search. */ + RPMQV_WHATCONFLICTS, /*!< ... from conflicts db search. */ ++ RPMQV_PATH_ALL, /*!< ... from file path db search (all states). */ + }; + + typedef rpmFlags rpmQVSources; +diff --git a/tests/rpmquery.at b/tests/rpmquery.at +index 36c62339a..ad580f664 100644 +--- a/tests/rpmquery.at ++++ b/tests/rpmquery.at +@@ -194,6 +194,58 @@ runroot rpm \ + + AT_CLEANUP + ++# ------------------------------ ++# query a package by a file ++AT_SETUP([rpm -qf]) ++AT_KEYWORDS([query]) ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm \ ++ --nodeps \ ++ -i /data/RPMS/hello-1.0-1.i386.rpm ++runroot rpm \ ++ -qf /usr/local/bin/hello ++], ++[0], ++[hello-1.0-1.i386 ++], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([rpm -qf on non-installed file]) ++AT_KEYWORDS([query]) ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm \ ++ --nodeps \ ++ --excludedocs \ ++ -i /data/RPMS/hello-1.0-1.i386.rpm ++runroot rpm \ ++ -qf /usr/share/doc/hello-1.0/FAQ ++], ++[1], ++[], ++[error: file /usr/share/doc/hello-1.0/FAQ: No such file or directory ++]) ++AT_CLEANUP ++ ++AT_SETUP([rpm -q --path on non-installed file]) ++AT_KEYWORDS([query]) ++AT_CHECK([ ++RPMDB_INIT ++runroot rpm \ ++ --nodeps \ ++ --excludedocs \ ++ -i /data/RPMS/hello-1.0-1.i386.rpm ++runroot rpm \ ++ -q --path /usr/share/doc/hello-1.0/FAQ ++], ++[0], ++[hello-1.0-1.i386 ++], ++[]) ++AT_CLEANUP ++ + # ------------------------------ + AT_SETUP([integer array query]) + AT_KEYWORDS([query]) +-- +2.35.1 + diff --git a/rpm-4.14.3-add-read-only-support-for-sqlite.patch b/rpm-4.14.3-add-read-only-support-for-sqlite.patch new file mode 100644 index 0000000..419d754 --- /dev/null +++ b/rpm-4.14.3-add-read-only-support-for-sqlite.patch @@ -0,0 +1,798 @@ +From 34790c335fe6e5e1099c9320d7b3134398104120 Mon Sep 17 00:00:00 2001 +Message-Id: <34790c335fe6e5e1099c9320d7b3134398104120.1624429665.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 23 Jun 2021 08:24:44 +0300 +Subject: [PATCH] Add read-only support for sqlite + +Based on latest upstream sqlite backend version, chainsaw write support +out and adjust for the infra differences (which there are more than a +few) and add an error message instead. +--- + configure.ac | 23 ++ + lib/Makefile.am | 6 + + lib/backend/dbi.c | 14 + + lib/backend/dbi.h | 5 + + lib/backend/sqlite.c | 659 +++++++++++++++++++++++++++++++++++++++++++ + macros.in | 1 + + 6 files changed, 708 insertions(+) + create mode 100644 lib/backend/sqlite.c + +diff --git a/configure.ac b/configure.ac +index 3fcb3ff20..e04aced68 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -589,6 +589,29 @@ AS_IF([test "$enable_ndb" = yes],[ + ]) + AM_CONDITIONAL([NDB], [test "$enable_ndb" = yes]) + ++# Check for SQLITE support ++AC_ARG_ENABLE([sqlite], ++ [AS_HELP_STRING([--enable-sqlite=@<:@yes/no/auto@:>@)], ++ [build with sqlite rpm database format support (default=yes)])], ++ [enable_sqlite="$enableval"], ++ [enable_sqlite=yes]) ++ ++AS_IF([test "x$enable_sqlite" != "xno"], [ ++ PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.22.0], [have_sqlite=yes], [have_sqlite=no]) ++ AS_IF([test "$enable_sqlite" = "yes"], [ ++ if test "$have_sqlite" = "no"; then ++ AC_MSG_ERROR([--enable-sqlite specified, but not available]) ++ fi ++ ]) ++]) ++ ++if test "x$have_sqlite" = "xyes"; then ++ AC_DEFINE([WITH_SQLITE], [1], [Define if SQLITE is available]) ++ SQLITE_REQUIRES=sqlite ++ AC_SUBST(SQLITE_REQUIRES) ++fi ++AM_CONDITIONAL([SQLITE], [test "x$have_sqlite" = "xyes"]) ++ + #================= + # Check for LMDB support + AC_ARG_ENABLE([lmdb], +diff --git a/lib/Makefile.am b/lib/Makefile.am +index baf3238ee..8a9fe77bd 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -76,6 +76,12 @@ librpm_la_SOURCES += \ + backend/ndb/rpmxdb.h + endif + ++if SQLITE ++AM_CPPFLAGS += $(SQLITE_CFLAGS) ++librpm_la_LIBADD += $(SQLITE_LIBS) ++librpm_la_SOURCES += backend/sqlite.c ++endif ++ + if LMDB + AM_CPPFLAGS += $(LMDB_CFLAGS) + librpm_la_LIBADD += $(LMDB_LIBS) +diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c +index e99a5f2b2..dc3587f58 100644 +--- a/lib/backend/dbi.c ++++ b/lib/backend/dbi.c +@@ -48,6 +48,11 @@ dbDetectBackend(rpmdb rdb) + if (!strcmp(db_backend, "ndb")) { + rdb->db_ops = &ndb_dbops; + } else ++#endif ++#ifdef WITH_SQLITE ++ if (!strcmp(db_backend, "sqlite")) { ++ rdb->db_ops = &sqlite_dbops; ++ } else + #endif + { + rdb->db_ops = &db3_dbops; +@@ -75,6 +80,15 @@ dbDetectBackend(rpmdb rdb) + free(path); + #endif + ++#ifdef WITH_SQLITE ++ path = rstrscat(NULL, dbhome, "/rpmdb.sqlite", NULL); ++ if (access(path, F_OK) == 0 && rdb->db_ops != &sqlite_dbops) { ++ rdb->db_ops = &sqlite_dbops; ++ rpmlog(RPMLOG_WARNING, _("Found SQLITE rpmdb.sqlite database while attempting %s backend: using sqlite backend.\n"), db_backend); ++ } ++ free(path); ++#endif ++ + path = rstrscat(NULL, dbhome, "/Packages", NULL); + if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) { + rdb->db_ops = &db3_dbops; +diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h +index 02f49c8fd..ff2b4f974 100644 +--- a/lib/backend/dbi.h ++++ b/lib/backend/dbi.h +@@ -275,6 +275,11 @@ RPM_GNUC_INTERNAL + extern struct rpmdbOps_s lmdb_dbops; + #endif + ++#if defined(WITH_SQLITE) ++RPM_GNUC_INTERNAL ++extern struct rpmdbOps_s sqlite_dbops; ++#endif ++ + #ifdef __cplusplus + } + #endif +diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c +new file mode 100644 +index 000000000..3caeba5f0 +--- /dev/null ++++ b/lib/backend/sqlite.c +@@ -0,0 +1,659 @@ ++#include "system.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include "lib/rpmdb_internal.h" ++ ++#include "debug.h" ++ ++static const int sleep_ms = 50; ++ ++struct dbiCursor_s { ++ sqlite3 *sdb; ++ sqlite3_stmt *stmt; ++ const char *fmt; ++ int flags; ++ rpmTagVal tag; ++ int ctype; ++ struct dbiCursor_s *subc; ++ ++ const void *key; ++ unsigned int keylen; ++}; ++ ++static int sqlexec(sqlite3 *sdb, const char *fmt, ...); ++ ++static void rpm_match3(sqlite3_context *sctx, int argc, sqlite3_value **argv) ++{ ++ int match = 0; ++ if (argc == 3) { ++ int b1len = sqlite3_value_bytes(argv[0]); ++ int b2len = sqlite3_value_bytes(argv[1]); ++ int n = sqlite3_value_int(argv[2]); ++ if (b1len >= n && b2len >= n) { ++ const char *b1 = sqlite3_value_blob(argv[0]); ++ const char *b2 = sqlite3_value_blob(argv[1]); ++ match = (memcmp(b1, b2, n) == 0); ++ } ++ } ++ sqlite3_result_int(sctx, match); ++} ++ ++static void errCb(void *data, int err, const char *msg) ++{ ++ rpmdb rdb = data; ++ rpmlog(RPMLOG_WARNING, "%s: %s: %s\n", ++ rdb->db_descr, sqlite3_errstr(err), msg); ++} ++ ++static int dbiCursorReset(dbiCursor dbc) ++{ ++ if (dbc->stmt) { ++ sqlite3_reset(dbc->stmt); ++ sqlite3_clear_bindings(dbc->stmt); ++ } ++ return 0; ++} ++ ++static int dbiCursorResult(dbiCursor dbc) ++{ ++ int rc = sqlite3_errcode(dbc->sdb); ++ int err = (rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW); ++ if (err) { ++ rpmlog(RPMLOG_ERR, "%s: %d: %s\n", sqlite3_sql(dbc->stmt), ++ sqlite3_errcode(dbc->sdb), sqlite3_errmsg(dbc->sdb)); ++ } ++ return err ? RPMRC_FAIL : RPMRC_OK; ++} ++ ++static int dbiCursorPrep(dbiCursor dbc, const char *fmt, ...) ++{ ++ if (dbc->stmt == NULL) { ++ char *cmd = NULL; ++ va_list ap; ++ ++ va_start(ap, fmt); ++ cmd = sqlite3_vmprintf(fmt, ap); ++ va_end(ap); ++ ++ sqlite3_prepare_v2(dbc->sdb, cmd, -1, &dbc->stmt, NULL); ++ sqlite3_free(cmd); ++ } else { ++ dbiCursorReset(dbc); ++ } ++ ++ return dbiCursorResult(dbc); ++} ++ ++static int dbiCursorBindPkg(dbiCursor dbc, unsigned int hnum, ++ void *blob, unsigned int bloblen) ++{ ++ int rc = 0; ++ ++ if (hnum) ++ rc = sqlite3_bind_int(dbc->stmt, 1, hnum); ++ else ++ rc = sqlite3_bind_null(dbc->stmt, 1); ++ ++ if (blob) { ++ if (!rc) ++ rc = sqlite3_bind_blob(dbc->stmt, 2, blob, bloblen, NULL); ++ } ++ return dbiCursorResult(dbc); ++} ++ ++static int dbiCursorBindIdx(dbiCursor dbc, const void *key, int keylen, ++ dbiIndexItem rec) ++{ ++ int rc; ++ if (dbc->ctype == SQLITE_TEXT) { ++ rc = sqlite3_bind_text(dbc->stmt, 1, key, keylen, NULL); ++ } else { ++ rc = sqlite3_bind_blob(dbc->stmt, 1, key, keylen, NULL); ++ } ++ ++ if (rec) { ++ if (!rc) ++ rc = sqlite3_bind_int(dbc->stmt, 2, rec->hdrNum); ++ if (!rc) ++ rc = sqlite3_bind_int(dbc->stmt, 3, rec->tagNum); ++ } ++ ++ return dbiCursorResult(dbc); ++} ++ ++static int sqlite_init(rpmdb rdb, const char * dbhome) ++{ ++ int rc = 0; ++ char *dbfile = NULL; ++ ++ if (rdb->db_dbenv == NULL) { ++ dbfile = rpmGenPath(dbhome, "rpmdb.sqlite", NULL); ++ sqlite3 *sdb = NULL; ++ int xx, flags = 0; ++ int retry_open = 1; ++ ++ free(rdb->db_descr); ++ rdb->db_descr = xstrdup("sqlite"); ++ ++ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY) ++ flags |= SQLITE_OPEN_READONLY; ++ else { ++ rpmlog(RPMLOG_ERR, ++ _("unable to open sqlite database %s for writing, sqlite support is read-only\n"), dbfile); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ ++ while (retry_open--) { ++ xx = sqlite3_open_v2(dbfile, &sdb, flags, NULL); ++ /* Attempt to create if missing, discarding OPEN_READONLY (!) */ ++ if (xx == SQLITE_CANTOPEN && (flags & SQLITE_OPEN_READONLY)) { ++ /* Sqlite allocates resources even on failure to open (!) */ ++ sqlite3_close(sdb); ++ flags &= ~SQLITE_OPEN_READONLY; ++ flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); ++ retry_open++; ++ } ++ } ++ ++ if (xx != SQLITE_OK) { ++ rpmlog(RPMLOG_ERR, _("Unable to open sqlite database %s: %s\n"), ++ dbfile, sqlite3_errstr(xx)); ++ rc = 1; ++ goto exit; ++ } ++ ++ sqlite3_create_function(sdb, "match", 3, ++ (SQLITE_UTF8|SQLITE_DETERMINISTIC), ++ NULL, rpm_match3, NULL, NULL); ++ ++ sqlite3_busy_timeout(sdb, sleep_ms); ++ sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb); ++ ++ sqlexec(sdb, "PRAGMA secure_delete = OFF"); ++ sqlexec(sdb, "PRAGMA case_sensitive_like = ON"); ++ ++ if (sqlite3_db_readonly(sdb, NULL) == 0) { ++ if (sqlexec(sdb, "PRAGMA journal_mode = WAL") == 0) { ++ int one = 1; ++ /* Annoying but necessary to support non-privileged readers */ ++ sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL, &one); ++ ++ if (!rpmExpandNumeric("%{?_flush_io}")) ++ sqlexec(sdb, "PRAGMA wal_autocheckpoint = 0"); ++ } ++ } ++ ++ rdb->db_dbenv = sdb; ++ } ++ rdb->db_opens++; ++ ++exit: ++ free(dbfile); ++ return rc; ++} ++ ++static int sqlite_fini(rpmdb rdb) ++{ ++ int rc = 0; ++ if (rdb) { ++ sqlite3 *sdb = rdb->db_dbenv; ++ if (rdb->db_opens > 1) { ++ rdb->db_opens--; ++ } else { ++ if (sqlite3_db_readonly(sdb, NULL) == 0) { ++ sqlexec(sdb, "PRAGMA optimize"); ++ sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE"); ++ } ++ rdb->db_dbenv = NULL; ++ int xx = sqlite3_close(sdb); ++ rc = (xx != SQLITE_OK); ++ } ++ } ++ ++ return rc; ++} ++ ++static int sqlexec(sqlite3 *sdb, const char *fmt, ...) ++{ ++ int rc = 0; ++ char *cmd = NULL; ++ char *err = NULL; ++ va_list ap; ++ ++ va_start(ap, fmt); ++ cmd = sqlite3_vmprintf(fmt, ap); ++ va_end(ap); ++ ++ /* sqlite3_exec() doesn't seeem to honor sqlite3_busy_timeout() */ ++ while ((rc = sqlite3_exec(sdb, cmd, NULL, NULL, &err)) == SQLITE_BUSY) { ++ usleep(sleep_ms); ++ } ++ ++ if (rc) ++ rpmlog(RPMLOG_ERR, "sqlite failure: %s: %s\n", cmd, err); ++ else ++ rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc); ++ ++ sqlite3_free(cmd); ++ ++ return rc ? RPMRC_FAIL : RPMRC_OK; ++} ++ ++static int dbiExists(dbiIndex dbi) ++{ ++ const char *col = (dbi->dbi_type == DBI_PRIMARY) ? "hnum" : "key"; ++ const char *tbl = dbi->dbi_file; ++ int rc = sqlite3_table_column_metadata(dbi->dbi_db, NULL, tbl, col, ++ NULL, NULL, NULL, NULL, NULL); ++ return (rc == 0); ++} ++ ++static int init_table(dbiIndex dbi, rpmTagVal tag) ++{ ++ int rc = 0; ++ ++ if (dbiExists(dbi)) ++ return 0; ++ ++ if (dbi->dbi_type == DBI_PRIMARY) { ++ rc = sqlexec(dbi->dbi_db, ++ "CREATE TABLE IF NOT EXISTS '%q' (" ++ "hnum INTEGER PRIMARY KEY AUTOINCREMENT," ++ "blob BLOB NOT NULL" ++ ")", ++ dbi->dbi_file); ++ } else { ++ const char *keytype = (rpmTagGetClass(tag) == RPM_STRING_CLASS) ? ++ "TEXT" : "BLOB"; ++ rc = sqlexec(dbi->dbi_db, ++ "CREATE TABLE IF NOT EXISTS '%q' (" ++ "key '%q' NOT NULL, " ++ "hnum INTEGER NOT NULL, " ++ "idx INTEGER NOT NULL, " ++ "FOREIGN KEY (hnum) REFERENCES 'Packages'(hnum)" ++ ")", ++ dbi->dbi_file, keytype); ++ } ++ if (!rc) ++ dbi->dbi_flags |= DBI_CREATED; ++ ++ return rc; ++} ++ ++static int create_index(sqlite3 *sdb, const char *table, const char *col) ++{ ++ return sqlexec(sdb, ++ "CREATE INDEX IF NOT EXISTS '%s_%s_idx' ON '%q'(%s ASC)", ++ table, col, table, col); ++} ++ ++static int init_index(dbiIndex dbi, rpmTagVal tag) ++{ ++ int rc = 0; ++ ++ /* Can't create on readonly database, but things will still work */ ++ if (sqlite3_db_readonly(dbi->dbi_db, NULL) == 1) ++ return 0; ++ ++ if (dbi->dbi_type == DBI_SECONDARY) { ++ int string = (rpmTagGetClass(tag) == RPM_STRING_CLASS); ++ int array = (rpmTagGetReturnType(tag) == RPM_ARRAY_RETURN_TYPE); ++ if (!rc && string) ++ rc = create_index(dbi->dbi_db, dbi->dbi_file, "key"); ++ if (!rc && array) ++ rc = create_index(dbi->dbi_db, dbi->dbi_file, "hnum"); ++ } ++ return rc; ++} ++ ++static int sqlite_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) ++{ ++ int rc = sqlite_init(rdb, rpmdbHome(rdb)); ++ ++ if (!rc) { ++ dbiIndex dbi = dbiNew(rdb, rpmtag); ++ dbi->dbi_db = rdb->db_dbenv; ++ ++ rc = init_table(dbi, rpmtag); ++ ++ if (!rc && !(rdb->db_flags & RPMDB_FLAG_REBUILD)) ++ rc = init_index(dbi, rpmtag); ++ ++ if (!rc && dbip) ++ *dbip = dbi; ++ else ++ dbiFree(dbi); ++ } ++ ++ return rc; ++} ++ ++static int sqlite_Close(dbiIndex dbi, unsigned int flags) ++{ ++ rpmdb rdb = dbi->dbi_rpmdb; ++ int rc = 0; ++ if (rdb->db_flags & RPMDB_FLAG_REBUILD) ++ rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file)); ++ sqlite_fini(dbi->dbi_rpmdb); ++ dbiFree(dbi); ++ return rc; ++} ++ ++static int sqlite_Verify(dbiIndex dbi, unsigned int flags) ++{ ++ int errors = -1; ++ int key_errors = -1; ++ sqlite3_stmt *s = NULL; ++ const char *cmd = "PRAGMA integrity_check"; ++ ++ if (dbi->dbi_type == DBI_SECONDARY) ++ return RPMRC_OK; ++ ++ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) { ++ errors = 0; ++ while (sqlite3_step(s) == SQLITE_ROW) { ++ const char *txt = (const char *)sqlite3_column_text(s, 0); ++ if (!rstreq(txt, "ok")) { ++ errors++; ++ rpmlog(RPMLOG_ERR, "verify: %s\n", txt); ++ } ++ } ++ sqlite3_finalize(s); ++ } else { ++ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db)); ++ } ++ ++ /* No point checking higher-level errors if low-level errors exist */ ++ if (errors) ++ goto exit; ++ ++ cmd = "PRAGMA foreign_key_check"; ++ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) { ++ key_errors = 0; ++ while (sqlite3_step(s) == SQLITE_ROW) { ++ key_errors++; ++ rpmlog(RPMLOG_ERR, "verify key: %s[%lld]\n", ++ sqlite3_column_text(s, 0), ++ sqlite3_column_int64(s, 1)); ++ } ++ sqlite3_finalize(s); ++ } else { ++ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db)); ++ } ++ ++exit: ++ ++ return (errors == 0 && key_errors == 0) ? RPMRC_OK : RPMRC_FAIL; ++} ++ ++static void sqlite_SetFSync(rpmdb rdb, int enable) ++{ ++ if (rdb->db_dbenv) { ++ sqlexec(rdb->db_dbenv, ++ "PRAGMA synchronous = %s", enable ? "FULL" : "OFF"); ++ } ++} ++ ++static int sqlite_Ctrl(rpmdb rdb, dbCtrlOp ctrl) ++{ ++ int rc = 0; ++ ++ switch (ctrl) { ++ case DB_CTRL_LOCK_RW: ++ rc = sqlexec(rdb->db_dbenv, "SAVEPOINT 'rwlock'"); ++ break; ++ case DB_CTRL_UNLOCK_RW: ++ rc = sqlexec(rdb->db_dbenv, "RELEASE 'rwlock'"); ++ break; ++ default: ++ break; ++ } ++ ++ return rc; ++} ++ ++static dbiCursor sqlite_CursorInit(dbiIndex dbi, unsigned int flags) ++{ ++ dbiCursor dbc = xcalloc(1, sizeof(*dbc)); ++ dbc->sdb = dbi->dbi_db; ++ dbc->flags = flags; ++ dbc->tag = rpmTagGetValue(dbi->dbi_file); ++ if (rpmTagGetClass(dbc->tag) == RPM_STRING_CLASS) { ++ dbc->ctype = SQLITE_TEXT; ++ } else { ++ dbc->ctype = SQLITE_BLOB; ++ } ++ if (dbc->flags & DBC_WRITE) ++ sqlexec(dbc->sdb, "SAVEPOINT '%s'", dbi->dbi_file); ++ return dbc; ++} ++ ++static dbiCursor sqlite_CursorFree(dbiIndex dbi, dbiCursor dbc) ++{ ++ if (dbc) { ++ sqlite3_finalize(dbc->stmt); ++ if (dbc->subc) ++ dbiCursorFree(dbi, dbc->subc); ++ if (dbc->flags & DBC_WRITE) ++ sqlexec(dbc->sdb, "RELEASE '%s'", dbi->dbi_file); ++ free(dbc); ++ } ++ return NULL; ++} ++ ++static rpmRC sqlite_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC sqlite_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC sqlite_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC sqlite_stepPkg(dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen) ++{ ++ int rc = sqlite3_step(dbc->stmt); ++ ++ if (rc == SQLITE_ROW) { ++ if (hdrLen) ++ *hdrLen = sqlite3_column_bytes(dbc->stmt, 1); ++ if (hdrBlob) ++ *hdrBlob = (void *) sqlite3_column_blob(dbc->stmt, 1); ++ } ++ return rc; ++} ++ ++static rpmRC sqlite_pkgdbByKey(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen) ++{ ++ int rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q' WHERE hnum=?", ++ dbi->dbi_file); ++ ++ if (!rc) ++ rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0); ++ ++ if (!rc) ++ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen); ++ ++ return dbiCursorResult(dbc); ++} ++ ++static rpmRC sqlite_pkgdbIter(dbiIndex dbi, dbiCursor dbc, ++ unsigned char **hdrBlob, unsigned int *hdrLen) ++{ ++ int rc = RPMRC_OK; ++ if (dbc->stmt == NULL) { ++ rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q'", dbi->dbi_file); ++ } ++ ++ if (!rc) ++ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen); ++ ++ if (rc == SQLITE_DONE) { ++ rc = RPMRC_NOTFOUND; ++ } else { ++ rc = dbiCursorResult(dbc); ++ } ++ ++ return rc; ++} ++ ++static rpmRC sqlite_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen) ++{ ++ int rc; ++ ++ if (hdrNum) { ++ rc = sqlite_pkgdbByKey(dbi, dbc, hdrNum, hdrBlob, hdrLen); ++ } else { ++ rc = sqlite_pkgdbIter(dbi, dbc, hdrBlob, hdrLen); ++ } ++ ++ return rc; ++} ++ ++static unsigned int sqlite_pkgdbKey(dbiIndex dbi, dbiCursor dbc) ++{ ++ return sqlite3_column_int(dbc->stmt, 0); ++} ++ ++static rpmRC sqlite_idxdbByKey(dbiIndex dbi, dbiCursor dbc, ++ const char *keyp, size_t keylen, int searchType, ++ dbiIndexSet *set) ++{ ++ int rc = RPMRC_NOTFOUND; ++ ++ if (searchType == DBC_PREFIX_SEARCH) { ++ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' " ++ "WHERE MATCH(key,'%q',%d) " ++ "ORDER BY key", ++ dbi->dbi_file, keyp, keylen); ++ } else { ++ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' WHERE key=?", ++ dbi->dbi_file); ++ if (!rc) ++ rc = dbiCursorBindIdx(dbc, keyp, keylen, NULL); ++ } ++ ++ ++ if (!rc) { ++ while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) { ++ unsigned int hnum = sqlite3_column_int(dbc->stmt, 0); ++ unsigned int tnum = sqlite3_column_int(dbc->stmt, 1); ++ ++ if (*set == NULL) ++ *set = dbiIndexSetNew(5); ++ dbiIndexSetAppendOne(*set, hnum, tnum, 0); ++ } ++ } ++ ++ if (rc == SQLITE_DONE) { ++ rc = (*set) ? RPMRC_OK : RPMRC_NOTFOUND; ++ } else { ++ rc = dbiCursorResult(dbc); ++ } ++ ++ return rc; ++} ++ ++static rpmRC sqlite_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set) ++{ ++ int rc = RPMRC_OK; ++ ++ if (dbc->stmt == NULL) { ++ rc = dbiCursorPrep(dbc, "SELECT DISTINCT key FROM '%q' ORDER BY key", ++ dbi->dbi_file); ++ if (set) ++ dbc->subc = dbiCursorInit(dbi, 0); ++ } ++ ++ if (!rc) ++ rc = sqlite3_step(dbc->stmt); ++ ++ if (rc == SQLITE_ROW) { ++ if (dbc->ctype == SQLITE_TEXT) { ++ dbc->key = sqlite3_column_text(dbc->stmt, 0); ++ } else { ++ dbc->key = sqlite3_column_blob(dbc->stmt, 0); ++ } ++ dbc->keylen = sqlite3_column_bytes(dbc->stmt, 0); ++ if (dbc->subc) { ++ rc = sqlite_idxdbByKey(dbi, dbc->subc, dbc->key, dbc->keylen, ++ DBC_NORMAL_SEARCH, set); ++ } else { ++ rc = RPMRC_OK; ++ } ++ } else if (rc == SQLITE_DONE) { ++ rc = RPMRC_NOTFOUND; ++ } else { ++ rc = dbiCursorResult(dbc); ++ } ++ ++ return rc; ++} ++ ++static rpmRC sqlite_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType) ++{ ++ int rc; ++ if (keyp) { ++ rc = sqlite_idxdbByKey(dbi, dbc, keyp, keylen, searchType, set); ++ } else { ++ rc = sqlite_idxdbIter(dbi, dbc, set); ++ } ++ ++ return rc; ++} ++ ++static rpmRC sqlite_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC sqlite_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) ++{ ++ return RPMRC_FAIL; ++} ++ ++static const void * sqlite_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen) ++{ ++ const void *key = NULL; ++ if (dbc) { ++ key = dbc->key; ++ if (key && keylen) ++ *keylen = dbc->keylen; ++ } ++ return key; ++} ++ ++struct rpmdbOps_s sqlite_dbops = { ++ .open = sqlite_Open, ++ .close = sqlite_Close, ++ .verify = sqlite_Verify, ++ .setFSync = sqlite_SetFSync, ++ .ctrl = sqlite_Ctrl, ++ ++ .cursorInit = sqlite_CursorInit, ++ .cursorFree = sqlite_CursorFree, ++ ++ .pkgdbPut = sqlite_pkgdbPut, ++ .pkgdbDel = sqlite_pkgdbDel, ++ .pkgdbGet = sqlite_pkgdbGet, ++ .pkgdbKey = sqlite_pkgdbKey, ++ .pkgdbNew = sqlite_pkgdbNew, ++ ++ .idxdbGet = sqlite_idxdbGet, ++ .idxdbPut = sqlite_idxdbPut, ++ .idxdbDel = sqlite_idxdbDel, ++ .idxdbKey = sqlite_idxdbKey ++}; ++ +diff --git a/macros.in b/macros.in +index a6069ee4d..9ad3d60ef 100644 +--- a/macros.in ++++ b/macros.in +@@ -620,6 +620,7 @@ package or when debugging this package.\ + # bdb Berkeley DB + # lmdb Lightning Memory-mapped Database + # ndb new data base format ++# sqlite Sqlite database (read-only in this version!) + # + %_db_backend bdb + +-- +2.31.1 + diff --git a/rpm-4.14.3-backport-multithreaded-zstd.patch b/rpm-4.14.3-backport-multithreaded-zstd.patch new file mode 100644 index 0000000..51a0290 --- /dev/null +++ b/rpm-4.14.3-backport-multithreaded-zstd.patch @@ -0,0 +1,178 @@ +From a5803faa083690526b96484c7e6a4cc915ca3921 Mon Nov 28 16:35:09 2022 +From: Aleksandr Kazakov +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 +--- + 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 + diff --git a/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch b/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch new file mode 100644 index 0000000..58606e9 --- /dev/null +++ b/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.14.3/lib/header.c.orig rpm-4.14.3/lib/header.c +--- rpm-4.14.3/lib/header.c.orig 2020-04-28 14:50:11.816399041 +0200 ++++ rpm-4.14.3/lib/header.c 2021-02-03 16:47:23.567245743 +0100 +@@ -1910,7 +1910,7 @@ rpmRC hdrblobRead(FD_t fd, int magic, in + + if (regionTag == RPMTAG_HEADERSIGNATURES) { + il_max = 32; +- dl_max = 8192; ++ dl_max = 64 * 1024 * 1024; + } + + memset(block, 0, sizeof(block)); diff --git a/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch b/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch new file mode 100644 index 0000000..343bd02 --- /dev/null +++ b/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch @@ -0,0 +1,167 @@ +From 534fd1f0c84b12ba6080a46e07c57ef913c77cba Mon Sep 17 00:00:00 2001 +From: Radovan Sroka +Date: Thu, 25 Aug 2022 15:38:01 +0200 +Subject: [PATCH] fapolicyd: Make write() nonblocking + +- switch to read only and non blocking mode for pipe +- add 1 minute loop to wait for pipe to reappear + +Sometimes during the system update/upgrade fapolicyd +get restarted e.g. when systemd gets updated. +That can lead to the situation where fapolicyd pipe +has been removed and created again. +In such cases rpm-plugin-fapolicyd gets stuck on +write() to the pipe which does not exist anymore. +After switching to non blocking file descriptor +we can try to reopen the pipe if there is an error +from write(). Assuming that a new pipe should appear +when fapolicyd daemon starts again. +If not then after 1 minute of waiting we expect +fapolicyd daemon to be not active and we let the +transaction continue. + +Signed-off-by: Radovan Sroka +--- + plugins/fapolicyd.c | 74 +++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 65 insertions(+), 9 deletions(-) + +diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c +index 1ff50c30f..6c6322941 100644 +--- a/plugins/fapolicyd.c ++++ b/plugins/fapolicyd.c +@@ -27,7 +27,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state) + int fd = -1; + struct stat s; + +- fd = open(state->fifo_path, O_RDWR); ++ fd = open(state->fifo_path, O_WRONLY|O_NONBLOCK); + if (fd == -1) { + rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno)); + goto bad; +@@ -55,15 +55,26 @@ static rpmRC open_fifo(struct fapolicyd_data* state) + } + + state->fd = fd; ++ + /* considering success */ + return RPMRC_OK; + + bad: + if (fd >= 0) + close(fd); ++ ++ state->fd = -1; + return RPMRC_FAIL; + } + ++static void close_fifo(struct fapolicyd_data* state) ++{ ++ if (state->fd > 0) ++ (void) close(state->fd); ++ ++ state->fd = -1; ++} ++ + static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) + { + ssize_t len = strlen(str); +@@ -86,6 +97,54 @@ static rpmRC write_fifo(struct fapolicyd_data* state, const char * str) + return RPMRC_FAIL; + } + ++static void try_to_write_to_fifo(struct fapolicyd_data* state, const char * str) ++{ ++ int reload = 0; ++ int printed = 0; ++ ++ /* 1min/60s */ ++ const int timeout = 60; ++ ++ /* wait up to X seconds */ ++ for (int i = 0; i < timeout; i++) { ++ ++ if (reload) { ++ if (!printed) { ++ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: waiting for the service connection to resume, it can take up to %d seconds\n", timeout); ++ printed = 1; ++ } ++ ++ (void) close_fifo(state); ++ (void) open_fifo(state); ++ } ++ ++ if (state->fd >= 0) { ++ if (write_fifo(state, str) == RPMRC_OK) { ++ ++ /* write was successful after few reopens */ ++ if (reload) ++ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has resumed\n"); ++ ++ break; ++ } ++ } ++ ++ /* failed write or reopen */ ++ reload = 1; ++ sleep(1); ++ ++ /* the last iteration */ ++ /* consider failure */ ++ if (i == timeout-1) { ++ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has not resumed\n"); ++ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: continuing without the service\n"); ++ } ++ ++ } ++ ++} ++ ++ + static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) + { + if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) +@@ -102,10 +161,7 @@ static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts) + + static void fapolicyd_cleanup(rpmPlugin plugin) + { +- if (fapolicyd_state.fd > 0) +- (void) close(fapolicyd_state.fd); +- +- fapolicyd_state.fd = -1; ++ (void) close_fifo(&fapolicyd_state); + } + + static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) +@@ -116,9 +172,9 @@ static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res) + /* we are ready */ + if (fapolicyd_state.fd > 0) { + /* send a signal that transaction is over */ +- (void) write_fifo(&fapolicyd_state, "1\n"); ++ (void) try_to_write_to_fifo(&fapolicyd_state, "1\n"); + /* flush cache */ +- (void) write_fifo(&fapolicyd_state, "2\n"); ++ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n"); + } + + end: +@@ -133,7 +189,7 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name, + + if (fapolicyd_state.changed_files > 0) { + /* send signal to flush cache */ +- (void) write_fifo(&fapolicyd_state, "2\n"); ++ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n"); + + /* optimize flushing */ + /* flush only when there was an actual change */ +@@ -176,7 +232,7 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + char * sha = rpmfiFDigestHex(fi, NULL); + + snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha); +- (void) write_fifo(&fapolicyd_state, buffer); ++ (void) try_to_write_to_fifo(&fapolicyd_state, buffer); + + free(sha); + +-- +2.37.3 + diff --git a/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch b/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch new file mode 100644 index 0000000..48039c7 --- /dev/null +++ b/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch @@ -0,0 +1,101 @@ +diff -up rpm-4.14.3/lib/rpmscript.c.orig rpm-4.14.3/lib/rpmscript.c +--- rpm-4.14.3/lib/rpmscript.c.orig 2021-02-08 14:07:44.527197946 +0100 ++++ rpm-4.14.3/lib/rpmscript.c 2021-02-08 14:09:05.732749080 +0100 +@@ -46,27 +46,27 @@ struct scriptInfo_s { + }; + + static const struct scriptInfo_s scriptInfo[] = { +- { RPMSCRIPT_PREIN, "%prein", 0, ++ { RPMSCRIPT_PREIN, "prein", 0, + RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS }, +- { RPMSCRIPT_PREUN, "%preun", 0, ++ { RPMSCRIPT_PREUN, "preun", 0, + RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS }, +- { RPMSCRIPT_POSTIN, "%post", 0, ++ { RPMSCRIPT_POSTIN, "post", 0, + RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS }, +- { RPMSCRIPT_POSTUN, "%postun", 0, ++ { RPMSCRIPT_POSTUN, "postun", 0, + RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS }, +- { RPMSCRIPT_PRETRANS, "%pretrans", 0, ++ { RPMSCRIPT_PRETRANS, "pretrans", 0, + RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS }, +- { RPMSCRIPT_POSTTRANS, "%posttrans", 0, ++ { RPMSCRIPT_POSTTRANS, "posttrans", 0, + RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS }, +- { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN, ++ { RPMSCRIPT_TRIGGERPREIN, "triggerprein", RPMSENSE_TRIGGERPREIN, + RPMTAG_TRIGGERPREIN, 0, 0 }, +- { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN, ++ { RPMSCRIPT_TRIGGERUN, "triggerun", RPMSENSE_TRIGGERUN, + RPMTAG_TRIGGERUN, 0, 0 }, +- { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN, ++ { RPMSCRIPT_TRIGGERIN, "triggerin", RPMSENSE_TRIGGERIN, + RPMTAG_TRIGGERIN, 0, 0 }, +- { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN, ++ { RPMSCRIPT_TRIGGERPOSTUN, "triggerpostun", RPMSENSE_TRIGGERPOSTUN, + RPMTAG_TRIGGERPOSTUN, 0, 0 }, +- { RPMSCRIPT_VERIFY, "%verify", 0, ++ { RPMSCRIPT_VERIFY, "verify", 0, + RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS}, + { 0, "unknown", 0, + RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND } +@@ -457,7 +457,7 @@ static const char * tag2sln(rpmTagVal ta + } + + static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body, +- rpmscriptFlags flags) ++ rpmscriptFlags flags, const char *prefix) + { + char *nevra = headerGetAsString(h, RPMTAG_NEVRA); + rpmScript script = xcalloc(1, sizeof(*script)); +@@ -465,7 +465,7 @@ static rpmScript rpmScriptNew(Header h, + script->type = getScriptType(tag); + script->flags = flags; + script->body = (body != NULL) ? xstrdup(body) : NULL; +- rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra); ++ rasprintf(&script->descr, "%%%s%s(%s)", prefix, tag2sln(tag), nevra); + + /* macros need to be expanded before possible queryformat */ + if (script->body && (script->flags & RPMSCRIPT_FLAG_EXPAND)) { +@@ -556,6 +556,7 @@ rpmScript rpmScriptFromTriggerTag(Header + rpmScript script = NULL; + struct rpmtd_s tscripts, tprogs, tflags; + headerGetFlags hgflags = HEADERGET_MINMEM; ++ const char *prefix = ""; + + switch (tm) { + case RPMSCRIPT_NORMALTRIGGER: +@@ -567,11 +568,13 @@ rpmScript rpmScriptFromTriggerTag(Header + headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags); + headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags); + headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags); ++ prefix = "file"; + break; + case RPMSCRIPT_TRANSFILETRIGGER: + headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags); + headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags); + headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags); ++ prefix = "transfile"; + break; + } + +@@ -582,7 +585,8 @@ rpmScript rpmScriptFromTriggerTag(Header + if (rpmtdSetIndex(&tflags, ix) >= 0) + sflags = rpmtdGetNumber(&tflags); + +- script = rpmScriptNew(h, triggerTag, rpmtdGetString(&tscripts), sflags); ++ script = rpmScriptNew(h, triggerTag, ++ rpmtdGetString(&tscripts), sflags, prefix); + + /* hack up a hge-style NULL-terminated array */ + script->args = xmalloc(2 * sizeof(*script->args) + strlen(prog) + 1); +@@ -608,7 +612,7 @@ rpmScript rpmScriptFromTag(Header h, rpm + + script = rpmScriptNew(h, scriptTag, + headerGetString(h, scriptTag), +- headerGetNumber(h, getFlagTag(scriptTag))); ++ headerGetNumber(h, getFlagTag(scriptTag)), ""); + + if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) { + script->args = prog.data; diff --git a/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch b/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch new file mode 100644 index 0000000..6b26ec5 --- /dev/null +++ b/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch @@ -0,0 +1,184 @@ +From f17aa638649fb8de730fecdbc906dc869b626ba5 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Tue, 16 Nov 2021 11:49:18 +0200 +Subject: [PATCH 1/2] Fix spurious %transfiletriggerpostun execution + (RhBug:2023311) + +If a package has multiple %transfiletriggerpostun triggers, any one +of them matching would cause all of them to run, due to disconnect +in the intel gathering stage: we'd gather all the headers with matching +files into a lump, and then add any postun triggers found in them, +but this loses the triggering file information and causes all postuns +to run. + +The triggers need to be added while looping over the file matches, +like runFileTriggers() does. Doing so actually simplifies the code. +These should really be unified to use the same code, but leaving +that exercise to another rainy day. +--- + lib/rpmtriggers.c | 64 +++++++++++++++++++++++------------------------ + 1 file changed, 31 insertions(+), 33 deletions(-) + +diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c +index 0827af0c2..dc457f7cc 100644 +--- a/lib/rpmtriggers.c ++++ b/lib/rpmtriggers.c +@@ -97,19 +97,37 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs) + } + } + ++static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter) ++{ ++ int tix = 0; ++ rpmds ds; ++ rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); ++ ++ while ((ds = rpmdsFilterTi(triggers, tix))) { ++ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) { ++ struct rpmtd_s priorities; ++ ++ if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, ++ &priorities, HEADERGET_MINMEM)) { ++ rpmtdSetIndex(&priorities, tix); ++ rpmtriggersAdd(ts->trigs2run, headerGetInstance(trigH), ++ tix, *rpmtdGetUint32(&priorities)); ++ } ++ } ++ rpmdsFree(ds); ++ tix++; ++ } ++ rpmdsFree(triggers); ++} ++ + void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) + { +- rpmdbMatchIterator mi; + rpmdbIndexIterator ii; +- Header trigH; + const void *key; + size_t keylen; + rpmfiles files; +- rpmds rpmdsTriggers; +- rpmds rpmdsTrigger; + + ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME); +- mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES); + files = rpmteFiles(te); + + /* Iterate over file triggers in rpmdb */ +@@ -121,39 +139,19 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) + rpmfi fi = rpmfilesFindPrefix(files, pfx); + while (rpmfiNext(fi) >= 0) { + if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { +- /* If yes then store it */ +- rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii), +- rpmdbIndexIteratorNumPkgs(ii)); +- break; ++ unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii); ++ const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii); ++ /* Save any matching postun triggers */ ++ for (int i = 0; i < npkg; i++) { ++ Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]); ++ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN); ++ headerFree(h); ++ } + } + } + rpmfiFree(fi); + } + rpmdbIndexIteratorFree(ii); +- +- if (rpmdbGetIteratorCount(mi)) { +- /* Filter triggers and save only trans postun triggers into ts */ +- while ((trigH = rpmdbNextIterator(mi)) != NULL) { +- int tix = 0; +- rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); +- while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) { +- if ((rpmdsNext(rpmdsTrigger) >= 0) && +- (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) { +- struct rpmtd_s priorities; +- +- headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, +- &priorities, HEADERGET_MINMEM); +- rpmtdSetIndex(&priorities, tix); +- rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi), +- tix, *rpmtdGetUint32(&priorities)); +- } +- rpmdsFree(rpmdsTrigger); +- tix++; +- } +- rpmdsFree(rpmdsTriggers); +- } +- } +- rpmdbFreeIterator(mi); + rpmfilesFree(files); + } + +-- +2.35.1 + +From e617e7c550d3523998707c55f96b37ede2c48c78 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 2 Feb 2022 13:46:23 +0200 +Subject: [PATCH 2/2] Really fix spurious %transfiletriggerpostun execution + (RhBug:2023311) + +Commit b3d672a5523dfec033160e5cc866432a0e808649 got the base reasoning +in the ballpark but the code all wrong, introducing a severe performance +regression without actually fixing what it claimed to. + +The missing incredient is actually comparing the current prefix with the +triggers in matched package (trying to describe this makes my head +spin): a package may have multiple triggers on multiple prefixes and +we need to make sure we only execute triggers of this type, from this +prefix. + +This stuff really needs more and better testcases. + +Fixes: b3d672a5523dfec033160e5cc866432a0e808649 +--- + lib/rpmtriggers.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c +index dc457f7cc..c652981be 100644 +--- a/lib/rpmtriggers.c ++++ b/lib/rpmtriggers.c +@@ -97,14 +97,16 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs) + } + } + +-static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter) ++static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter, ++ const char *prefix) + { + int tix = 0; + rpmds ds; + rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); + + while ((ds = rpmdsFilterTi(triggers, tix))) { +- if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) { ++ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter) && ++ strcmp(prefix, rpmdsN(ds)) == 0) { + struct rpmtd_s priorities; + + if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, +@@ -141,12 +143,13 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) + if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { + unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii); + const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii); +- /* Save any matching postun triggers */ ++ /* Save any postun triggers matching this prefix */ + for (int i = 0; i < npkg; i++) { + Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]); +- addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN); ++ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN, pfx); + headerFree(h); + } ++ break; + } + } + rpmfiFree(fi); +-- +2.35.1 + diff --git a/rpm-4.14.3-hdrblobInit-add-bounds-check.patch b/rpm-4.14.3-hdrblobInit-add-bounds-check.patch new file mode 100644 index 0000000..8321161 --- /dev/null +++ b/rpm-4.14.3-hdrblobInit-add-bounds-check.patch @@ -0,0 +1,100 @@ +commit 8f4b3c3cab8922a2022b9e47c71f1ecf906077ef +Author: Demi Marie Obenour +Date: Mon Feb 8 16:05:01 2021 -0500 + + hdrblobInit() needs bounds checks too + + Users can pass untrusted data to hdrblobInit() and it must be robust + against this. + +diff --git a/lib/header.c b/lib/header.c +index ea39e679f..ebba9c2b0 100644 +--- a/lib/header.c ++++ b/lib/header.c +@@ -11,6 +11,7 @@ + #include "system.h" + #include + #include ++#include + #include + #include + #include "lib/header_internal.h" +@@ -1912,6 +1913,25 @@ hdrblob hdrblobFree(hdrblob blob) + return NULL; + } + ++static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl, ++ char **emsg) { ++ uint32_t il_max = HEADER_TAGS_MAX; ++ uint32_t dl_max = HEADER_DATA_MAX; ++ if (regionTag == RPMTAG_HEADERSIGNATURES) { ++ il_max = 32; ++ dl_max = 64 * 1024 * 1024; ++ } ++ if (hdrchkRange(il_max, il)) { ++ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il); ++ return RPMRC_FAIL; ++ } ++ if (hdrchkRange(dl_max, dl)) { ++ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; ++} ++ + rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg) + { + int32_t block[4]; +@@ -1924,13 +1944,6 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl + size_t nb; + rpmRC rc = RPMRC_FAIL; /* assume failure */ + int xx; +- int32_t il_max = HEADER_TAGS_MAX; +- int32_t dl_max = HEADER_DATA_MAX; +- +- if (regionTag == RPMTAG_HEADERSIGNATURES) { +- il_max = 32; +- dl_max = 64 * 1024 * 1024; +- } + + memset(block, 0, sizeof(block)); + if ((xx = Freadall(fd, bs, blen)) != blen) { +@@ -1943,15 +1956,9 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl + goto exit; + } + il = ntohl(block[2]); +- if (hdrchkRange(il_max, il)) { +- rasprintf(emsg, _("hdr tags: BAD, no. of tags(%d) out of range"), il); +- goto exit; +- } + dl = ntohl(block[3]); +- if (hdrchkRange(dl_max, dl)) { +- rasprintf(emsg, _("hdr data: BAD, no. of bytes(%d) out of range"), dl); ++ if (hdrblobVerifyLengths(regionTag, il, dl, emsg)) + goto exit; +- } + + nb = (il * sizeof(struct entryInfo_s)) + dl; + uc = sizeof(il) + sizeof(dl) + nb; +@@ -1995,11 +2002,18 @@ rpmRC hdrblobInit(const void *uh, size_t uc, + struct hdrblob_s *blob, char **emsg) + { + rpmRC rc = RPMRC_FAIL; +- + memset(blob, 0, sizeof(*blob)); ++ if (uc && uc < 8) { ++ rasprintf(emsg, _("hdr length: BAD")); ++ goto exit; ++ } ++ + blob->ei = (int32_t *) uh; /* discards const */ +- blob->il = ntohl(blob->ei[0]); +- blob->dl = ntohl(blob->ei[1]); ++ blob->il = ntohl((uint32_t)(blob->ei[0])); ++ blob->dl = ntohl((uint32_t)(blob->ei[1])); ++ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK) ++ goto exit; ++ + blob->pe = (entryInfo) &(blob->ei[2]); + blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) + + (blob->il * sizeof(*blob->pe)) + blob->dl; diff --git a/rpm-4.14.3-imp-covscan-fixes.patch b/rpm-4.14.3-imp-covscan-fixes.patch new file mode 100644 index 0000000..679c474 --- /dev/null +++ b/rpm-4.14.3-imp-covscan-fixes.patch @@ -0,0 +1,327 @@ +commit c7d7c5acd0c14d0450016887cba1d86483086794 +Author: Michal Domonkos +Date: Mon Jun 21 10:05:10 2021 +0200 + + Add quoting to literal curly brackets + + These curly brackets are already treated as literals by the shell, so + let's make that explicit for clarity, and silence a ShellCheck warning + at the same time. + + More info: https://github.com/koalaman/shellcheck/wiki/SC1083 + + Found by ShellCheck. + +diff -up rpm-4.16.1.3/scripts/check-rpaths-worker.orig rpm-4.16.1.3/scripts/check-rpaths-worker +--- rpm-4.16.1.3/scripts/check-rpaths-worker.orig 2021-06-29 15:34:31.671003589 +0200 ++++ rpm-4.16.1.3/scripts/check-rpaths-worker 2021-06-29 15:34:51.993414093 +0200 +@@ -120,13 +120,13 @@ for i; do + (/lib64/*|/usr/lib64/*|/usr/X11R6/lib64/*|/usr/local/lib64/*) + badness=0;; + +- (\$ORIGIN|\${ORIGINX}|\$ORIGIN/*|\${ORIGINX}/*) ++ (\$ORIGIN|\$\{ORIGINX\}|\$ORIGIN/*|\$\{ORIGINX\}/*) + test $allow_ORIGIN -eq 0 && badness=8 || { + badness=0 + new_allow_ORIGIN=1 + } + ;; +- (/*\$PLATFORM*|/*\${PLATFORM}*|/*\$LIB*|/*\${LIB}*) ++ (/*\$PLATFORM*|/*\$\{PLATFORM\}*|/*\$LIB*|/*\$\{LIB\}*) + badness=0;; + + (/lib|/usr/lib|/usr/X11R6/lib) +From d8dc4fd37b1d90cd97de7fcf484d449ec132c9b3 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Wed, 9 Jun 2021 21:31:40 +0200 +Subject: [PATCH 1/7] Fix memory leak in sqlexec() + +Callers are supposed to free the error strings themselves: +https://www.sqlite.org/capi3ref.html#sqlite3_exec + +Found by Coverity. +--- + lib/backend/sqlite.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c +index 7c2de45aa..dbefeb163 100644 +--- a/lib/backend/sqlite.c ++++ b/lib/backend/sqlite.c +@@ -233,6 +233,7 @@ static int sqlexec(sqlite3 *sdb, const char *fmt, ...) + rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc); + + sqlite3_free(cmd); ++ sqlite3_free(err); + + return rc ? RPMRC_FAIL : RPMRC_OK; + } +-- +2.31.1 + +From 5baf73feb4951cc3b3f553a4b18d3b3599cbf87c Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 25 Jun 2021 11:21:46 +0200 +Subject: [PATCH 2/7] Always free the arg list passed to rpmGlob() + +Even though the actual implementation of rpmGlob() does not allocate the +passed arg list (av) if the return code (rc) is non-zero or arg count +(ac) is 0, it's the responsibility of the caller (rpmInstall() here) to +free that memory, so make sure we do that irrespectively of the above +conditions. + +Found by Coverity. +--- + lib/rpminstall.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rpminstall.c b/lib/rpminstall.c +index 724126e94..302ec0ba1 100644 +--- a/lib/rpminstall.c ++++ b/lib/rpminstall.c +@@ -461,6 +461,7 @@ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv) + rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp); + } + eiu->numFailed++; ++ argvFree(av); + continue; + } + +-- +2.31.1 + +From 3c8b01b67ec907afaaffe71691fa41b878578527 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Mon, 14 Jun 2021 10:21:25 +0200 +Subject: [PATCH 3/7] Fix resource leak in Fts_children() + +This function is not used anywhere within our codebase (and neither is +it part of the public API) so it's basically a no-op... Still, rather +than yanking it completely, let's just silence the Coverity error here. + +Found by Coverity. +--- + misc/fts.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/misc/fts.c b/misc/fts.c +index d3ebb2946..caf27495d 100644 +--- a/misc/fts.c ++++ b/misc/fts.c +@@ -585,8 +585,10 @@ Fts_children(FTS * sp, int instr) + if ((fd = __open(".", O_RDONLY, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); +- if (__fchdir(fd)) ++ if (__fchdir(fd)) { ++ (void)__close(fd); + return (NULL); ++ } + (void)__close(fd); + return (sp->fts_child); + } +-- +2.31.1 + +From 39b7bf8579e0522cf16347b3a7e332d3b6d742c6 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Mon, 14 Jun 2021 12:34:23 +0200 +Subject: [PATCH 4/7] Fix memory leak in fts_build() + +Turns out this leak is already fixed in glibc's current version of fts.c +(where our copy originates from), so let's just backport that. + +Original commit in glibc: +https://sourceware.org/git/?p=glibc.git;\ +a=commit;h=db67c2c98b89a5723af44df54f38b779de8d4a65 + +Found by Coverity. +--- + misc/fts.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/misc/fts.c b/misc/fts.c +index caf27495d..f7fce0eaa 100644 +--- a/misc/fts.c ++++ b/misc/fts.c +@@ -855,6 +855,7 @@ mem1: saved_errno = errno; + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); ++ fts_lfree(head); + return (NULL); + } + +@@ -862,6 +863,7 @@ mem1: saved_errno = errno; + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; ++ fts_lfree(head); + return (NULL); + } + +-- +2.31.1 + +From 9c093c4f092dd6bd1e0c8d2b852a72b74db076c2 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Tue, 15 Jun 2021 13:34:21 +0200 +Subject: [PATCH 5/7] Fix memory leak in decodePkts() + +Found by Coverity. +--- + rpmio/rpmpgp.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index c59185dce..ee5c81e24 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -1371,9 +1371,13 @@ static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen) + crc = pgpCRC(dec, declen); + if (crcpkt != crc) { + ec = PGPARMOR_ERR_CRC_CHECK; ++ _free(dec); + goto exit; + } +- if (pkt) *pkt = dec; ++ if (pkt) ++ *pkt = dec; ++ else ++ _free(dec); + if (pktlen) *pktlen = declen; + ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */ + goto exit; +-- +2.31.1 + +From 590b2fc06252567eb7d57197dc361a8b459d62a3 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Mon, 21 Jun 2021 17:51:14 +0200 +Subject: [PATCH 6/7] Fix memory leak with multiple %lang-s in one line + +We permit two equivalent forms of specifying a list of languages per +file: + + %lang(xx,yy,zz) /path/to/file + %lang(xx) %lang(yy) %lang(zz) /path/to/file + +The leak was when parsing the second form. + +Found by Coverity. +--- + build/files.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/build/files.c b/build/files.c +index f8153ad2b..0c8859f6c 100644 +--- a/build/files.c ++++ b/build/files.c +@@ -777,6 +777,8 @@ static rpmRC parseForLang(char * buf, FileEntry cur) + + if (*pe == ',') pe++; /* skip , if present */ + } ++ ++ q = _free(q); + } + + rc = RPMRC_OK; +-- +2.31.1 + +From b7a1e996326ee29a163d67ceb1e6127fdc251c14 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 25 Jun 2021 15:15:08 +0200 +Subject: [PATCH 7/7] Fix memory leaks in Lua rex extension + +This covers the following usage: + +expr = rex.newPOSIX() +expr:match() # A leak occurred here +expr:gmatch(, ) # A leak occurred here + +Found by Coverity. +--- + luaext/lrexlib.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/luaext/lrexlib.c b/luaext/lrexlib.c +index 09c5a6454..0f29b6371 100644 +--- a/luaext/lrexlib.c ++++ b/luaext/lrexlib.c +@@ -80,6 +80,7 @@ static void rex_push_matches(lua_State *L, const char *text, regmatch_t *match, + + static int rex_match(lua_State *L) + { ++ int rc = 0; + int res; + #ifdef REG_BASIC + size_t len; +@@ -109,9 +110,10 @@ static int rex_match(lua_State *L) + lua_pushstring(L, "n"); + lua_pushnumber(L, ncapt); + lua_rawset(L, -3); +- return 3; +- } else +- return 0; ++ rc = 3; ++ } ++ free(match); ++ return rc; + } + + static int rex_gmatch(lua_State *L) +@@ -158,6 +160,7 @@ static int rex_gmatch(lua_State *L) + break; + } + lua_pushnumber(L, nmatch); ++ free(match); + return 1; + } + +-- +2.31.1 + +commit 9747a6af016a3458d54fe060777c95e3900b5fa4 +Author: Demi Marie Obenour +Date: Tue Mar 2 12:47:29 2021 -0500 + + Fix a tiny memory leak + + Found by fuzzing rpmReadPackageFile() with libfuzzer under ASAN. + +diff --git a/lib/headerutil.c b/lib/headerutil.c +index 22e36c74d..fab210ff2 100644 +--- a/lib/headerutil.c ++++ b/lib/headerutil.c +@@ -333,8 +333,10 @@ static void providePackageNVR(Header h) + rpmds hds, nvrds; + + /* Generate provides for this package name-version-release. */ +- if (!(name && pEVR)) ++ if (!(name && pEVR)) { ++ free(pEVR); + return; ++ } + + /* + * Rpm prior to 3.0.3 does not have versioned provides. +commit cb2ae4bdf2f60876fdc68e3f84938e9c37182fab +Author: Igor Gnatenko +Date: Tue Feb 6 14:50:27 2018 +0100 + + lua: fix memory leak in Pexec() + + Signed-off-by: Igor Gnatenko + +diff --git a/luaext/lposix.c b/luaext/lposix.c +index 5d7ad3c87..2730bcff7 100644 +--- a/luaext/lposix.c ++++ b/luaext/lposix.c +@@ -348,6 +348,7 @@ static int Pexec(lua_State *L) /** exec(path,[args]) */ + for (i=1; i +Date: Thu, 27 May 2021 13:58:58 +0300 +Subject: [PATCH] Macroize find-debuginfo script location + +Makes it easier to handle varying paths, mainly in preparation for the +next step. + +Backported for 4.14.3. +--- + macros.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/macros.in b/macros.in +index a6069ee4d..be28a3b28 100644 +--- a/macros.in ++++ b/macros.in +@@ -82,6 +82,8 @@ + %__remsh %{__rsh} + %__strip @__STRIP@ + ++%__find_debuginfo %{_rpmconfigdir}/find-debuginfo.sh ++ + # XXX avoid failures if tools are not installed when rpm is built. + %__libtoolize libtoolize + %__aclocal aclocal +@@ -177,7 +179,7 @@ + # the script. See the script for details. + # + %__debug_install_post \ +- %{_rpmconfigdir}/find-debuginfo.sh \\\ ++ %{__find_debuginfo} \\\ + %{?_smp_mflags} \\\ + %{?_missing_build_ids_terminate_build:--strict-build-id} \\\ + %{?_no_recompute_build_ids:-n} \\\ +-- +2.33.1 + diff --git a/rpm-4.14.3-more-careful-sig-hdr-copy.patch b/rpm-4.14.3-more-careful-sig-hdr-copy.patch new file mode 100644 index 0000000..4a4f4ae --- /dev/null +++ b/rpm-4.14.3-more-careful-sig-hdr-copy.patch @@ -0,0 +1,162 @@ +commit d6a86b5e69e46cc283b1e06c92343319beb42e21 +Author: Panu Matilainen +Date: Thu Mar 4 13:21:19 2021 +0200 + + Be much more careful about copying data from the signature header + + Only look for known tags, and ensure correct type and size where known + before copying over. Bump the old arbitrary 16k count limit to 16M limit + though, it's not inconceivable that a package could have that many files. + While at it, ensure none of these tags exist in the main header, + which would confuse us greatly. + + This is optimized for backporting ease, upstream can remove redundancies + and further improve checking later. + + Reported and initial patches by Demi Marie Obenour. + + Fixes: RhBug:1935049, RhBug:1933867, RhBug:1935035, RhBug:1934125, ... + + Fixes: CVE-2021-3421, CVE-2021-20271 + + Combined with e2f1f1931c5ccf3ecbe4e1e12cacb1e17a277776 and backported into + 4.14.3 + +diff -up rpm-4.14.3/lib/package.c.orig rpm-4.14.3/lib/package.c +--- rpm-4.14.3/lib/package.c.orig 2021-05-31 12:32:49.970393976 +0200 ++++ rpm-4.14.3/lib/package.c 2021-05-31 13:53:58.250673275 +0200 +@@ -31,76 +31,72 @@ struct pkgdata_s { + rpmRC rc; + }; + ++struct taglate_s { ++ rpmTagVal stag; ++ rpmTagVal xtag; ++ rpm_count_t count; ++ int quirk; ++} const xlateTags[] = { ++ { RPMSIGTAG_SIZE, RPMTAG_SIGSIZE, 1, 0 }, ++ { RPMSIGTAG_PGP, RPMTAG_SIGPGP, 0, 0 }, ++ { RPMSIGTAG_MD5, RPMTAG_SIGMD5, 16, 0 }, ++ { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 }, ++ /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */ ++ { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 }, ++ { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, ++ { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, ++ { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, ++ { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0, 0 }, ++ { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1, 0 }, ++ { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1, 0 }, ++ { 0 } ++}; ++ + /** \ingroup header + * Translate and merge legacy signature tags into header. + * @param h header (dest) + * @param sigh signature header (src) ++ * @return failing tag number, 0 on success + */ + static +-void headerMergeLegacySigs(Header h, Header sigh) ++rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg) + { +- HeaderIterator hi; ++ const struct taglate_s *xl; + struct rpmtd_s td; + +- hi = headerInitIterator(sigh); +- for (; headerNext(hi, &td); rpmtdFreeData(&td)) +- { +- switch (td.tag) { +- /* XXX Translate legacy signature tag values. */ +- case RPMSIGTAG_SIZE: +- td.tag = RPMTAG_SIGSIZE; +- break; +- case RPMSIGTAG_PGP: +- td.tag = RPMTAG_SIGPGP; +- break; +- case RPMSIGTAG_MD5: +- td.tag = RPMTAG_SIGMD5; +- break; +- case RPMSIGTAG_GPG: +- td.tag = RPMTAG_SIGGPG; +- break; +- case RPMSIGTAG_PGP5: +- td.tag = RPMTAG_SIGPGP5; +- break; +- case RPMSIGTAG_PAYLOADSIZE: +- td.tag = RPMTAG_ARCHIVESIZE; +- break; +- case RPMSIGTAG_SHA1: +- case RPMSIGTAG_SHA256: +- case RPMSIGTAG_DSA: +- case RPMSIGTAG_RSA: +- default: +- if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE)) ++ rpmtdReset(&td); ++ for (xl = xlateTags; xl->stag; xl++) { ++ /* There mustn't be one in the main header */ ++ if (headerIsEntry(h, xl->xtag)) { ++ /* Some tags may exist in either header, but never both */ ++ if (xl->quirk && !headerIsEntry(sigh, xl->stag)) + continue; + break; + } +- if (!headerIsEntry(h, td.tag)) { +- switch (td.type) { +- case RPM_NULL_TYPE: +- continue; ++ if (headerGet(sigh, xl->stag, &td, HEADERGET_RAW|HEADERGET_MINMEM)) { ++ /* Translate legacy tags */ ++ if (xl->stag != xl->xtag) ++ td.tag = xl->xtag; ++ /* Ensure type and tag size match expectations */ ++ if (td.type != rpmTagGetTagType(td.tag)) + break; +- case RPM_CHAR_TYPE: +- case RPM_INT8_TYPE: +- case RPM_INT16_TYPE: +- case RPM_INT32_TYPE: +- case RPM_INT64_TYPE: +- if (td.count != 1) +- continue; ++ if (td.count < 1 || td.count > 16*1024*1024) + break; +- case RPM_STRING_TYPE: +- case RPM_BIN_TYPE: +- if (td.count >= 16*1024) +- continue; ++ if (xl->count && td.count != xl->count) + break; +- case RPM_STRING_ARRAY_TYPE: +- case RPM_I18NSTRING_TYPE: +- continue; ++ if (!headerPut(h, &td, HEADERPUT_DEFAULT)) + break; +- } +- (void) headerPut(h, &td, HEADERPUT_DEFAULT); ++ rpmtdFreeData(&td); + } + } +- headerFreeIterator(hi); ++ rpmtdFreeData(&td); ++ ++ if (xl->stag) { ++ rasprintf(msg, "invalid signature tag %s (%d)", ++ rpmTagGetName(xl->xtag), xl->xtag); ++ } ++ ++ return xl->stag; + } + + /** +@@ -363,7 +359,8 @@ rpmRC rpmReadPackageFile(rpmts ts, FD_t + goto exit; + + /* Append (and remap) signature tags to the metadata. */ +- headerMergeLegacySigs(h, sigh); ++ if (headerMergeLegacySigs(h, sigh, &msg)) ++ goto exit; + applyRetrofits(h); + + /* Bump reference count for return. */ diff --git a/rpm-4.14.3-python3.diff b/rpm-4.14.3-python3.diff new file mode 100644 index 0000000..7ec81b5 --- /dev/null +++ b/rpm-4.14.3-python3.diff @@ -0,0 +1,13 @@ +--- rpm-4.14.3/configure.ac.orig 2020-05-04 21:08:41.481365399 +0200 ++++ rpm-4.14.3/configure.ac 2020-05-04 21:09:03.550604043 +0200 +@@ -129,8 +129,8 @@ + + AC_PATH_PROG(__PERL, perl, /usr/bin/perl, $MYPATH) + AC_PATH_PROG(__PGP, pgp, /usr/bin/pgp, $MYPATH) +-AC_PATH_PROG(__PYTHON, python2, /usr/bin/python2, $MYPATH) +-AC_PATH_PROG(PYTHON, python2, /usr/bin/python2, $MYPATH) ++AC_PATH_PROG(__PYTHON, python3, /usr/bin/python3, $MYPATH) ++AC_PATH_PROG(PYTHON, python3, /usr/bin/python3, $MYPATH) + AC_PATH_PROG(__RM, rm, /bin/rm, $MYPATH) + AC_PATH_PROG(__RSH, rsh, /usr/bin/rsh, $MYPATH) + AC_PATH_PROG(__SED, sed, /bin/sed, $MYPATH) diff --git a/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch b/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch new file mode 100644 index 0000000..ff9d1a3 --- /dev/null +++ b/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch @@ -0,0 +1,29 @@ +From fe274b8f965582fdf97e6c46f90b9e7c124b0b8b Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Fri, 16 Dec 2022 15:50:12 +0100 +Subject: [PATCH] rpm2archive: Don't print usage on no arguments + +given as we want to default to reading from stdin and writing to stdout in +that case. +--- + rpm2archive.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/rpm2archive.c b/rpm2archive.c +index 09da8d16b..53f047f58 100644 +--- a/rpm2archive.c ++++ b/rpm2archive.c +@@ -241,10 +241,6 @@ int main(int argc, const char *argv[]) + exit(EXIT_FAILURE); + } + } +- if (argc < 2 || poptGetNextOpt(optCon) == 0) { +- poptPrintUsage(optCon, stderr, 0); +- exit(EXIT_FAILURE); +- } + + rpmts ts = rpmtsCreate(); + rpmVSFlags vsflags = 0; +-- +2.38.1 + diff --git a/rpm-4.14.3-rpm2archive-nocompression.patch b/rpm-4.14.3-rpm2archive-nocompression.patch new file mode 100644 index 0000000..92c84ae --- /dev/null +++ b/rpm-4.14.3-rpm2archive-nocompression.patch @@ -0,0 +1,138 @@ +From d8a169164cf40fc1cf6448792c1fa991f19bb375 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Thu, 22 Apr 2021 14:50:34 +0200 +Subject: [PATCH] Add --nocompression option to rpm2archive + +Also use popt for the command line handling. As we are using librpm +anyway there is no reason to keep the dependencies low (as with +rpm2cpio). + +Resolves: #1530 +--- + doc/rpm2archive.8 | 16 ++++++++++--- + rpm2archive.c | 60 ++++++++++++++++++++++++++++++++++------------- + 2 files changed, 57 insertions(+), 19 deletions(-) + +diff --git a/rpm2archive.c b/rpm2archive.c +index d96db006ea..cb39c7a712 100644 +--- a/rpm2archive.c ++++ b/rpm2archive.c +@@ -10,6 +10,8 @@ + + #include + ++#include ++ + #include + #include + #include +@@ -18,6 +20,16 @@ + + #define BUFSIZE (128*1024) + ++int compress = 1; ++ ++static struct poptOption optionsTable[] = { ++ { "nocompression", 'n', POPT_ARG_VAL, &compress, 0, ++ N_("create uncompressed tar file"), ++ NULL }, ++ POPT_AUTOHELP ++ POPT_TABLEEND ++}; ++ + static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi) + { + archive_entry_clear(entry); +@@ -60,7 +72,7 @@ static void write_file_content(struct archive * a, char * buf, rpmfi fi) + } + } + +-static int process_package(rpmts ts, char * filename) ++static int process_package(rpmts ts, const char * filename) + { + FD_t fdi; + FD_t gzdi; +@@ -119,9 +131,11 @@ static int process_package(rpmts ts, char * filename) + + /* create archive */ + a = archive_write_new(); +- if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { +- fprintf(stderr, "Error: Could not create gzip output filter\n"); +- exit(EXIT_FAILURE); ++ if (compress) { ++ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { ++ fprintf(stderr, "%s\n", archive_error_string(a)); ++ exit(EXIT_FAILURE); ++ } + } + if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) { + fprintf(stderr, "Error: Format pax restricted is not supported\n"); +@@ -142,7 +156,12 @@ static int process_package(rpmts ts, char * filename) + } + archive_write_open_fd(a, STDOUT_FILENO); + } else { +- char * outname = rstrscat(NULL, filename, ".tgz", NULL); ++ char * outname = rstrscat(NULL, filename, NULL); ++ if (compress) { ++ outname = rstrscat(&outname, ".tgz", NULL); ++ } else { ++ outname = rstrscat(&outname, ".tar", NULL); ++ } + if (archive_write_open_filename(a, outname) != ARCHIVE_OK) { + fprintf(stderr, "Error: Can't open output file: %s\n", outname); + exit(EXIT_FAILURE); +@@ -203,21 +222,22 @@ static int process_package(rpmts ts, char * filename) + return rc; + } + +-int main(int argc, char *argv[]) ++int main(int argc, const char *argv[]) + { +- int rc = 0, i; ++ int rc = 0; ++ poptContext optCon; ++ const char *fn; + + xsetprogname(argv[0]); /* Portability call -- see system.h */ + rpmReadConfigFiles(NULL, NULL); + +- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { +- fprintf(stderr, "Usage: %s [file.rpm ...]\n", argv[0]); ++ optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); ++ poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); ++ if (argc < 2 || poptGetNextOpt(optCon) == 0) { ++ poptPrintUsage(optCon, stderr, 0); + exit(EXIT_FAILURE); + } + +- if (argc == 1) +- argv[argc++] = "-"; /* abuse NULL pointer at the end of argv */ +- + rpmts ts = rpmtsCreate(); + rpmVSFlags vsflags = 0; + +@@ -227,13 +247,21 @@ int main(int argc, char *argv[]) + vsflags |= RPMVSF_NOHDRCHK; + (void) rpmtsSetVSFlags(ts, vsflags); + +- for (i = 1; i < argc; i++) { ++ /* if no file name is given use stdin/stdout */ ++ if (!poptPeekArg(optCon)) { ++ rc = process_package(ts, "-"); ++ if (rc != 0) ++ goto exit; ++ } + +- rc = process_package(ts, argv[i]); ++ while ((fn = poptGetArg(optCon)) != NULL) { ++ rc = process_package(ts, fn); + if (rc != 0) +- return rc; ++ goto exit; + } + ++ exit: ++ poptFreeContext(optCon); + (void) rpmtsFree(ts); + return rc; + } diff --git a/rpm-4.14.3-rpm2archive-parse-popt-options.patch b/rpm-4.14.3-rpm2archive-parse-popt-options.patch new file mode 100644 index 0000000..0170c35 --- /dev/null +++ b/rpm-4.14.3-rpm2archive-parse-popt-options.patch @@ -0,0 +1,36 @@ +From 8f416b275a365426b07c75adfc017e0b18a85450 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Fri, 16 Dec 2022 15:45:20 +0100 +Subject: [PATCH] rpm2archive: Properly parse popt options + +and issue an error message for unknown options. Before unknown options +could mess up the argument parsing leading to reading and writing from +stdin/stdout. + +Thanks to Eva Mrakova and the Red Hat QE team for spotting this! +--- + rpm2archive.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/rpm2archive.c b/rpm2archive.c +index de1a17d2b..09da8d16b 100644 +--- a/rpm2archive.c ++++ b/rpm2archive.c +@@ -233,6 +233,14 @@ int main(int argc, const char *argv[]) + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); ++ while ((rc = poptGetNextOpt(optCon)) != -1) { ++ if (rc < 0) { ++ fprintf(stderr, "%s: %s\n", ++ poptBadOption(optCon, POPT_BADOPTION_NOALIAS), ++ poptStrerror(rc)); ++ exit(EXIT_FAILURE); ++ } ++ } + if (argc < 2 || poptGetNextOpt(optCon) == 0) { + poptPrintUsage(optCon, stderr, 0); + exit(EXIT_FAILURE); +-- +2.38.1 + diff --git a/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch b/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch new file mode 100644 index 0000000..ee12010 --- /dev/null +++ b/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch @@ -0,0 +1,40 @@ +From 2e61e5846f8301f85da9d30281538ea736d96fd0 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Tue, 7 Dec 2021 08:08:37 +0100 +Subject: [PATCH] Skip recorded symlinks in --setperms (RhBug:1900662) + +If a package contains a symlink in the buildroot which is declared as a +ghost or config file but is a regular file or directory on the system +where it's installed, a --setperms call will reset its permissions to +those of a symlink (777 on Linux), which almost certainly is not the +correct thing to do. + +To fix that, just skip files that were recorded as symlinks. + +This is a special case of a general issue in --setperms; since file +permission semantics may change depending on the file type, to stay on +the safe side, any (ghost or config) file whose type changes after +installation should probably be skipped. However, symlinks are the most +prominent case here, so let's just focus on that now and avoid adding +too much cleverness to a popt alias (this got us into trouble not too +long ago, see commits 38c2f6e and 0d83637). We may revisit this in the +eventual C implementation. +--- + rpmpopt.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rpmpopt.in b/rpmpopt.in +index 67fcabfb1..e130a5d05 100644 +--- a/rpmpopt.in ++++ b/rpmpopt.in +@@ -44,6 +44,7 @@ rpm alias --scripts --qf '\ + --POPTdesc=$"list install/erase scriptlets from package(s)" + + rpm alias --setperms -q --qf '[\[ -L %{FILENAMES:shescape} \] || \ ++ \[ -n %{FILELINKTOS:shescape} \] || \ + ( \[ $((%{FILEFLAGS} & 2#1001000)) != 0 \] && \[ ! -e %{FILENAMES:shescape} \] ) || \ + chmod %7{FILEMODES:octal} %{FILENAMES:shescape}\n]' \ + --pipe "grep -v \(none\) | grep '^. -L ' | sed 's/chmod .../chmod /' | sh" \ +-- +2.35.1 + diff --git a/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch b/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch new file mode 100644 index 0000000..7d4e85b --- /dev/null +++ b/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch @@ -0,0 +1,401 @@ +From 82c53e4b7f720012a391d8f6e5da9ee3c4f22bed Mon Sep 17 00:00:00 2001 +From: Demi Marie Obenour +Date: Thu, 6 May 2021 18:34:45 -0400 +Subject: [PATCH] Validate and require subkey binding signatures on PGP public + keys + +All subkeys must be followed by a binding signature by the primary key +as per the OpenPGP RFC, enforce the presence and validity in the parser. + +The implementation is as kludgey as they come to work around our +simple-minded parser structure without touching API, to maximise +backportability. Store all the raw packets internally as we decode them +to be able to access previous elements at will, needed to validate ordering +and access the actual data. Add testcases for manipulated keys whose +import previously would succeed. + +Combined with: +5ff86764b17f31535cb247543a90dd739076ec38 +b5e8bc74b2b05aa557f663fe227b94d2bc64fbd8 +9f03f42e2614a68f589f9db8fe76287146522c0c +b6dffb6dc5ffa2ddc389743f0507876cab341315 (mem-leak fix) +ae3d2d234ae47ff85229d3fce97a266fa1aa5a61 (use-after-free fix) + +Fixes CVE-2021-3521. +--- + rpmio/rpmpgp.c | 122 +++++++++++++++--- + sign/rpmgensig.c | 2 +- + tests/Makefile.am | 3 + + tests/data/keys/CVE-2021-3521-badbind.asc | 25 ++++ + .../data/keys/CVE-2021-3521-nosubsig-last.asc | 25 ++++ + tests/data/keys/CVE-2021-3521-nosubsig.asc | 37 ++++++ + tests/rpmsigdig.at | 28 ++++ + 7 files changed, 224 insertions(+), 18 deletions(-) + create mode 100644 tests/data/keys/CVE-2021-3521-badbind.asc + create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig-last.asc + create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig.asc + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index 46cd0f31a..bd4992ec7 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -511,7 +511,7 @@ pgpDigAlg pgpDigAlgFree(pgpDigAlg alg) + return NULL; + } + +-static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, ++static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, + const uint8_t *p, const uint8_t *h, size_t hlen, + pgpDigParams sigp) + { +@@ -524,10 +524,8 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype, + int mpil = pgpMpiLen(p); + if (p + mpil > pend) + break; +- if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) { +- if (sigalg->setmpi(sigalg, i, p)) +- break; +- } ++ if (sigalg->setmpi(sigalg, i, p)) ++ break; + p += mpil; + } + +@@ -600,7 +598,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + } + + p = ((uint8_t *)v) + sizeof(*v); +- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); ++ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); + } break; + case 4: + { pgpPktSigV4 v = (pgpPktSigV4)h; +@@ -658,7 +656,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + if (p > (h + hlen)) + return 1; + +- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); ++ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp); + } break; + default: + rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version); +@@ -999,36 +997,127 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype) + return algo; + } + ++static pgpDigParams pgpDigParamsNew(uint8_t tag) ++{ ++ pgpDigParams digp = xcalloc(1, sizeof(*digp)); ++ digp->tag = tag; ++ return digp; ++} ++ ++static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag) ++{ ++ int rc = -1; ++ if (pkt->tag == exptag) { ++ uint8_t head[] = { ++ 0x99, ++ (pkt->blen >> 8), ++ (pkt->blen ), ++ }; ++ ++ rpmDigestUpdate(hash, head, 3); ++ rpmDigestUpdate(hash, pkt->body, pkt->blen); ++ rc = 0; ++ } ++ return rc; ++} ++ ++static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig, ++ const struct pgpPkt *all, int i) ++{ ++ int rc = -1; ++ DIGEST_CTX hash = NULL; ++ ++ switch (selfsig->sigtype) { ++ case PGPSIGTYPE_SUBKEY_BINDING: ++ hash = rpmDigestInit(selfsig->hash_algo, 0); ++ if (hash) { ++ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY); ++ if (!rc) ++ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY); ++ } ++ break; ++ default: ++ /* ignore types we can't handle */ ++ rc = 0; ++ break; ++ } ++ ++ if (hash && rc == 0) ++ rc = pgpVerifySignature(key, selfsig, hash); ++ ++ rpmDigestFinal(hash, NULL, NULL, 0); ++ ++ return rc; ++} ++ + int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype, + pgpDigParams * ret) + { + const uint8_t *p = pkts; + const uint8_t *pend = pkts + pktlen; + pgpDigParams digp = NULL; +- struct pgpPkt pkt; ++ pgpDigParams selfsig = NULL; ++ int i = 0; ++ int alloced = 16; /* plenty for normal cases */ ++ struct pgpPkt *all = xmalloc(alloced * sizeof(*all)); + int rc = -1; /* assume failure */ ++ int expect = 0; ++ int prevtag = 0; + + while (p < pend) { +- if (decodePkt(p, (pend - p), &pkt)) ++ struct pgpPkt *pkt = &all[i]; ++ if (decodePkt(p, (pend - p), pkt)) + break; + + if (digp == NULL) { +- if (pkttype && pkt.tag != pkttype) { ++ if (pkttype && pkt->tag != pkttype) { + break; + } else { +- digp = xcalloc(1, sizeof(*digp)); +- digp->tag = pkt.tag; ++ digp = pgpDigParamsNew(pkt->tag); + } + } + +- if (pgpPrtPkt(&pkt, digp)) ++ if (expect) { ++ if (pkt->tag != expect) ++ break; ++ selfsig = pgpDigParamsNew(pkt->tag); ++ } ++ ++ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp)) + break; + +- p += (pkt.body - pkt.head) + pkt.blen; ++ if (selfsig) { ++ /* subkeys must be followed by binding signature */ ++ int xx = 1; /* assume failure */ ++ ++ if (!(prevtag == PGPTAG_PUBLIC_SUBKEY && ++ selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING)) ++ xx = pgpVerifySelf(digp, selfsig, all, i); ++ ++ selfsig = pgpDigParamsFree(selfsig); ++ if (xx) ++ break; ++ expect = 0; ++ } ++ ++ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY) ++ expect = PGPTAG_SIGNATURE; ++ prevtag = pkt->tag; ++ ++ i++; ++ p += (pkt->body - pkt->head) + pkt->blen; ++ if (pkttype == PGPTAG_SIGNATURE) ++ break; ++ ++ if (alloced <= i) { ++ alloced *= 2; ++ all = xrealloc(all, alloced * sizeof(*all)); ++ } + } + +- rc = (digp && (p == pend)) ? 0 : -1; ++ rc = (digp && (p == pend) && expect == 0) ? 0 : -1; + ++ free(all); + if (ret && rc == 0) { + *ret = digp; + } else { +@@ -1063,8 +1152,7 @@ int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen, + digps = xrealloc(digps, alloced * sizeof(*digps)); + } + +- digps[count] = xcalloc(1, sizeof(**digps)); +- digps[count]->tag = PGPTAG_PUBLIC_SUBKEY; ++ digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY); + /* Copy UID from main key to subkey */ + digps[count]->userid = xstrdup(mainkey->userid); + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 771d01098..b33fe996c 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -409,7 +409,7 @@ static int haveSignature(rpmtd sigtd, Header h) + pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2); + if (pgpDigParamsCmp(sig1, sig2) == 0) + rc = 1; +- pgpDigParamsFree(sig2); ++ sig2 = pgpDigParamsFree(sig2); + } + pgpDigParamsFree(sig1); + rpmtdFreeData(&oldtd); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 5f5207e56..309347262 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -87,6 +87,9 @@ EXTRA_DIST += data/SPECS/hello-config-buildid.spec + EXTRA_DIST += data/SPECS/hello-cd.spec + EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub + EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret ++EXTRA_DIST += data/keys/CVE-2021-3521-badbind.asc ++EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig.asc ++EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig-last.asc + EXTRA_DIST += data/macros.testfile + + # testsuite voodoo +diff --git a/tests/data/keys/CVE-2021-3521-badbind.asc b/tests/data/keys/CVE-2021-3521-badbind.asc +new file mode 100644 +index 000000000..aea00f9d7 +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-badbind.asc +@@ -0,0 +1,25 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= ++=WCfs ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/data/keys/CVE-2021-3521-nosubsig-last.asc b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc +new file mode 100644 +index 000000000..aea00f9d7 +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc +@@ -0,0 +1,25 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE= ++=WCfs ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/data/keys/CVE-2021-3521-nosubsig.asc b/tests/data/keys/CVE-2021-3521-nosubsig.asc +new file mode 100644 +index 000000000..3a2e7417f +--- /dev/null ++++ b/tests/data/keys/CVE-2021-3521-nosubsig.asc +@@ -0,0 +1,37 @@ ++-----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.17.90 (NSS-3) ++ ++mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g ++HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY ++91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8 ++eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas ++7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ ++1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl ++c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK ++CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf ++Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB ++BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr ++XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX ++fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq +++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN ++BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY ++zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz ++iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6 ++Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c ++KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m ++L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAG5AQ0EWOY5GAEIAKT68NmshdC4 ++VcRhOhlXBvZq23NtskkKoPvW+ZlMuxbRDG48pGBtxhjOngriVUGceEWsXww5Q7En ++uRBYglkxkW34ENym0Ji6tsPYfhbbG+dZWKIL4vMIzPOIwlPrXrm558vgkdMM/ELZ ++8WIz3KtzvYubKUk2Qz+96lPXbwnlC/SBFRpBseJC5LoOb/5ZGdR/HeLz1JXiacHF ++v9Nr3cZWqg5yJbDNZKfASdZgC85v3kkvhTtzknl//5wqdAMexbuwiIh2xyxbO+B/ ++qqzZFrVmu3sV2Tj5lLZ/9p1qAuEM7ULbixd/ld8yTmYvQ4bBlKv2bmzXtVfF+ymB ++Tm6BzyQEl/MAEQEAAYkBHwQYAQgACQUCWOY5GAIbDAAKCRBDRFkeGWTF/PANB/9j ++mifmj6z/EPe0PJFhrpISt9PjiUQCt0IPtiL5zKAkWjHePIzyi+0kCTBF6DDLFxos ++3vN4bWnVKT1kBhZAQlPqpJTg+m74JUYeDGCdNx9SK7oRllATqyu+5rncgxjWVPnQ ++zu/HRPlWJwcVFYEVXYL8xzfantwQTqefjmcRmBRdA2XJITK+hGWwAmrqAWx+q5xX ++Pa8wkNMxVzNS2rUKO9SoVuJ/wlUvfoShkJ/VJ5HDp3qzUqncADfdGN35TDzscngQ ++gHvnMwVBfYfSCABV1hNByoZcc/kxkrWMmsd/EnIyLd1Q1baKqc3cEDuC6E6/o4yJ ++E4XX4jtDmdZPreZALsiB ++=rRop ++-----END PGP PUBLIC KEY BLOCK----- ++ +diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at +index 09fcdd525..a74f400ae 100644 +--- a/tests/rpmsigdig.at ++++ b/tests/rpmsigdig.at +@@ -212,6 +212,34 @@ UNW2iqnN3BA7guhOv6OMiROF1+I7Q5nWT63mQC7IgQ== + []) + AT_CLEANUP + ++AT_SETUP([rpmkeys --import invalid keys]) ++AT_KEYWORDS([rpmkeys import]) ++RPMDB_INIT ++ ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-badbind.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-badbind.asc: key 1 import failed.] ++) ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-nosubsig.asc: key 1 import failed.] ++) ++ ++AT_CHECK([ ++runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig-last.asc ++], ++[1], ++[], ++[error: /data/keys/CVE-2021-3521-nosubsig-last.asc: key 1 import failed.] ++) ++AT_CLEANUP ++ + # ------------------------------ + # Test pre-built package verification + AT_SETUP([rpmkeys -K 1]) +-- +2.34.1 + diff --git a/rpm-4.16.1.3-rpm2archive-error-handling.patch b/rpm-4.16.1.3-rpm2archive-error-handling.patch new file mode 100644 index 0000000..4a8a6f5 --- /dev/null +++ b/rpm-4.16.1.3-rpm2archive-error-handling.patch @@ -0,0 +1,51 @@ +From f1634250587479d664b34b6de1a6546b2c2b9de5 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Mon, 18 Jan 2021 15:02:34 +0100 +Subject: [PATCH] rpm2archive: Add more error handling + +Cleanly error out if file can't be written instead of segfaulting + +Resolves: #1091 +--- + rpm2archive.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/rpm2archive.c b/rpm2archive.c +index 646f1663d..15c5da016 100644 +--- a/rpm2archive.c ++++ b/rpm2archive.c +@@ -119,9 +119,14 @@ static int process_package(rpmts ts, char * filename) + + /* create archive */ + a = archive_write_new(); +- archive_write_add_filter_gzip(a); +- archive_write_set_format_pax_restricted(a); +- ++ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { ++ fprintf(stderr, "Error: Could not create gzip output filter\n"); ++ exit(EXIT_FAILURE); ++ } ++ if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) { ++ fprintf(stderr, "Error: Format pax restricted is not supported\n"); ++ exit(EXIT_FAILURE); ++ } + if (!strcmp(filename, "-")) { + if (isatty(STDOUT_FILENO)) { + fprintf(stderr, "Error: refusing to output archive data to a terminal.\n"); +@@ -130,9 +135,11 @@ static int process_package(rpmts ts, char * filename) + archive_write_open_fd(a, STDOUT_FILENO); + } else { + char * outname = rstrscat(NULL, filename, ".tgz", NULL); +- archive_write_open_filename(a, outname); ++ if (archive_write_open_filename(a, outname) != ARCHIVE_OK) { ++ fprintf(stderr, "Error: Can't open output file: %s\n", outname); ++ exit(EXIT_FAILURE); ++ } + _free(outname); +- // XXX error handling + } + + entry = archive_entry_new(); +-- +2.38.1 + diff --git a/rpm-4.7.1-geode-i686.patch b/rpm-4.7.1-geode-i686.patch new file mode 100644 index 0000000..2e8692a --- /dev/null +++ b/rpm-4.7.1-geode-i686.patch @@ -0,0 +1,14 @@ +diff --git a/rpmrc.in b/rpmrc.in +index 4a6cca9..d62ddaf 100644 +--- a/rpmrc.in ++++ b/rpmrc.in +@@ -281,7 +281,7 @@ arch_compat: alphaev5: alpha + arch_compat: alpha: axp noarch + + arch_compat: athlon: i686 +-arch_compat: geode: i586 ++arch_compat: geode: i686 + arch_compat: pentium4: pentium3 + arch_compat: pentium3: i686 + arch_compat: i686: i586 + diff --git a/rpm-4.8.1-use-gpg2.patch b/rpm-4.8.1-use-gpg2.patch new file mode 100644 index 0000000..61ef55e --- /dev/null +++ b/rpm-4.8.1-use-gpg2.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.8.1/macros.in.gpg2 rpm-4.8.1/macros.in +--- rpm-4.8.0/macros.in.gpg2 2011-01-17 12:17:38.000000000 +0200 ++++ rpm-4.8.0/macros.in 2011-01-17 12:17:59.000000000 +0200 +@@ -40,7 +40,7 @@ + %__cp @__CP@ + %__cpio @__CPIO@ + %__file @__FILE@ +-%__gpg @__GPG@ ++%__gpg /usr/bin/gpg2 + %__grep @__GREP@ + %__gzip @__GZIP@ + %__id @__ID@ diff --git a/rpm-4.9.90-no-man-dirs.patch b/rpm-4.9.90-no-man-dirs.patch new file mode 100644 index 0000000..04f276a --- /dev/null +++ b/rpm-4.9.90-no-man-dirs.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs rpm-4.9.90.git11486/scripts/find-lang.sh +--- rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs 2012-03-07 11:31:10.000000000 +0200 ++++ rpm-4.9.90.git11486/scripts/find-lang.sh 2012-03-07 15:11:57.465801075 +0200 +@@ -181,7 +181,7 @@ s:%lang(C) :: + find "$TOP_DIR" -type d|sed ' + s:'"$TOP_DIR"':: + '"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+/\):: +-'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1*: ++'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1/*: + s:^\([^%].*\):: + s:%lang(C) :: + /^$/d' >> $MO_NAME diff --git a/rpm.spec b/rpm.spec new file mode 100644 index 0000000..8cebcb6 --- /dev/null +++ b/rpm.spec @@ -0,0 +1,2629 @@ +# build against xz? +%bcond_without xz +# just for giggles, option to build with internal Berkeley DB +%bcond_with int_bdb +# run internal testsuite? +%bcond_with check +# build with plugins? +%bcond_without plugins +# build with sanitizers? +%bcond_with sanitizer +# build with libarchive? (needed for rpm2archive) +%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_without ndb +# build with zstd support? +%bcond_without zstd +# build with lmdb support? +%bcond_with lmdb +# build with readonly sqlite support? +%bcond_without sqlite + +%if 0%{?rhel} > 7 +# Disable python2 build by default +%bcond_with python2 +%else +%bcond_without python2 +%endif + +%define rpmhome /usr/lib/rpm + +%global rpmver 4.14.3 +#global snapver rc2 +%global rel 26.4 + +%global srcver %{version}%{?snapver:-%{snapver}} +%global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} + +%define bdbname libdb +%define bdbver 5.3.15 +%define dbprefix db + +Summary: The RPM package management system +Name: rpm +Version: %{rpmver} +Release: %{?snapver:0.%{snapver}.}%{rel}%{?dist} +Group: System Environment/Base +Url: http://www.rpm.org/ +Source0: http://ftp.rpm.org/releases/%{srcdir}/%{name}-%{srcver}.tar.bz2 +%if %{with int_bdb} +Source1: db-%{bdbver}.tar.gz +%else +BuildRequires: libdb-devel +%endif + +# Disable autoconf config.site processing (#962837) +Patch1: rpm-4.11.x-siteconfig.patch +# Fedora specspo is setup differently than what rpm expects, considering +# this as Fedora-specific patch for now +Patch2: rpm-4.13.0-fedora-specspo.patch +# In current Fedora, man-pages pkg owns all the localized man directories +Patch3: rpm-4.9.90-no-man-dirs.patch +# gnupg2 comes installed by default, avoid need to drag in gnupg too +Patch4: rpm-4.8.1-use-gpg2.patch +# Temporary band-aid for rpm2cpio whining on payload size mismatch (#1142949) +Patch5: rpm-4.12.0-rpm2cpio-hack.patch + +# Downstream-only patch: +# Add envvar that will be present during RPM build +# - Part of a Fedora Change for F28: +# - "Avoid /usr/bin/python in RPM build" +# - https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build +Patch7: rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch + +# Patches already upstream: +Patch101: rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch +Patch102: 0001-Document-noverify-in-the-man-page-RhBug-1646458.patch +Patch104: 0001-Mark-elements-with-associated-problems-as-failed.patch +Patch108: 0001-Only-read-through-payload-on-verify-if-actually-need.patch +Patch111: 0003-Verify-packages-before-signing-RhBug-1646388.patch +Patch112: 0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch +Patch116: 0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch +Patch119: 0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch +Patch132: 0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch +Patch133: 0002-Handle-.debug_macro-in-debugedit.patch +Patch134: 0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch +Patch135: 0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch +Patch136: 0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch +Patch137: 0001-Fix-brp-strip-static-archive-parallelism.patch +Patch138: 0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch +Patch139: 0001-Make-check-buildroot-check-the-build-files-in-parall.patch +Patch140: 0001-Fix-resource-leaks-on-zstd-open-error-paths.patch +# XXX should be before 0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch +Patch141: 0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch +Patch142: rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch +Patch143: 0001-Work-around-buggy-signature-region-preventing-resign.patch +Patch144: 0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch +Patch145: 0001-Always-close-libelf-handle-1313.patch +Patch146: 0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch +Patch147: 0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch +Patch148: 0001-Add-limits-to-autopatch-macro.patch +Patch149: rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch +Patch150: rpm-4.14.3-add-fapolicyd-rpm-plugin.patch +Patch151: 0001-Unblock-signals-in-forked-scriptlets.patch +Patch152: rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch +Patch153: rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch +Patch154: rpm-4.14.3-more-careful-sig-hdr-copy.patch +Patch156: rpm-4.14.3-hdrblobInit-add-bounds-check.patch +Patch157: rpm-4.14.3-add-read-only-support-for-sqlite.patch +Patch158: rpm-4.14.3-imp-covscan-fixes.patch +Patch159: rpm-4.14.3-add-path-query-option.patch +Patch160: rpm-4.14.3-macroize-find-debuginfo-script-location.patch +Patch161: rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch +Patch162: rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch +Patch163: rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch +Patch164: rpm-4.14.3-fapolicyd-make-write-nonblocking.patch +Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch +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 + +# Python 3 string API sanity +Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch +Patch501: 0001-Return-NULL-string-as-None-from-utf8FromString.patch +# Make test-suite work with Python 3 +Patch503: 0001-Honor-PYTHON-from-configure-when-running-tests.patch +Patch504: 0002-Use-Python-3-compatible-exception-syntax-in-tests.patch +Patch505: 0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch +Patch506: 0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch +Patch507: 0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch +Patch508: rpm-4.14.3-python3.diff +Patch509: rpm-4-14.3-selinux-log-error.patch + +# These are not yet upstream +# Audit support +Patch800: rpm-4.14.2-audit-3.patch + +Patch906: rpm-4.7.1-geode-i686.patch +# Probably to be upstreamed in slightly different form +Patch907: rpm-4.13.90-ldflags.patch + +# Switch off the part of the brp-python-bytecompile script +# that utilizes python2 to bytecompile .py files within +# non-standard paths. +Patch1000: disable-python-extra.patch + +# Compile Python 3.6 stuff with /usr/libexec/platform-python instead of +# /usr/bin/python3.6 +Patch1001: compile-with-Platform-Python-binary-where-relevant.patch +# make unversioned %%__python an error unless explicitly overridden +Patch1002: rpm-4.14.2-unversioned-python.patch + +%if %{with zstd} +# multithreaded zstd compression +Patch1003: 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+ + +Requires: coreutils +%if %{without int_bdb} +# db recovery tools, rpmdb_util symlinks +Requires: %{_bindir}/%{dbprefix}_stat +%endif +Requires: popt%{_isa} >= 1.10.2.1 +Requires: curl + +%if %{without int_bdb} +BuildRequires: %{bdbname}-devel +%endif + +%if %{with check} +BuildRequires: fakechroot gnupg2 +%endif + +# XXX generally assumed to be installed but make it explicit as rpm +# is a bit special... +BuildRequires: redhat-rpm-config +BuildRequires: gcc make +BuildRequires: gawk +BuildRequires: elfutils-devel >= 0.112 +BuildRequires: elfutils-libelf-devel +BuildRequires: readline-devel zlib-devel +BuildRequires: openssl-devel +# The popt version here just documents an older known-good version +BuildRequires: popt-devel >= 1.10.2 +BuildRequires: file-devel +BuildRequires: gettext-devel +BuildRequires: ncurses-devel +BuildRequires: bzip2-devel >= 0.9.0c-2 +BuildRequires: lua-devel >= 5.1 +BuildRequires: libcap-devel +BuildRequires: libacl-devel +BuildRequires: audit-libs-devel +%if %{with sqlite} +BuildRequires: sqlite-devel +%endif +%if %{with xz} +BuildRequires: xz-devel >= 4.999.8 +%endif +%if %{with libarchive} +BuildRequires: libarchive-devel +%endif +%if %{with zstd} +BuildRequires: libzstd-devel +%endif +%if %{with lmdb} +BuildRequires: lmdb-devel +%endif +# Only required by sepdebugcrcfix patch +BuildRequires: binutils-devel +# Couple of patches change makefiles so, require for now... +BuildRequires: automake libtool + +%if %{with plugins} +BuildRequires: libselinux-devel +BuildRequires: dbus-devel +%endif + +%if %{with sanitizer} +BuildRequires: libasan +BuildRequires: libubsan +#BuildRequires: liblsan +#BuildRequires: libtsan +%global sanitizer_flags -fsanitize=address -fsanitize=undefined +%endif + +%if %{with libimaevm} +%if 0%{?fedora} >= 28 || 0%{?rhel} > 7 +%global imadevname ima-evm-utils-devel +%else +%global imadevname ima-evm-utils +%endif +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, +verifying, querying, and updating software packages. Each software +package consists of an archive of files along with information about +the package like its version, a description, etc. + +%package libs +Summary: Libraries for manipulating RPM packages +Group: Development/Libraries +License: GPLv2+ and LGPLv2+ with exceptions +Requires: %{name} = %{version}-%{release} +# librpm uses cap_compare, introduced sometimes between libcap 2.10 and 2.16. +# A manual require is needed, see #505596 +Requires: libcap%{_isa} >= 2.16 + +%description libs +This package contains the RPM shared libraries. + +%package build-libs +Summary: Libraries for building and signing RPM packages +Group: Development/Libraries +License: GPLv2+ and LGPLv2+ with exceptions +Requires: rpm-libs%{_isa} = %{version}-%{release} +Requires: %{_bindir}/gpg2 + +%description build-libs +This package contains the RPM shared libraries for building and signing +packages. + +%package devel +Summary: Development files for manipulating RPM packages +Group: Development/Libraries +License: GPLv2+ and LGPLv2+ with exceptions +Requires: %{name} = %{version}-%{release} +Requires: %{name}-libs%{_isa} = %{version}-%{release} +Requires: %{name}-build-libs%{_isa} = %{version}-%{release} +Requires: popt-devel%{_isa} + +%description devel +This package contains the RPM C library and header files. These +development files will simplify the process of writing programs that +manipulate RPM packages and databases. These files are intended to +simplify the process of creating graphical package managers or any +other tools that need an intimate knowledge of RPM packages in order +to function. + +This package should be installed if you want to develop programs that +will manipulate RPM packages and databases. + +%package build +Summary: Scripts and executable programs used to build packages +Group: Development/Tools +Requires: rpm = %{version}-%{release} +Requires: elfutils >= 0.128 binutils +Requires: findutils sed grep gawk diffutils file patch >= 2.5 +Requires: tar unzip gzip bzip2 cpio xz +%if %{with zstd} +Requires: zstd >= 1.3.8 +%endif +Requires: pkgconfig >= 1:0.24 +Requires: /usr/bin/gdb-add-index +# Technically rpmbuild doesn't require any external configuration, but +# creating distro-compatible packages does. To make the common case +# "just work" while allowing for alternatives, depend on a virtual +# provide, typically coming from redhat-rpm-config. +Requires: system-rpm-config + +%description build +The rpm-build package contains the scripts and executable programs +that are used to build packages using the RPM Package Manager. + +%package sign +Summary: Package signing support +Group: System Environment/Base +Requires: rpm-build-libs%{_isa} = %{version}-%{release} + +%description sign +This package contains support for digitally signing RPM packages. + +%if %{with python2} +%package -n python2-%{name} +Summary: Python 2 bindings for apps which will manipulate RPM packages +Group: Development/Libraries +BuildRequires: python2-devel +%{?python_provide:%python_provide python2-%{name}} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}-python = %{version}-%{release} +Obsoletes: %{name}-python < %{version}-%{release} + +%description -n python2-%{name} +The python2-rpm package contains a module that permits applications +written in the Python programming language to use the interface +supplied by RPM Package Manager libraries. + +This package should be installed if you want to develop Python 2 +programs that will manipulate RPM packages and databases. +%endif # with python2 + +%package -n python3-%{name} +Summary: Python 3 bindings for apps which will manipulate RPM packages +Group: Development/Libraries +BuildRequires: python3-devel +%{?python_provide:%python_provide python3-%{name}} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Provides: %{name}-python3 = %{version}-%{release} +Obsoletes: %{name}-python3 < %{version}-%{release} +# Lowest compatible DNF version (acts as a safeguard to protect DNF from +# breaking in case the user attempts to upgrade RPM separately). +# Version 4.2.7 added support for the new API output format introduced in +# rpm-4.14.2-10. +Conflicts: python3-dnf < 4.2.7 + +%description -n python3-%{name} +The python3-rpm package contains a module that permits applications +written in the Python programming language to use the interface +supplied by RPM Package Manager libraries. + +This package should be installed if you want to develop Python 3 +programs that will manipulate RPM packages and databases. + +%package apidocs +Summary: API documentation for RPM libraries +Group: Documentation +BuildArch: noarch + +%description apidocs +This package contains API documentation for developing applications +that will manipulate RPM packages and databases. + +%package cron +Summary: Create daily logs of installed packages. +Group: System Environment/Base +BuildArch: noarch +Requires: crontabs logrotate rpm = %{version}-%{release} + +%description cron +This package contains a cron job which creates daily logs of installed +packages on a system. + +%if %{with plugins} +%package plugin-selinux +Summary: Rpm plugin for SELinux functionality +Group: System Environment/Base +Requires: rpm-libs%{_isa} = %{version}-%{release} +Requires: selinux-policy-base + +%description plugin-selinux +%{summary} + +%package plugin-syslog +Summary: Rpm plugin for syslog functionality +Group: System Environment/Base +Requires: rpm-libs%{_isa} = %{version}-%{release} + +%description plugin-syslog +%{summary} + +%package plugin-systemd-inhibit +Summary: Rpm plugin for systemd inhibit functionality +Group: System Environment/Base +Requires: rpm-libs%{_isa} = %{version}-%{release} + +%description plugin-systemd-inhibit +This plugin blocks systemd from entering idle, sleep or shutdown while an rpm +transaction is running using the systemd-inhibit mechanism. + +%package plugin-ima +Summary: Rpm plugin ima file signatures +Group: System Environment/Base +Requires: rpm-libs%{_isa} = %{version}-%{release} + +%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 +Requires: rpm-libs%{_isa} = %{version}-%{release} + +%description plugin-prioreset +%{summary} + +Useful on legacy SysV init systems if you run rpm transactions with +nice/ionice priorities. Should not be used on systemd systems. + +%package plugin-fapolicyd +Summary: Rpm plugin for fapolicyd functionality +Requires: rpm-libs%{_isa} = %{version}-%{release} +Provides: fapolicyd-plugin +Obsoletes: fapolicyd-dnf-plugin + +%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 +%autosetup -n %{name}-%{srcver} %{?with_int_bdb:-a 1} -p1 + +%if %{with int_bdb} +ln -s db-%{bdbver} db +%endif + +%build +%if %{without int_bdb} +#CPPFLAGS=-I%{_includedir}/db%{bdbver} +#LDFLAGS=-L%{_libdir}/db%{bdbver} +%endif +CPPFLAGS="$CPPFLAGS -DLUA_COMPAT_APIINTCASTS" +CFLAGS="$RPM_OPT_FLAGS %{?sanitizer_flags} -DLUA_COMPAT_APIINTCASTS" +LDFLAGS="$LDFLAGS %{?__global_ldflags}" +export CPPFLAGS CFLAGS LDFLAGS + +autoreconf -i -f + +# Hardening hack taken from macro %%configure defined in redhat-rpm-config +for i in $(find . -name ltmain.sh) ; do + %{__sed} -i.backup -e 's~compiler_flags=$~compiler_flags="%{_hardened_ldflags}"~' $i +done; + +# Using configure macro has some unwanted side-effects on rpm platform +# setup, use the old-fashioned way for now only defining minimal paths. +./configure \ + --prefix=%{_usr} \ + --sysconfdir=%{_sysconfdir} \ + --localstatedir=%{_var} \ + --sharedstatedir=%{_var}/lib \ + --libdir=%{_libdir} \ + --build=%{_target_platform} \ + --host=%{_target_platform} \ + --with-vendor=redhat \ + %{!?with_int_bdb: --with-external-db} \ + %{!?with_plugins: --disable-plugins} \ + --with-lua \ + --with-selinux \ + --with-cap \ + --with-acl \ + %{?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} \ + --with-fapolicyd \ + --enable-python \ + --with-crypto=openssl \ + PYTHON=python3 + +make %{?_smp_mflags} + +pushd python +%if %{with python2} +%{__python2} setup.py build +%endif # with python2 +%{__python3} setup.py build +popd + +%install +rm -rf $RPM_BUILD_ROOT + +make DESTDIR="$RPM_BUILD_ROOT" install + +# We need to build with --enable-python for the self-test suite, but we +# actually package the bindings built with setup.py (#531543#c26) +pushd python +%if %{with python2} +%{__python2} setup.py install --skip-build --root $RPM_BUILD_ROOT +%endif # with python2 +%{__python3} setup.py install --skip-build --root $RPM_BUILD_ROOT +popd + + +# Save list of packages through cron +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/cron.daily +install -m 755 scripts/rpm.daily ${RPM_BUILD_ROOT}%{_sysconfdir}/cron.daily/rpm + +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d +install -m 644 scripts/rpm.log ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/rpm + +mkdir -p ${RPM_BUILD_ROOT}/usr/lib/tmpfiles.d +echo "r /var/lib/rpm/__db.*" > ${RPM_BUILD_ROOT}/usr/lib/tmpfiles.d/rpm.conf + +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm +mkdir -p $RPM_BUILD_ROOT%{rpmhome}/macros.d + +mkdir -p $RPM_BUILD_ROOT/var/lib/rpm +for dbi in \ + Basenames Conflictname Dirnames Group Installtid Name Obsoletename \ + Packages Providename Requirename Triggername Sha1header Sigmd5 \ + __db.001 __db.002 __db.003 __db.004 __db.005 __db.006 __db.007 \ + __db.008 __db.009 +do + touch $RPM_BUILD_ROOT/var/lib/rpm/$dbi +done + +# plant links to relevant db utils as rpmdb_foo for documention compatibility +%if %{without int_bdb} +for dbutil in dump load recover stat upgrade verify +do + ln -s ../../bin/%{dbprefix}_${dbutil} $RPM_BUILD_ROOT/%{rpmhome}/rpmdb_${dbutil} +done +%endif + +%find_lang %{name} + +find $RPM_BUILD_ROOT -name "*.la"|xargs rm -f + +# These live in perl-generators and python-rpm-generators now +rm -f $RPM_BUILD_ROOT/%{rpmhome}/{perldeps.pl,perl.*,pythond*} +rm -f $RPM_BUILD_ROOT/%{_fileattrsdir}/{perl*,python*} +# Axe unused cruft +rm -f $RPM_BUILD_ROOT/%{rpmhome}/{tcl.req,osgideps.pl} + +# Avoid unnecessary dependency on /usr/bin/python +chmod a-x $RPM_BUILD_ROOT/%{rpmhome}/python-macro-helper + +%if %{with check} +%check +make check || cat tests/rpmtests.log +%endif + +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig + +%post build-libs -p /sbin/ldconfig +%postun build-libs -p /sbin/ldconfig + +%files -f %{name}.lang +%license COPYING +%doc CREDITS doc/manual/[a-z]* + +/usr/lib/tmpfiles.d/rpm.conf +%dir %{_sysconfdir}/rpm + +%attr(0755, root, root) %dir /var/lib/rpm +%attr(0644, root, root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/rpm/* + +%{_bindir}/rpm +%if %{with libarchive} +%{_bindir}/rpm2archive +%endif +%{_bindir}/rpm2cpio +%{_bindir}/rpmdb +%{_bindir}/rpmkeys +%{_bindir}/rpmquery +%{_bindir}/rpmverify + +%{_mandir}/man8/rpm.8* +%{_mandir}/man8/rpmdb.8* +%{_mandir}/man8/rpmkeys.8* +%{_mandir}/man8/rpm2cpio.8* +%{_mandir}/man8/rpm-misc.8* + +# XXX this places translated manuals to wrong package wrt eg rpmbuild +%lang(fr) %{_mandir}/fr/man[18]/*.[18]* +%lang(ko) %{_mandir}/ko/man[18]/*.[18]* +%lang(ja) %{_mandir}/ja/man[18]/*.[18]* +%lang(pl) %{_mandir}/pl/man[18]/*.[18]* +%lang(ru) %{_mandir}/ru/man[18]/*.[18]* +%lang(sk) %{_mandir}/sk/man[18]/*.[18]* + +%attr(0755, root, root) %dir %{rpmhome} +%{rpmhome}/macros +%{rpmhome}/macros.d +%{rpmhome}/rpmpopt* +%{rpmhome}/rpmrc + +%{rpmhome}/rpmdb_* +%{rpmhome}/rpm.daily +%{rpmhome}/rpm.log +%{rpmhome}/rpm.supp +%{rpmhome}/rpm2cpio.sh +%{rpmhome}/tgpg +%{rpmhome}/python-macro-helper + +%{rpmhome}/platform + +%dir %{rpmhome}/fileattrs + +%files libs +%{_libdir}/librpmio.so.* +%{_libdir}/librpm.so.* +%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 + +%files plugin-selinux +%{_libdir}/rpm-plugins/selinux.so + +%files plugin-systemd-inhibit +%{_libdir}/rpm-plugins/systemd_inhibit.so +%{_mandir}/man8/rpm-plugin-systemd-inhibit.8* + +%files plugin-ima +%{_libdir}/rpm-plugins/ima.so + +%files plugin-prioreset +%{_libdir}/rpm-plugins/prioreset.so + +%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 +%{_libdir}/librpmbuild.so.* +%{_libdir}/librpmsign.so.* + +%files build +%{_bindir}/rpmbuild +%{_bindir}/gendiff +%{_bindir}/rpmspec + +%{_mandir}/man1/gendiff.1* +%{_mandir}/man8/rpmbuild.8* +%{_mandir}/man8/rpmdeps.8* +%{_mandir}/man8/rpmspec.8* + +%{rpmhome}/brp-* +%{rpmhome}/check-* +%{rpmhome}/debugedit +%{rpmhome}/sepdebugcrcfix +%{rpmhome}/find-debuginfo.sh +%{rpmhome}/find-lang.sh +%{rpmhome}/*provides* +%{rpmhome}/*requires* +%{rpmhome}/*deps* +%{rpmhome}/*.prov +%{rpmhome}/*.req +%{rpmhome}/config.* +%{rpmhome}/mkinstalldirs +%{rpmhome}/macros.p* +%{rpmhome}/fileattrs/* + +%files sign +%{_bindir}/rpmsign +%{_mandir}/man8/rpmsign.8* + +%if %{with python2} +%files -n python2-%{name} +%{python2_sitearch}/%{name}/ +%{python2_sitearch}/%{name}-%{version}*.egg-info +%endif # with python2 + +%files -n python3-%{name} +%{python3_sitearch}/%{name}/ +%{python3_sitearch}/%{name}-%{version}*.egg-info + +%files devel +%{_mandir}/man8/rpmgraph.8* +%{_bindir}/rpmgraph +%{_libdir}/librp*[a-z].so +%{_libdir}/pkgconfig/%{name}.pc +%{_includedir}/%{name}/ + +%files cron +%{_sysconfdir}/cron.daily/rpm +%config(noreplace) %{_sysconfdir}/logrotate.d/rpm + +%files apidocs +%license COPYING +%doc doc/librpm/html/* + +%changelog +* Wed Feb 21 2024 Davide Cavalca - 4.14.3-26.4 +- Convert to dist-git layout + +* Wed Sep 13 2023 Richard Phibel - 4.14.3-26.3 +- Fix IMA signature lengths assumed constant + +* Thu Aug 17 2023 Richard Phibel - 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 - 4.14.3-26.1 +- Merge upstream changes for Hyperscale + +* Mon Dec 19 2022 Florian Festi - 4.14.4-26 +- Add --nocompression to rpm2archive (#2129345) + +* Fri Dec 16 2022 Davide Cavalca - 4.14.3-25.1 +- Merge upstream changes for Hyperscale + +* Wed Nov 30 2022 Richard Phibel - 4.14.3-24.3 +- Add deny list support and workaround for RPM CoW + +* Tue Nov 29 2022 Aleksandr Kazakov - 4.14.3-24.2 +- Backport support for multi-threaded zstd compression + +* Sat Oct 29 2022 Richard Phibel - 4.14.3-24.1 +- Merge upstream changes for Hyperscale + +* Tue Sep 13 2022 Michal Domonkos - 4.14.3-24 +- Make write() nonblocking in fapolicyd plugin (#2110787) + +* Tue Jun 21 2022 Manu Bretelle - 4.14.3-23.2 +- Revert ndb by default (e62c0500274012ca77817a24814de38944c8abd4) + +* Mon May 16 2022 Manu Bretelle - 4.14.3-23.1 +- Rebuild for Hyperscale + +* Tue Apr 05 2022 Michal Domonkos - 4.14.3-23 +- Fix minor ABI regression in rpmcli.h (#1940895) + +* Fri Mar 25 2022 Manu Bretelle - 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 - 4.14.3-21.5 +- Backport GH#1040 to allow ndb DB query on read-only FS + +* Tue Feb 15 2022 Michal Domonkos - 4.14.3-22 +- Fix spurious %transfiletriggerpostun execution (#2023693) +- Skip recorded symlinks in --setperms (#1900662) + +* Mon Feb 14 2022 Manu Bretelle - 4.14.3-21.4 +- Use ndb by default +- Fix support for hardlinks + +* Tue Feb 08 2022 Manu Bretelle - 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 - 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 - 4.14.3-21.1 +- Rebuild for Hyperscale + +* Mon Jan 10 2022 Michal Domonkos - 4.14.3-21 +- Address covscan issues in binding sigs validation patch (#1958480) + +* Thu Dec 09 2021 Michal Domonkos - 4.14.3-20 +- Add --path query option (#1940895) +- Macroize find-debuginfo script location (#2019540) +- Validate and require subkey binding sigs on PGP pubkeys (#1958480) +- Fixes CVE-2021-3521 + +* Thu Nov 04 2021 Matthew Almond - 4.14.3-18.2 +- Include PR1779 + +* Wed Oct 06 2021 Michal Domonkos - 4.14.3-19 +- Unbreak in-tree kmod strip by reverting brp-strip fix (#1967291) + +* Thu Sep 16 2021 Matthew Almond - 4.14.3-18.1 +- Rebase c8s-sig-hyperscale-experimental branch onto c8s changes + +* Thu Aug 26 2021 Michal Domonkos - 4.14.3-18 +- Address important covscan issues (#1996665), vol. 2 + +* Mon Aug 23 2021 Michal Domonkos - 4.14.3-17 +- Address important covscan issues (#1996665) + +* Thu Aug 19 2021 Michal Domonkos - 4.14.3-16 +- Add support for read-only sqlite rpmdb (#1938928) +- Drop compat .decode() method from returned Py3 strings (#1840142) + +* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.4 +- Add measure plugin + +* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.3 +- Move rpm2extents to plugin package + +* Tue Aug 03 2021 Matthew Almond - 4.14.3-15.2 +- Added fsverity backport + +* Sat Jul 24 2021 Neal Gompa - 4.14.3-15.1 +- Rebuild for Hyperscale + +* Thu Jul 15 2021 Michal Domonkos - 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 - 4.14.3-14.1 +- Rebuild for Hyperscale + +* Thu May 27 2021 Michal Domonkos - 4.14.3-14 +- Be more careful about copying data from signature header (#1958477) +- Fixes CVE-2021-20271 + +* Thu Mar 18 2021 Matthew Almond - 4.14.3-13.1 +- PR1381 (Fix Fseek for offset > 2GiB) +- PR1470 (CoW) + +* Fri Feb 12 2021 Michal Domonkos - 4.14.3-13 +- Fix minor issues found by COVSCAN in fapolicyd plugin +- Actually honor libarchive bcond at configure time (#1902887) + +* Tue Feb 09 2021 Michal Domonkos - 4.14.3-12 +- Bump up the limit of signature header to 64MB (#1918777) +- Add fapolicyd plugin (#1923167) +- Unblock signals in forked scriptlets (#1913765) +- Fix ambiguous diagnostics output on file triggers (#1883338) +- Ensure ELF files get stripped when debuginfo is disabled (#1634084) + +* Sun Jan 10 2021 Michal Domonkos - 4.14.3-10 +- Rebuild for libimaevm soname bump, now for real (#1896046) + +* Thu Jan 07 2021 Florian Festi - 4.14.3-8 +- Add limits to autopatch macro (#1834931) + +* Thu Dec 03 2020 Michal Domonkos - 4.14.3-6 +- Rebuild for libimaevm soname bump (#1896046) + +* Fri Oct 30 2020 Florian Festi - 4.14.3-5 +- Don't error out when replacing an invalid signature (#1874062) +- Raise an expection when erasing a package fails in Python (#1872623) +- Fix builds on NFS filesystems (#1840728) + +* Fri Jun 26 2020 Michal Domonkos - 4.14.3-4 +- Fix hang when signing with expired key (#1746353) + +* Wed May 13 2020 Panu Matilainen - 4.14.3-3 +- Fix configure option for --with ndb (#1817010, Matthew Almond) + +* Mon May 11 2020 Florian Festi - 4.14.3-2 +- Re-add selinux fix dropped in rebase + +* Mon May 4 2020 Florian Festi - 4.14.3-1 +- Rebase to 4.14.3 (#1765187) + +* Fri Feb 21 2020 Michal Domonkos - 4.14.2-37 +- Add API safeguard for DNF by using Conflicts: (#1790400) + +* Thu Jan 09 2020 Panu Matilainen - 4.14.2-36 +- Revert DBUS shutdown patch, it causes regressions (#1783346) + +* Wed Nov 27 2019 Panu Matilainen - 4.14.2-35 +- Revert mistakenly included patch from caret backport + +* Thu Nov 21 2019 Panu Matilainen - 4.14.2-34 +- Backport caret version operator (#1654901) + +* Thu Nov 21 2019 Panu Matilainen - 4.14.2-33 +- Backport _smp_build_ncpus macro for #1691824 and #1704354 + +* Thu Nov 21 2019 Panu Matilainen - 4.14.2-32 +- Fix resource leaks on zstd open error + +* Mon Nov 18 2019 Florian Festi - 4.14.2-31 +- Parallelize /usr/lib/rpm/brp-strip-static-archive (#1691824) +- Parallelize /usr/lib/rpm/check-buildroot (#1704354) + +* Tue Nov 12 2019 Panu Matilainen - 4.14.2-30 +- Handle gcc -g3 debug level output in debuginfo (#1630926) + +* Thu Oct 24 2019 Panu Matilainen - 4.14.2-29 +- Use Python 3 for the test suite and make it pass (#1724138) + +* Thu Oct 24 2019 Panu Matilainen - 4.14.2-28 +- Accept PGP public keys with missing EOL (#1733971) + +* Thu Oct 24 2019 Panu Matilainen - 4.14.2-27 +- Support generating build-id's from compressed ELF files (#1650074) +- Compress annobit notes in find-debuginfo (#1719837) + +* Wed Oct 16 2019 Panu Matilainen - 4.14.2-26 +- Re-enable support for zstd (#1715799) + +* Wed Aug 07 2019 Florian Festi - 4.14.2-25 +- Fix memory leak in verify code (#1714657) + +* Wed Jul 31 2019 Florian Festi - 4.14.2-24 +- Fix off-by-one in hdrblobGet() breaking large packages (#1722921) + +* Thu Jul 25 2019 Florian Festi - 4.14.2-23 +- Use --dpbath only with full path (#1696408) +- Fix memory leaks (#1714657) +- Remove capabilities instead of setting empty caps via. --setcaps (#1700920) +- Fix bash warning from solution for #1689810 + +* Thu Jul 18 2019 Florian Festi - 4.14.2-22 +- Add information about FIPS mode to rpmsign man page (#1726678) + +* Wed Jul 03 2019 Florian Festi - 4.14.2-21 +- Fix bash warning from solution for #1689810 + +* Thu Jun 06 2019 Panu Matilainen - 4.14.2-20 +- Fix packages getting removed on failed update via dnf (#1710346) + +* Tue Jun 04 2019 Panu Matilainen - 4.14.2-19 +- Fix rare segfault in fingerprinting symlink round (#1660232) + +* Tue Jun 04 2019 Panu Matilainen - 4.14.2-18 +- Make use of unversioned %%__python macro an error (#1645663) + +* Wed Apr 24 2019 Florian Festi - 4.14.2-17 +- Add flag to use strip -g instead of full strip on DSOs (#1689810) + +* Wed Apr 24 2019 Florian Festi - 4.14.2-16 +- Sort list of hard linked files in find-debuginfo.sh (#1421272) +- Correct rpm -ql exit value when optional -p is omitted (#1680610) +- Show list of files only once when use rpm -ql and multiple rpm files (#1689898) + +* Fri Apr 12 2019 Panu Matilainen - 4.14.2-15 +- Fix %_minimize_writes stripping suid/sgid bits and capabilities (#1690876) + +* Thu Apr 11 2019 Panu Matilainen - 4.14.2-14 +- Verify packages before signing (#1646388) +- Make rpmsign exist values more consistent with our other tools + +* Thu Apr 11 2019 Panu Matilainen - 4.14.2-13 +- Report meaningful errors from SElinux plugin (#1679028) + +* Thu Apr 11 2019 Panu Matilainen - 4.14.2-12 +- Fix an ancient GIL locking bug, required for the .decode() trick + +* Thu Apr 11 2019 Panu Matilainen - 4.14.2-11 +- Revised patch for Py3 string data as surrogate-escaped utf-8 (#1631292) +- Add a .decode() method to returned Py3 strings for compatibility + +* Wed Mar 06 2019 Panu Matilainen - 4.14.2-10 +- Return all string data as surrogate-escaped utf-8 in Python 3 (#1631292) + +* Thu Dec 20 2018 Panu Matilainen - 4.14.2-9 +- Mark elements with associated problems as failed (needed for audit) + +* Fri Dec 14 2018 Panu Matilainen - 4.14.2-8 +- Differentiate between install and update in audit log + +* Mon Dec 03 2018 Panu Matilainen - 4.14.2-7 +- Move python-macro-helper to main package where the macros are (#1651926) +- Document --noverify in the man page (#1646458) +- Handle unsupported digests the same as disabled ones (#1652529) + +* Mon Dec 03 2018 Panu Matilainen - 4.14.2-6 +- Fix our SElinux dependencies (#1651926) + +* Fri Nov 30 2018 Florian Festi - 4.14.2-5 +- Add new tag MODULARITYLABEL (#1650287) + +* Mon Oct 22 2018 Panu Matilainen - 4.14.2-4 +- Fix nasty --setperms/--setugids regression introduced in 4.14.2 (#1640470) + +* Thu Sep 13 2018 Panu Matilainen - 4.14.2-3 +- Oops, op= was supposed to be first in the audit message (#1607612) + +* Thu Sep 13 2018 Panu Matilainen - 4.14.2-2 +- Revised audit patch, log removals and verify failures too (#1607612) + +* Mon Sep 03 2018 Panu Matilainen - 4.14.2-1 +- Buildrequire audit-libs-devel to actually enable the feature (#1607612) +- Update to rpm 4.14.2 final (http://rpm.org/wiki/Releases/4.14.2) + +* Fri Aug 10 2018 Panu Matilainen - 4.14.2-0.rc2.1 +- Update to rpm 4.14.2-rc2 +- Fixes a regression in rpmlog error handling (#1597274) +- Fixes several resource leaks found by covscan (#1602681) +- Fixes DISTTAG not getting copied to source rpms (#1596193) + +* Tue Aug 07 2018 Florian Festi - 4.14.2-0.rc1.5 +- Wrap zstd Requires in build condition + +* Thu Aug 02 2018 Florian Festi - 4.14.2-0.rc1.4 +- Add log entries to audit system (#1607612) + +* Wed Aug 01 2018 Panu Matilainen - 4.14.2-0.rc1.3 +- Disable test-suite by default to avoid fakechroot dependency (#1601024) + +* Mon Jul 30 2018 Florian Festi - 4.14.2-0.rc1.2 +- Build without zstd support + +* Wed Jul 18 2018 Florian Festi - 4.14.2-0.rc1.1 +- Update to rpm 4.14.2-rc1 + +* Tue Jul 03 2018 Tomas Orsava - 4.14.1-11 +- Compile Python 3.6 stuff with /usr/libexec/platform-python instead of + /usr/bin/python3.6 + +* Fri Jun 29 2018 Charalampos Stratakis - 4.14.1-10.1 +- Bump release for rebuild + +* Tue Jun 26 2018 Charalampos Stratakis - 4.14.1-9 +- Disable python2 bytecompilation + +* Fri Jun 22 2018 Charalampos Stratakis - 4.14.1-8 +- Conditionalize the python2 subpackage + +* Mon Feb 19 2018 Panu Matilainen - 4.14.1-7 +- Explicitly BuildRequire gcc and make + +* Fri Feb 09 2018 Igor Gnatenko - 4.14.1-6.1 +- Escape macros in %%changelog + +* Wed Jan 31 2018 Panu Matilainen - 4.14.1-6 +- Avoid unnecessary macro helper dependency on /usr/bin/python (#1538657) +- Fix release of previous changelog entry + +* Tue Jan 30 2018 Tomas Orsava - 4.14.1-5 +- Add envvar that will be present during RPM build, + Part of a Fedora Change for F28: "Avoid /usr/bin/python in RPM build" + https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build + +* Tue Jan 30 2018 Petr Viktorin - 4.14.1-4 +- Skip automatic Python byte-compilation if *.py files are not present + +* Thu Jan 25 2018 Florian Weimer - 4.14.1-3 +- Rebuild to work around gcc bug leading to librpm miscompilation (#1538648) + +* Thu Jan 18 2018 Panu Matilainen - 4.14.1-2 +- Avoid nuking the new python-macro-helper along with dep generators (#1535692) + +* Tue Jan 16 2018 Panu Matilainen - 4.14.1-1 +- Rebase to rpm 4.14.1 (http://rpm.org/wiki/Releases/4.14.1) + +* Tue Nov 07 2017 Igor Gnatenko - 4.14.0-5 +- Fix typo in Obsoletes + +* Mon Nov 06 2017 Igor Gnatenko - 4.14.0-4 +- Remove platform-python bits + +* Thu Oct 26 2017 Panu Matilainen - 4.14.0-3 +- Move selinux plugin dependency to selinux-policy in Fedora >= 28 (#1493267) + +* Thu Oct 12 2017 Panu Matilainen - 4.14.0-2 +- Dump out test-suite log in case of failures again +- Don't assume per-user groups in test-suite + +* Thu Oct 12 2017 Panu Matilainen - 4.14.0-1 +- Rebase to rpm 4.14.0 final (http://rpm.org/wiki/Releases/4.14.0) + +* Tue Oct 10 2017 Troy Dawson - 4.14.0-0.rc2.6 +- Cleanup spec file conditionals + +* Tue Oct 03 2017 Panu Matilainen - 4.14.0-0.rc2.5 +- Add build conditionals for zstd and lmdb support +- Enable zstd support + +* Tue Oct 03 2017 Panu Matilainen - 4.14.0-0.rc2.4 +- Spec cleanups + +* Fri Sep 29 2017 Panu Matilainen - 4.14.0-0.rc2.3 +- BuildRequire gnupg2 for the testsuite + +* Fri Sep 29 2017 Panu Matilainen - 4.14.0-0.rc2.2 +- ima-evm-utils only has a -devel package in fedora >= 28 + +* Thu Sep 28 2017 Panu Matilainen - 4.14.0-0.rc2.1 +- Rebase to rpm 4.14.0-rc2 (http://rpm.org/wiki/Releases/4.14.0) + +* Mon Sep 18 2017 Panu Matilainen - 4.14.0-0.rc1.3 +- Fix Ftell() past 2GB on 32bit architectures (#1492587) + +* Thu Sep 07 2017 Panu Matilainen - 4.14.0-0.rc1.2 +- Actually honor with/without libimaevm option +- ima-evm-utils-devel >= 1.0 is required for rpm >= 4.14.0 + +* Wed Sep 06 2017 Panu Matilainen - 4.14.0-0.rc1.1 +- Rebase to rpm 4.14.0-rc1 (http://rpm.org/wiki/Releases/4.14.0) +- Re-enable SHA256 header digest generation (see #1480407) + +* Mon Aug 28 2017 Panu Matilainen - 4.13.90-0.git14000.8 +- Band-aid for DB_VERSION_MISMATCH errors on glibc updates (#1465809) + +* Thu Aug 24 2017 Panu Matilainen - 4.13.90-0.git14000.7 +- Remove ugly kludges from posttrans script, BDB handles this now + +* Fri Aug 18 2017 Panu Matilainen - 4.13.90-0.git14000.6 +- Silence harmless but bogus error message on noarch packages (#1482144) + +* Thu Aug 17 2017 Miro Hrončok - 4.13.90-0.git14002.5 +- Build with platform_python + +* Mon Aug 14 2017 Miro Hrončok - 4.13.90-0.git14000.4 +- Add platform-python bytecompilation patch: platform-python-bytecompile.patch +- Add platform python deps generator patch: platform-python-abi.patch +- Add a platform-python subpackage and remove system python related declarations +- Build rpm without platform_python for bytecompilation + (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack) + +* Mon Aug 14 2017 Panu Matilainen - 4.13.90-0.git14000.3 +- Disable macro argument quoting as a band-aid to #1481025 + +* Fri Aug 11 2017 Panu Matilainen - 4.13.90-0.git14000.2 +- Disable SHA256 header-only digest generation temporarily (#1480407) + +* Thu Aug 10 2017 Panu Matilainen - 4.13.90-0.git14000.1 +- Rebase to rpm 4.13.90 aka 4.14.0-alpha (#1474836) + +* Mon Jul 31 2017 Igor Gnatenko - 4.13.0.1-41 +- Move _debuginfo_subpackages and _debugsource_packages to redhat-rpm-config + +* Sat Jul 29 2017 Igor Gnatenko - 4.13.0.1-40 +- Update latest patches from merged versions + +* Fri Jul 28 2017 Igor Gnatenko - 4.13.0.1-39 +- Backport fixes for debuginfo subpackages + +* Wed Jul 26 2017 Igor Gnatenko - 4.13.0.1-38 +- Backport trivial fix for debugsourcefiles.list ending up in random dir + +* Tue Jul 25 2017 Igor Gnatenko - 4.13.0.1-37 +- Enable debugsource and debuginfo subpackages by default + +* Mon Jul 24 2017 Igor Gnatenko - 4.13.0.1-36 +- Make sure that test results are not ignored + +* Sun Jul 23 2017 Mark Wielaard - 4.13.0.1-35 +- Fix rpmfd_write on big endian arches. + +* Fri Jul 21 2017 Mark Wielaard - 4.13.0.1-34 +- find-debuginfo.sh: Remove non-allocated NOBITS sections from minisymtab. + +* Thu Jul 20 2017 Igor Gnatenko - 4.13.0.1-33 +- Remove strict requirement on python libs + +* Tue Jul 18 2017 Mark Wielaard - 4.13.0.1-32 +- Add find-debuginfo.sh: Add --keep-section and --remove-section (#1465997) + +* Wed Jul 12 2017 Igor Gnatenko - 4.13.0.1-31 +- Add automatic provides debuginfo(build-id) = ... into debuginfo subpackages + +* Fri Jul 07 2017 Igor Gnatenko - 4.13.0.1-30 +- Fix brokeness when using %%filter_setup (RHBZ #1468476) + +* Tue Jul 04 2017 Mark Wielaard - 4.13.0.1-29 +- Track patches using https://pagure.io/rpm-fedora +- Use file list to explicitly set mode for build-id dirs/files + (#1452893, #1458839) + +* Thu Jun 29 2017 Mark Wielaard - 4.13.0.1-28 +- Add debugedit-prefix.patch. +- Add find-debuginfo-filter-built-ins.patch. +- Add find-debuginfo-dwz-multi.patch. +- Add find-debuginfo-and-macro-docs.patch. + +* Wed Jun 28 2017 Mark Wielaard - 4.13.0.1-27 +- Add find-debuginfo-split-traversal-and-extraction-fix.patch (#1465170) + +* Wed Jun 28 2017 Igor Gnatenko - 4.13.0.1-26 +- Backport patches for rich dependencies from dependency generators + +* Sun Jun 25 2017 Mark Wielaard - 4.13.0.1-25 +- Add support for debugsource and debuginfo subpackages + - find-debuginfo-untangle-unique-build-options.patch + - debugsrc-and-sub-debuginfo-packages.patch + +* Fri Jun 23 2017 Mark Wielaard - 4.13.0.1-24 +- Backport parallel debuginfo processing. + +* Tue May 30 2017 Mark Wielaard - 4.13.0.1-23 +- Fix resetting attr flags in buildid creation (#1449732) + +* Tue May 23 2017 Panu Matilainen - 4.13.0.1-22 +- Python dependency generators live in python-rpm-generators now (#1444925) + +* Tue May 23 2017 Panu Matilainen - 4.13.0.1-21 +- Fix rpmsign python module import failing (#1393659) + +* Tue Apr 25 2017 Mark Wielaard - 4.13.0.1-20 +- Fix rpmbuild world writable empty (tmp) dirs in debuginfo (#641022) + +* Sat Apr 15 2017 Mark Wielaard - 4.13.0.1-19 +- Minisymtab should only be added for executables or shared libraries. +- Add find-debuginfo.sh -n (debugedit --no-recompute-build-id) option. + +* Fri Mar 31 2017 Panu Matilainen - 4.13.0.1-18 +- gpg path must not depend on %%_prefix and such (#1437726) + +* Mon Mar 27 2017 Panu Matilainen - 4.13.0.1-17 +- Work around missing python[23] during build dependency parse +- Include ISA in the new python library version dependencies too + +* Mon Mar 27 2017 Panu Matilainen - 4.13.0.1-16 +- Band-aid for python library versioning inadequacies (#1435135) + +* Mon Mar 27 2017 Mark Wielaard - 4.13.0.1-15 +- Unbreak short-circuited binary builds (#1434235). + +* Tue Mar 21 2017 Mark Wielaard - 4.13.0.1-14 +- Add fix for off by one adding DW_FORM_string replacement (#1434347). + +* Mon Mar 20 2017 Mark Wielaard - 4.13.0.1-13 +- Add tests fix for sed file build-id regexp matching. +- Add fix for build-ids in non-executable ELF files (#1433837). + +* Fri Mar 17 2017 Mark Wielaard - 4.13.0.1-12 +- Fix reading and updating (cross-endian) build-id information. + +* Fri Mar 17 2017 Mark Wielaard - 4.13.0.1-11 +- Do not process build-ids for noarch packages. + +* Thu Mar 16 2017 Mark Wielaard - 4.13.0.1-10 +- Add fix for debugedit replace debug_line files. + +* Thu Mar 16 2017 Igor Gnatenko - 4.13.0.1-9 +- Switch to OpenSSL (RHBZ #1390624) + +* Wed Mar 15 2017 Mark Wielaard - 4.13.0.1-8 +- Add fix to reset buildid file attributes (#1432372) + +* Fri Mar 10 2017 Mark Wielaard - 4.13.0.1-7 +- Add fixup fix for build-id warnings on object files (#1430587) + +* Thu Mar 09 2017 Mark Wielaard - 4.13.0.1-6 +- Add fix for missing_build_ids_terminate_build without __debug_package. + +* Thu Mar 09 2017 Mark Wielaard - 4.13.0.1-5 +- Add fix for build-id warnings on object files (#1430587) + +* Wed Mar 08 2017 Panu Matilainen - 4.13.0.1-4 +- Mark Wielaard's backports for debuginfo parallel installation etc (#1427970) + +* Fri Feb 24 2017 Pavlina Moravcova Varekova - 4.13.0.1-3 +- Fix number of references on spec_Type (#1426578) + +* Thu Feb 16 2017 Tomas Orsava - 4.13.0.1-2 +- Fix handling of Python wheels by pythondistdeps.py --provides (#1421776) + +* Thu Feb 16 2017 Panu Matilainen - 4.13.0.1-1 +- Update to 4.13.0.1 ((http://rpm.org/wiki/Releases/4.13.0) + +* Tue Feb 14 2017 Florian Festi - 4.13.0-12 +- Fix Python byte compilation for Python3 only packages (#1411588) + +* Sat Feb 11 2017 Fedora Release Engineering - 4.13.0-11.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Jan 23 2017 Panu Matilainen - 4.13.0-11 +- Fix malformed packages being generated around 4GB boundary (#1405570) +- Resurrect debuginfo GDB index generation (#1410907) + +* Fri Jan 06 2017 Igor Gnatenko - 4.13.0-10 +- Add Requires: python-setuptools for rpm-build (RHBZ #1410631) + +* Wed Dec 21 2016 Peter Robinson 4.13.0-9 +- Rebuild for Python 3.6 + +* Sun Dec 18 2016 Igor Gnatenko - 4.13.0-8 +- Switch rpm-build to system-python (RHBZ #1405483) + +* Fri Dec 09 2016 Charalampos Stratakis - 4.13.0-7 +- Rebuild for Python 3.6 + +* Sat Dec 03 2016 Igor Gnatenko - 4.13.0-6 +- Fix arch-dependent requires in subpackages (RHBZ #1398591) + +* Fri Nov 25 2016 Igor Gnatenko - 4.13.0-5 +- Fix arch-dependent requires in subpackages (RHBZ #1398591) + +* Fri Nov 11 2016 Panu Matilainen - 4.13.0-4 +- Expand python subpackage obsoletion range (related: #1394125) + +* Mon Nov 07 2016 Panu Matilainen - 4.13.0-3 +- Fix invalid memory access on %%transfiletriggerpostun (#1284645) + +* Fri Nov 04 2016 Thierry Vignaud - 4.13.0-2 +- Fix package name references in python sub-packages to match reality +- Re-enable test-suite now that it works again + +* Thu Nov 03 2016 Panu Matilainen - 4.13.0-1 +- Rebase to rpm 4.13.0 final (http://rpm.org/wiki/Releases/4.13.0) + +* Wed Nov 02 2016 Panu Matilainen - 4.13.0-0.rc2.2 +- Fix harmless unused variable warning from fedora-specspo patch + +* Thu Oct 20 2016 Panu Matilainen - 4.13.0-0.rc2.1 +- Rebase to rpm 4.13.0-rc2 + +* Fri Sep 23 2016 Richard W.M. Jones - 4.13.0-0.rc1.47 +- Backport two upstream patches which add riscv64 architecture support. + +* Wed Aug 24 2016 Igor Gnatenko - 4.13.0-0.rc1.46 +- Backport patch for missing import in Python dependency generator + +* Wed Aug 24 2016 Kalev Lember - 4.13.0-0.rc1.45 +- Fix -python2 and -python3 subpackage obsoleting from .42 + +* Tue Aug 23 2016 Igor Gnatenko - 4.13.0-0.rc1.44 +- Use %%python_provide for python3 subpackage + +* Mon Aug 22 2016 Igor Gnatenko - 4.13.0-0.rc1.43 +- Backport fixes to ignore .egg-link files in Python dependency generator + +* Fri Aug 12 2016 Florian Festi - 4.13.0-0.rc1.42 +- Enable --majorver-provides in Python dependency generator + +* Tue Aug 09 2016 Igor Gnatenko - 4.13.0-0.rc1.41 +- Add %%{?system_python_abi} +- rpm-python -> python2-rpm && rpm-python3 -> python3-rpm with providing old names +- Fixes and cleanups + +* Tue Jul 19 2016 Fedora Release Engineering - 4.13.0-0.rc1.40.1 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Mon Jul 18 2016 Petr Pisar - 4.13.0-0.rc1.40 +- Drop rpm-build's dependency on perl-generators (bug #1158860) + +* Fri Jul 15 2016 Florian Festi - 4.13.0-0.rc1.39 +- Pass relevant files to new Python dependency generator + +* Mon Jun 13 2016 Florian Festi - 4.13.0-0.rc1.38 +- Add new Python dependency generator (provides only for now) (#1340885) + +* Thu Jun 02 2016 Florian Festi - 4.13.0-0.rc1.37 +- Add support for _buildhost macro (#1309367) + +* Mon May 23 2016 Lubos Kardos 4.13.0-0.rc1.36 +- Fix signing with non-ASCII uid keys (#1243963) + +* Thu May 19 2016 Lubos Kardos 4.13.0-0.rc1.35 +- Use armv7hl isa for all armhfp (armv7h*l) arches (#1326871) + +* Tue May 17 2016 Lubos Kardos 4.13.0-0.rc1.34 +- Filter unversioned deps if corresponding versioned deps exist (#678605) + +* Mon Apr 25 2016 Lubos Kardos 4.13.0-0.rc1.33 +- Fix sigsegv in stringFormat() (#1316903) +- Fix reading rpmtd behind its size in formatValue() (#1316896) + +* Fri Apr 15 2016 Lubos Kardos 4.13.0-0.rc1.32 +- escape %% chars in previous changelog record + +* Fri Apr 15 2016 Lubos Kardos 4.13.0-0.rc1.31 +- Enable --no-backup-if-mismatch by default in %%patch macro (#884755) +- Add %%{_default_patch_flags} to %%__patch which is used in %%autosetup +- Use fuzz settings for %%autopatch/%%autosetup + +* Thu Apr 14 2016 Lubos Kardos 4.13.0-0-rc1.30 +- Make creating index records consistent for rich and rich-weak deps (#1325982) + +* Tue Apr 12 2016 Lubos Kardos 4.13.0-0.rc1.29 +- Add RPMCALLBACK_ELEM_PROGRESS callback type (needed by dnf) + +* Wed Apr 06 2016 Lubos Kardos 4.13.0-0.rc1.28 +- Fix non-working combination of %%lang and %%doc directive (#1254483) + +* Thu Mar 10 2016 Lubos Kardos 4.13.0-0.rc1.27 +- Add posix.redirect2null (#1287918) + +* Fri Feb 26 2016 Florian Festi - 4.13.0-0.rc1.26 +- Fix ExclusiveArch/ExcludeArch for noarch packages (#1298668) + +* Thu Feb 25 2016 Florian Festi - 4.13.0-0.rc1.25 +- Fix dependencies for RemovePathPostfixes (#1306559) + +* Fri Feb 19 2016 Florian Festi - 4.13.0-0.rc1.24 +- Also block idle and sleep in the systemd-inhibit plugin (#1297984) +- Add support for MIPS release 6 +- Add mips32 mips64 mipsel and mipseb macros (#1285116) + +* Tue Feb 02 2016 Lubos Kardos - 4.13.0-0.rc1.23 +- Remove size limit when expanding macros (#1301677) + +* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.22 +- Harden rpm package again, previous attempt had to be reverted (#1289734) + +* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.21 +- Remove setting %%_gnu macro explictly, no more needed (#1303265) + +* Mon Feb 01 2016 Lubos Kardos - 4.13.0-0.rc1.20 +- Revert using %%configure, it causes problems +- Temporary set %%_gnu macro explictly, just for one build (#1303265) + +* Fri Jan 29 2016 Lubos Kardos - 4.13.0-0.rc1.19 +- Use %%configure macro, harden rpm package (#1289734) + +* Tue Jan 19 2016 Lubos Kardos - 4.13.0-0.rc1.18 +- Escape %%autosetup in previous changelog record + +* Tue Jan 19 2016 Lubos Kardos - 4.13.0-0.rc1.17 +- Fix %%autosetup not to cause errors during run of rpmspec tool (#1293687) + +* Fri Jan 15 2016 Lubos Kardos - 4.13.0-0.rc1.16 +- Fix recursive calling of rpmdeps tool (#1297557) + +* Fri Jan 15 2016 Florian Festi - 4.13.0-0.rc1.15 +- Add support for missingok file attribute + +* Fri Jan 15 2016 Lubos Kardos - 4.13.0-0.rc1.14 +- Fix not chrooting transaction file triggers + +* Mon Nov 23 2015 Lubos Kardos - 4.13.0-0.rc1.13 +- Add possibility to disable file triggers +- Fix unwanted multiple execution of filetriggers in dnf (#1282115) + +* Thu Nov 12 2015 Fedora Release Engineering - 4.13.0-0.rc1.12 +- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5 + +* Fri Nov 06 2015 Lubos Kardos - 4.13.0-0.rc1.11 +- Fix crash when parsing corrupted RPM file (#1273360) + +* Fri Nov 06 2015 Lubos Kardos - 4.13.0-0.rc1.10 +- Fix SIGSEGV in case of old unsupported gpg keys (#1277464) + +* Fri Oct 30 2015 Lubos Kardos - 4.13.0-0.rc1.9 +- Ignore SIGPIPE signals during execucton of scriptlets (#1264198) + +* Fri Oct 30 2015 Florian Festi - 4.13.0-0.rc1.8 +- Move /usr/lib/rpm/fileattrs directory from rpm-build to rpm (#1272766) + +* Fri Oct 23 2015 Lubos Kardos - 4.13-0.rc1.7 +- Fix reading a memory right after the end of an allocated area (#1260248) +- Add support for various types of dependencies to rpmdeps tool (#1247092) +- fix %%autopatch when patch do not exist (#1244172) + +* Fri Oct 23 2015 Lubos Kardos - 4.13-0.rc1.6 +- If %%_wrong_version_format_terminate_build is 1 then terminate build in case + that version format is wrong i. e. epoch is not unsigned integer or version + contains more separators (":", "-"). %%_wrong_version_format_terminate_build + is 1 by deafault (#1265700) + +* Wed Oct 14 2015 Robert Kuska - 4.13.0-0.rc1.5 +- Rebuilt for Python3.5 rebuild + +* Mon Oct 12 2015 Florian Festi - 4.13.0-0.rc1.4 +- Fix selinux plugin for permissive mode + +* Mon Sep 07 2015 Florian Festi - 4.13.0-0.rc1.3 +- Fix new rich dependency syntax + +* Sat Sep 05 2015 Kalev Lember - 4.13.0-0.rc1.2 +- Obsolete compat-librpm3 + +* Wed Sep 02 2015 Florian Festi - 4.13.0-0.rc1.1 +- Update to upstream rc1 release + +* Mon Aug 10 2015 Lubos Kardos - 4.12.90-7 +- Fix last occurence of PyString + +* Thu Aug 06 2015 Lubos Kardos - 4.12.90-6 +- Add --filetriggers option to show info about file triggers. + +* Mon Aug 03 2015 Lubos Kardos - 4.12.90-5 +- If globbing of a filename fails, try use the filename without globbing. + (#1246743) +- Modify rpmIsGlob() to be more precise and compatible with glob(). + (#1246743) + +* Thu Jul 30 2015 Lubos Kardos - 4.12.90-4 +- Don't warn when an escaped macro is in a comment (#1224660) + +* Mon Jul 27 2015 Florian Festi - 4.12.90-3 +- Fix compressed patches (#1247248) + +* Mon Jul 27 2015 Lubos Kardos - 4.12.90-2 +- Enable braces expansion in rpmGlob() (#1246743) + +* Fri Jul 24 2015 Florian Festi - 4.12.90-1 +- Update to upstream alpha release + +* Tue Jul 14 2015 Michal Toman - 4.12.0.1-18 +- Add support for MIPS platform + +* Mon Jun 29 2015 Florian Festi - 4.12.0.1-17 +- Fix Python import directive for more strict Python3 search rules (#1236493) + +* Fri Jun 19 2015 Lubos Kardos 4.12.0.1-16 +- Allow gpg to get passphrase by itself (#1228234) + +* Thu Jun 18 2015 Fedora Release Engineering - 4.12.0.1-15.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Fri Jun 12 2015 Florian Festi - 4.12.0.1-15 +- Add --whatrecommends and friends (#1231247) + +* Wed Apr 15 2015 Florian Festi - 4.12.0.1-14 +- Fix references to sources in golang debuginfo packages (#1184221) + +* Tue Mar 31 2015 Lubos Kardos 4.12.0-13 +- Fix wrong use of variable strip_g in find-debuginfo.sh (#1207434) + +* Mon Mar 30 2015 Lubos Kardos 4.12.0-12 +- Fix segmentation fault (#1206750) + +* Fri Mar 27 2015 Lubos Kardos 4.12.0-11 +- Pass _find_debuginfo_opts -g to eu-strip for executables (#1186563) +- add_minidebug is not ran when strip_g is set (#1186563) + +* Fri Mar 20 2015 Lubos Kardos 4.12.0-10 +- Fix "--excludedocs" option (#1192625) + +* Fri Mar 20 2015 Florian Festi - 4.12.0.1-9 +- Fix spec to allow building without plugins (#1182385) + +* Mon Mar 16 2015 Than Ngo - 4.12.0.1-8 +- bump release and rebuild so that koji-shadow can rebuild it + against new gcc on secondary arch + +* Sat Feb 21 2015 Till Maas - 4.12.0.1-7.1 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Tue Feb 17 2015 Richard W.M. Jones - 4.12.0.1-7 +- Include upstream patch to fix find-debuginfo (http://www.rpm.org/ticket/887). + +* Fri Jan 16 2015 Tom Callaway - 4.12.0.1-6 +- rebuild against lua 5.3 + +* Fri Dec 12 2014 Lubos Kardos - 4.12.0.1-5 +- Add check against malicious CPIO file name size (#1168715) +- Fixes CVE-2014-8118 +- Fix race condidition where unchecked data is exposed in the file system + (#1039811) +- Fixes CVE-2013-6435 + +* Thu Oct 30 2014 Panu Matilainen - 4.12.0.1-4 +- Axe unused generator scripts forcing a perl dependency (#1158580, #1158583) + +* Tue Oct 28 2014 Panu Matilainen - 4.12.0.1-3 +- Skip ghost files in payload (#1156497) +- Fix size and archice size tag generation on big-endian systems + +* Wed Oct 01 2014 Panu Matilainen - 4.12.0.1-2 +- Dont wait for transaction lock inside scriptlets (#1135596) + +* Thu Sep 18 2014 Panu Matilainen - 4.12.0.1-1 +- Update to rpm-4.12.0.1 final (http://rpm.org/wiki/Releases/4.12.0.1) +- Temporary workaround payload size mismatch issue in rpm2cpio (#1142949) + +* Wed Sep 17 2014 Panu Matilainen - 4.12.0-2 +- Reduce the double separator spec parse error into a warning (#1065563) + +* Tue Sep 16 2014 Panu Matilainen - 4.12.0-1 +- Update to rpm-4.12.0 final (http://rpm.org/wiki/Releases/4.12.0) + +* Tue Sep 02 2014 Panu Matilainen - 4.12.0-0.rc1.2 +- Resurrect payload and tilde rpmlib() dependencies + +* Wed Aug 27 2014 Panu Matilainen - 4.12.0-0.rc1.1 +- Update to rpm-4.12.0-rc1 + +* Mon Aug 25 2014 Panu Matilainen - 4.12.0-0.beta1.6 +- Resurrect dependency logging on package build +- Resurrect rpmlib() dependencies in src.rpms + +* Wed Aug 20 2014 Panu Matilainen - 4.12.0-0.beta1.5 +- Fix duplicate trigger indexes caused by beta1.3 fix (#1131960) + +* Wed Aug 20 2014 Panu Matilainen - 4.12.0-0.beta1.4 +- Emergency hack for #1131892 + +* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.3 +- Fix regression on rpmspec dependency queries + +* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.2 +- Fix regression on BuildRequires checking + +* Mon Aug 18 2014 Panu Matilainen - 4.12.0-0.beta1.1 +- Update to 4.12.0-beta1 (http://rpm.org/wiki/Releases/4.12.0) +- Fixes #1122004, #1111349, #1117912, #1123722 +- Drop upstreamed patches + +* Mon Aug 18 2014 Fedora Release Engineering - 4.11.90-0.git12844.5.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Jul 03 2014 Panu Matilainen - 4.11.90-0.git12844.5 +- Fix wildcard database iterator (#1115824) + +* Wed Jul 02 2014 Panu Matilainen - 4.11.90-0.git12844.4 +- Use autosetup for building rpm itself +- Hopefully fix armv7 vfp/neon detection + +* Tue Jul 01 2014 Panu Matilainen - 4.11.90-0.git12844.3 +- Drop no longer needed temporary UsrMove patch +- Macro-expand load macro argument + +* Mon Jun 30 2014 Panu Matilainen - 4.11.90-0.git12844.2 +- Fix multiple interleaved hardlink groups during build + +* Mon Jun 30 2014 Panu Matilainen - 4.11.90-0.git12844.1 +- Update to rpm 4.12-alpha ((http://rpm.org/wiki/Releases/4.12.0) +- Drop/adjust patches as appropriate +- New sub-package(s) for plugins + +* Thu Jun 26 2014 Panu Matilainen - 4.11.2-17 +- Clean up old, no longer needed cruft from spec + +* Thu Jun 26 2014 Panu Matilainen - 4.11.2-16 +- Mark licenses as such, not documentation + +* Wed Jun 25 2014 Panu Matilainen - 4.11.2-15 +- Perl dependency generators live in perl-generators (#1110823) now + +* Wed Jun 18 2014 Lubomir Rintel - 4.11.2-14 +- Fix the armhfp patch for armv6hl + +* Tue Jun 10 2014 Panu Matilainen - 4.11.2-13 +- Rawhide broke our test-suite, disable for now to allow builds to be done + +* Sun Jun 08 2014 Fedora Release Engineering - 4.11.2-12.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat May 31 2014 Peter Robinson 4.11.2-12 +- Drop ChangeLog.bz2 (it's in the source, and it's large) + +* Thu May 15 2014 Bohuslav Kabrda - 4.11.2-11 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* Mon Apr 21 2014 Tom Callaway - 4.11.2-10 +- remove _isa from all BuildRequires (bz 554854) + See: https://fedoraproject.org/wiki/Packaging:Guidelines#BuildRequires_and_.25.7B_isa.7D + +* Tue Apr 15 2014 Panu Matilainen - 4.11.2-9 +- move kmod and libsymlink dependency generators to redhat-rpm-config + +* Mon Apr 14 2014 Panu Matilainen - 4.11.2-8 +- fix appdata.prov script missing from package + +* Fri Apr 11 2014 Panu Matilainen - 4.11.2-7 +- disable sanitizers for now, needs more work... + +* Fri Apr 11 2014 Panu Matilainen - 4.11.2-6 +- build with -fsanitize=address and -fsanitize=undefined for now +- add spec build conditional for sanitizer build + +* Tue Apr 08 2014 Panu Matilainen - 4.11.2-5 +- replace unmaintained dependency generator scripts with rpmdeps wrappers + +* Thu Mar 27 2014 Panu Matilainen - 4.11.2-4 +- revert #1045723 fix for now, it breaks some java package macros + +* Wed Mar 26 2014 Panu Matilainen - 4.11.2-3 +- dont eat newlines on parametrized macro invocations (#1045723) +- fully reset file actions between rpmtsRun() calls (#1076552) +- fix build and sign module initialization in python3 (#1064758) + +* Tue Feb 18 2014 Panu Matilainen - 4.11.2-2 +- reduce the double separator spec parse error into a warning (#1065563) + +* Thu Feb 13 2014 Panu Matilainen - 4.11.2-1 +- update to 4.11.2 final (http://rpm.org/wiki/Releases/4.11.2) + +* Thu Feb 06 2014 Panu Matilainen - 4.11.2-0.rc2.1 +- update to 4.11.2-rc2 (http://rpm.org/wiki/Releases/4.11.2) + +* Mon Jan 20 2014 Panu Matilainen - 4.11.2-0.rc1.1 +- update to 4.11.2-rc1 (http://rpm.org/wiki/Releases/4.11.2) +- drop upstreamed patches, adjust others as needed +- handle python egg-info's version munging in file lists + +* Wed Jan 15 2014 Panu Matilainen - 4.11.1-12 +- include ppc64le in %%power64 macro (#1052930) + +* Tue Dec 03 2013 Panu Matilainen - 4.11.1-11 +- generate kmod(module.ko) provides for kernel (#1025513) +- dont override CONFIG_SITE if already set (related to #962837) + +* Mon Nov 18 2013 Panu Matilainen - 4.11.1-10 +- python 3 string and file compatibility fixes + +* Mon Oct 14 2013 Panu Matilainen - 4.11.1-9 +- generate application() provides for gnome-software + +* Tue Oct 01 2013 Panu Matilainen - 4.11.1-8 +- add support for ppc64le architecture + +* Mon Sep 09 2013 Panu Matilainen - 4.11.1-7 +- fix build-time double-free on file capability processing (#956190) +- fix relocation related regression on file sanity check (#1001553) +- fix segfault on empty -p scriptlet body (#1004062) +- fix source url, once again + +* Wed Aug 21 2013 Panu Matilainen - 4.11.1-6 +- add python3 sub-package, based on patch by Bohuslav Kabrda + +* Sat Aug 03 2013 Petr Pisar - 4.11.1-5.1 +- Perl 5.18 rebuild + +* Fri Aug 02 2013 Panu Matilainen - 4.11.1-5 +- add missing dependency on tar to rpm-build (#986539) + +* Tue Jul 30 2013 Florian Festi - 4.11.1-4 +- Do not filter out lib64.* dependencies (#988373) + +* Wed Jul 17 2013 Petr Pisar - 4.11.1-3.1 +- Perl 5.18 rebuild + +* Fri Jul 05 2013 Panu Matilainen - 4.11.1-3 +- ensure relocatable packages always get install-prefix(es) set (#979443) + +* Thu Jul 04 2013 Panu Matilainen - 4.11.1-2 +- fix .gnu_debuglink CRC32 after dwz, buildrequire binutils-devel (#971119) + +* Thu Jun 27 2013 Panu Matilainen - 4.11.1-1 +- update to 4.11.1 final (http://rpm.org/wiki/Releases/4.11.1) + +* Thu Jun 20 2013 Panu Matilainen - 4.11.1-0.rc2.1 +- update to 4.11.2-rc2 (http://rpm.org/wiki/Releases/4.11.1) +- drop upstreamed patches + +* Mon Jun 17 2013 Panu Matilainen - 4.11.1-0.rc1.4 +- handle aarch64 debug_info relocations in debugedit (#974860) + +* Tue Jun 11 2013 Panu Matilainen - 4.11.1-0.rc1.3 +- disable autoconf config.site processing in builds (#962837) + +* Tue Jun 11 2013 Panu Matilainen - 4.11.1-0.rc1.2 +- fix regression on addressing main package by its name (#972994) + +* Mon Jun 10 2013 Panu Matilainen - 4.11.1-0.rc1.1 +- update to 4.11.1-rc1 (http://rpm.org/wiki/Releases/4.11.1) + +* Tue May 28 2013 Panu Matilainen - - 4.11.0.1-7 +- serialize BDB environment open/close (#924417) + +* Wed May 22 2013 Panu Matilainen - - 4.11.0.1-6 +- only consider files with .pm suffix as perl modules (#927211) + +* Fri May 17 2013 Panu Matilainen - - 4.11.0.1-5 +- filter out non-library soname dependencies + +* Thu May 16 2013 Panu Matilainen - - 4.11.0.1-4 +- check for stale locks when opening write-cursors (#860500, #962750...) + +* Fri May 10 2013 Tom Callaway - 4.11.0.1-3 +- lua 5.2 fix from upstream + +* Mon Mar 25 2013 Panu Matilainen - 4.11.0.1-2 +- make rpm-build depend on virtual system-rpm-config provide + +* Mon Feb 04 2013 Panu Matilainen - 4.11.0.1-1 +- update to 4.11.0.1 (http://rpm.org/wiki/Releases/4.11.0.1) + +* Tue Jan 29 2013 Panu Matilainen - 4.11.0-0.beta1.3 +- revert yesterdays ghost-fix, it eats rpmdb's on upgrades + +* Mon Jan 28 2013 Panu Matilainen - 4.11.0-0.beta1.2 +- armv7hl and armv7hnl should not have -mthumb (#901901) +- fix duplicate directory ownership between rpm and rpm-build (#894201) +- fix regression on paths shared between a real file/dir and a ghost + +* Mon Dec 10 2012 Panu Matilainen - 4.11.0-0.beta1.1 +- update to 4.11 beta + +* Mon Nov 19 2012 Panu Matilainen - 4.10.90-0.git11989.3 +- package /usr/lib/rpm/macros.d directory (related to #846679) +- fixup a bunch of old incorrect dates in spec changelog + +* Sat Nov 17 2012 Panu Matilainen - 4.10.90-0.git11989.2 +- fix double-free on %%caps in spec (#877512) + +* Thu Nov 15 2012 Panu Matilainen - 4.10.90-0.git11989.1 +- update to 4.11 (http://rpm.org/wiki/Releases/4.11.0) post-alpha snapshot +- drop/adjust patches as necessary + +* Thu Oct 11 2012 Panu Matilainen - 4.10.1-3 +- fix noarch __isa_* macro filter in installplatform (#865436) + +* Wed Oct 10 2012 Panu Matilainen - 4.10.1-2 +- account for intentionally skipped files when verifying hardlinks (#864622) + +* Wed Oct 03 2012 Panu Matilainen - 4.10.1-1 +- update to 4.10.1 ((http://rpm.org/wiki/Releases/4.10.1) + +* Mon Jul 30 2012 Panu Matilainen - 4.10.0-6 +- move our tmpfiles config to more politically correct location (#840192) + +* Sat Jul 21 2012 Fedora Release Engineering - 4.10.0-5.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 02 2012 Panu Matilainen - 4.10.0-5 +- force _host_vendor to redhat to better match toolchain etc (#485203) + +* Thu Jun 28 2012 Panu Matilainen - 4.10.0-4 +- merge ppc64p7 related fixes that only went into f17 (#835978) + +* Wed Jun 27 2012 Panu Matilainen - 4.10.0-3 +- add support for minidebuginfo generation (#834073) + +* Mon Jun 25 2012 Panu Matilainen - 4.10.0-2 +- add dwarf compression support to debuginfo generation (#833311) + +* Thu May 24 2012 Panu Matilainen - 4.10.0-1 +- update to 4.10.0 final + +* Mon Apr 23 2012 Panu Matilainen - 4.10.0-0.beta1.1 +- update to 4.10.0-beta1 + +* Mon Apr 16 2012 Panu Matilainen - 4.9.90-0.git11536.1 +- newer git snapshot (#809402, #808750) +- adjust posttrans script wrt bdb string change (#803866, #805613) + +* Thu Apr 05 2012 Panu Matilainen - 4.9.90-0.git11519.1 +- newer git snapshot to keep patch-count down +- fixes CVE-2012-0060, CVE-2012-0061 and CVE-2012-0815 +- fix obsoletes in installing set getting matched on provides (#810077) + +* Wed Apr 04 2012 Jindrich Novy - 4.9.90-0.git11505.12 +- rebuild against new libdb + +* Tue Apr 03 2012 Jindrich Novy - 4.9.90-0.git11505.11 +- build with internal libdb to allow libdb build with higher soname + +* Fri Mar 30 2012 Panu Matilainen - 4.9.90-0.git11505.10 +- fix base arch macro generation (#808250) + +* Thu Mar 29 2012 Panu Matilainen - 4.9.90-0.git11505.9 +- accept files as command line arguments to rpmdeps again (#807767) + +* Mon Mar 26 2012 Panu Matilainen - 4.9.90-0.git11505.8 +- remove fake library provide hacks now that deltarpm got rebuilt + +* Fri Mar 23 2012 Panu Matilainen - 4.9.90-0.git11505.7 +- fix header data length calculation breakage + +* Thu Mar 22 2012 Panu Matilainen - 4.9.90-0.git11505.6 +- fix keyid size bogosity causing breakage on 32bit systems + +* Wed Mar 21 2012 Panu Matilainen - 4.9.90-0.git11505.5 +- add temporary fake library provides to get around deltarpm "bootstrap" + dependency (yes its dirty) + +* Wed Mar 21 2012 Panu Matilainen - 4.9.90-0.git11505.4 +- fix overzealous sanity check breaking posttrans scripts + +* Tue Mar 20 2012 Panu Matilainen - 4.9.90-0.git11505.3 +- fix bad interaction with yum's test-transaction and pretrans scripts + +* Tue Mar 20 2012 Jindrich Novy - 4.9.90-0.git11505.2 +- rebuild + +* Tue Mar 20 2012 Panu Matilainen - 4.9.90-0.git11505.1 +- update to 4.10.0 alpha (http://rpm.org/wiki/Releases/4.10.0) +- drop/adjust patches as necessary + +* Wed Mar 07 2012 Panu Matilainen - 4.9.1.2-14 +- fix backport thinko in the exclude patch + +* Wed Mar 07 2012 Panu Matilainen - 4.9.1.2-13 +- fix memory corruption on rpmdb size estimation (#766260) +- fix couple of memleaks in python bindings (#782147) +- fix regression in verify output formatting (#797964) +- dont process spec include in false branch of if (#782970) +- only warn on missing excluded files on build (#745629) +- dont free up file info sets on test transactions + +* Thu Feb 09 2012 Panu Matilainen - 4.9.1.2-12 +- switch back to smaller BDB cache default (#752897) + +* Sun Jan 15 2012 Dennis Gilmore - 4.9.1.2-11 +- always apply arm hfp macros, conditionally apply the logic to detect hfp + +* Tue Jan 10 2012 Panu Matilainen - 4.9.1.2-10 +- adjust perl and python detection rules for libmagic change (#772699) + +* Mon Jan 09 2012 Jindrich Novy - 4.9.1.2-9 +- recognize perl script as perl code (#772632) + +* Tue Dec 20 2011 Kay Sievers - 4.9.1.2-8 +- add temporary rpmlib patch to support filesystem transition + https://fedoraproject.org/wiki/Features/UsrMove + +* Fri Dec 02 2011 Panu Matilainen - 4.9.1.2-7 +- switch over to libdb, aka Berkeley DB 5.x + +* Thu Dec 01 2011 Panu Matilainen - 4.9.1.2-6 +- fix classification of ELF binaries with setuid/setgid bit (#758251) + +* Fri Nov 25 2011 Panu Matilainen - 4.9.1.2-5 +- adjust font detection rules for libmagic change (#757105) + +* Wed Nov 09 2011 Dennis Gilmore - 4.9.1.2-4 +- conditionally apply arm patch for hardfp on all arches but arm softfp ones + +* Fri Oct 28 2011 Panu Matilainen - 4.9.1.2-3 +- adjust db util prefix & dependency due to #749293 +- warn but dont fail the build if STABS encountered by debugedit (#725378) + +* Wed Oct 12 2011 Panu Matilainen - 4.9.1.2-2 +- try teaching find-lang about the new gnome help layout (#736523) + +* Thu Sep 29 2011 Panu Matilainen - 4.9.1.2-1 +- update to 4.9.1.2 (CVE-2011-3378) +- drop upstreamed rpmdb signal patch + +* Mon Sep 19 2011 Panu Matilainen - 4.9.1.1-3 +- fix signal blocking/unblocking regression on rpmdb open/close (#739492) + +* Mon Aug 08 2011 Adam Jackson 4.9.1.1-2 +- Add RPM_LD_FLAGS to build environment (#728974) + +* Tue Aug 02 2011 Panu Matilainen - 4.9.1.1-1 +- update to 4.9.1.1 + +* Tue Jul 19 2011 Panu Matilainen - 4.9.1-2 +- fix recursion of directories with trailing slash in file list (#722474) + +* Fri Jul 15 2011 Panu Matilainen - 4.9.1-1 +- update to 4.9.1 (http://rpm.org/wiki/Releases/4.9.1) +- drop no longer needed patches + +* Thu Jun 16 2011 Panu Matilainen - 4.9.0-10 +- rebuild to fix a missing interpreter dependency due to bug #712251 + +* Fri Jun 10 2011 Panu Matilainen - 4.9.0-9 +- fix crash if prep or changelog section in spec is empty (#706959) +- fix crash on macro which undefines itself +- fix script dependency generation with file 5.07 string changes (#712251) + +* Thu May 26 2011 Panu Matilainen - 4.9.0-8 +- add dwarf-4 support to debugedit (#707677) +- generate build-id symlinks for all filenames sharing a build-id (#641377) + +* Thu Apr 07 2011 Panu Matilainen - 4.9.0-7 +- add missing ldconfig calls to build-libs sub-package +- fix source url + +* Thu Apr 07 2011 Panu Matilainen - 4.9.0-6 +- revert the spec query change (#693338) for now, it breaks fedpkg + +* Tue Apr 05 2011 Panu Matilainen - 4.9.0-5 +- verify some properties of replaced and wrong-colored files (#528383) +- only list packages that would be generated on spec query (#693338) +- preferred color packages should be erased last (#680261) +- fix leaks when freeing a populated transaction set +- take file state into account for file dependencies + +* Tue Mar 22 2011 Panu Matilainen - 4.9.0-4 +- fix classification of elf executables with sticky bit set (#689182) + +* Wed Mar 16 2011 Jindirch Novy - 4.9.0-3 +- fix crash in package manifest check (#688091) + +* Fri Mar 04 2011 Panu Matilainen - 4.9.0-2 +- fix duplicate rpmsign binary in rpm main package dragging in build-libs + +* Wed Mar 02 2011 Panu Matilainen - 4.9.0-1 +- update to 4.9.0 final +- drop upstreamed patches + +* Tue Mar 01 2011 Panu Matilainen - 4.9.0-0.rc1.4 +- spec cosmetics clean up extra whitespace + group more logically +- wipe out BDB environment at boot via tmpfiles.d + +* Mon Feb 21 2011 Panu Matilainen - 4.9.0-0.rc1.3 +- fix erronous double cursor open, causing yum reinstall hang (#678644) + +* Mon Feb 21 2011 Panu Matilainen - 4.9.0-0.rc1.2 +- fix broken logic in depgen collector, hopefully curing #675002 + +* Tue Feb 15 2011 Panu Matilainen - 4.9.0-0.rc1.1 +- update to 4.9.0-rc1 +- drop upstream patches +- nss packaging has changed, buildrequire nss-softokn-freebl-devel + +* Wed Feb 09 2011 Fedora Release Engineering - 4.9.0-0.beta1.7.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Feb 07 2011 Panu Matilainen - 4.9.0-0.beta1.7 +- fix segfault when building more than one package at a time (#675565) + +* Sun Feb 06 2011 Panu Matilainen - 4.9.0-0.beta1.6 +- adjust ocaml rule for libmagic string change + +* Mon Jan 31 2011 Panu Matilainen - 4.9.0-0.beta1.5 +- dont try to remove environment files if private env used (related to #671200) +- unbreak mono dependency extraction (#673663) +- complain instead of silent abort if cwd is not readable (#672576) + +* Tue Jan 25 2011 Panu Matilainen - 4.9.0-0.beta1.4 +- add support for Requires(posttrans) dependencies + +* Fri Jan 21 2011 Panu Matilainen - 4.9.0-0.beta1.3 +- avoid division by zero in rpmdb size calculation (#671056) +- fix secondary index iteration returing duplicate at end (#671149) +- fix rebuilddb creating duplicate indexes for first header + +* Fri Jan 21 2011 Panu Matilainen - 4.9.0-0.beta1.2 +- permit queries from rpmdb on read-only media (#671200) + +* Tue Jan 18 2011 Panu Matilainen - 4.9.0-0.beta1.1 +- rpm 4.9.0-beta1 (http://rpm.org/wiki/Releases/4.9.0) + - drop no longer needed patches + - adjust requires + buildrequires to match current needs + - adjust rpmdb index ghosts to match the new release + - split librpmbuild and librpmsign to a separate rpm-build-libs package + - split rpmsign to its own package to allow signing without all the build goo + - build-conditionalize plugins, disabled for now + - gstreamer and printer dependency generation moving out + - handle .so symlink dependencies with fileattrs + - use gnupg2 for signing as that's what typically installed by default + +* Tue Jan 18 2011 Panu Matilainen - 4.8.1-7 +- bunch of spec tweaks, cleanups + corrections: + - shorten rpm-build filelist a bit with glob use, reorder for saner grouping + - missing isa in popt version dependency + - only add rpmdb_foo symlinks for actually relevant db_* utils + - drop no longer necessary file-devel dependency from rpm-devel + - drop sqlite backend build-conditional + - preliminaries for moving from db4 to libdb +- use gnupg2 for signing as that's more likely to be installed by default + +* Mon Oct 25 2010 Jindrich Novy - 4.8.1-6 +- rebuild with new xz-5.0.0 + +* Tue Aug 10 2010 Panu Matilainen - 4.8.1-5 +- create gdb index on debuginfo generation (#617166) +- rpm-build now requires /usr/bin/gdb-add-index for consistent index creation +- include COPYING in -apidocs for licensing guidelines compliance + +* Thu Jul 22 2010 David Malcolm - 4.8.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild + +* Fri Jul 02 2010 Panu Matilainen - 4.8.1-3 +- ugh, reversed condition braindamage in the font provide extractor "fix" + +* Wed Jun 30 2010 Panu Matilainen - 4.8.1-2 +- fix a potential getOutputFrom() error from font provide extraction +- debug-friendlier message to aid finding other similar cases (#565223) + +* Fri Jun 11 2010 Panu Matilainen - 4.8.1-1 +- update to 4.8.1 (http://rpm.org/wiki/Releases/4.8.1) +- drop no longer needed patches +- fix source url pointing to testing directory + +* Thu Jun 03 2010 Panu Matilainen - 4.8.0-19 +- also strip POSIX file capabilities from hardlinks on upgrade/erase (#598775) + +* Wed Jun 02 2010 Panu Matilainen - 4.8.0-18 +- remove s-bits on upgrade too (#598775) + +* Thu May 27 2010 Panu Matilainen - 4.8.0-17 +- fix segfault in spec parser (#597835) + +* Thu May 27 2010 Panu Matilainen - 4.8.0-16 +- adjust to new pkg-config behavior wrt private dependencies (#596433) +- rpm-build now requires pkgconfig >= 0.24 + +* Fri May 21 2010 Panu Matilainen - 4.8.0-15 +- handle non-existent dependency sets correctly in python (#593553) +- make find-lang look in all locale dirs (#584866) + +* Fri Apr 23 2010 Panu Matilainen - 4.8.0-14 +- lose dangling symlink to extinct (and useless) berkeley_db_svc (#585174) + +* Wed Mar 24 2010 Panu Matilainen - 4.8.0-13 +- fix python match iterator regression wrt boolean representation + +* Wed Mar 17 2010 Panu Matilainen - 4.8.0-12 +- unbreak find-lang --with-man from yesterdays braindamage + +* Tue Mar 16 2010 Panu Matilainen - 4.8.0-11 +- support single PPD providing driver for devices (#568351) +- merge the psdriver patch pile into one +- preserve empty lines in spec prep section (#573339) +- teach python bindings about RPMTRANS_FLAG_NOCONTEXTS (related to #573111) +- dont own localized man directories through find_lang (#569536) + +* Mon Feb 15 2010 Panu Matilainen - 4.8.0-10 +- drop bogus dependency on lzma, xz is used to handle the lzma format too + +* Fri Feb 05 2010 Panu Matilainen - 4.8.0-9 +- unbreak python(abi) requires generation (#562906) + +* Fri Feb 05 2010 Panu Matilainen - 4.8.0-8 +- more fixes to postscript provides extractor (#562228) +- avoid accessing unrelated mount points in disk space checking (#547548) +- fix disk space checking with erasures present in transaction (#561160) + +* Fri Feb 05 2010 Panu Matilainen - 4.8.0-7 +- couple of fixes to the postscript provides extractor (#538101) + +* Thu Feb 04 2010 Panu Matilainen - 4.8.0-6 +- extract provides for postscript printer drivers (#538101) + +* Wed Feb 03 2010 Panu Matilainen - 4.8.0-5 +- python byte-compilation fixes + improvements (#558997) + +* Sat Jan 30 2010 Panu Matilainen - 4.8.0-4 +- support parallel python versions in python dependency extractor (#532118) + +* Thu Jan 21 2010 Panu Matilainen - 4.8.0-3 +- fix segfault on failed url retrieval +- fix verification error code depending on verbosity level +- if anything in testsuite fails, dump out the log + +* Fri Jan 08 2010 Panu Matilainen - 4.8.0-2 +- put disttag back, accidentally nuked in 4.8.0 final update + +* Fri Jan 08 2010 Panu Matilainen - 4.8.0-1 +- update to 4.8.0 final (http://rpm.org/wiki/Releases/4.8.0) + +* Thu Jan 07 2010 Panu Matilainen - 4.8.0-0.beta1.6 +- pull out macro scoping "fix" for now, it breaks font package macros + +* Mon Jan 04 2010 Panu Matilainen - 4.8.0-0.beta1.5 +- always clear locally defined macros when they go out of scope + +* Thu Dec 17 2009 Panu Matilainen - 4.8.0-0.beta1.4 +- permit unexpanded macros when parsing spec (#547997) + +* Wed Dec 09 2009 Panu Matilainen - 4.8.0-0.beta1.3 +- fix a bunch of python refcount-errors causing major memory leaks + +* Mon Dec 07 2009 Panu Matilainen - 4.8.0-0.beta1.2 +- fix noise from python bytecompile on non-python packages (#539635) +- make all our -devel [build]requires isa-specific +- trim out superfluous -devel dependencies from rpm-devel + +* Mon Dec 07 2009 Panu Matilainen - 4.8.0-0.beta1.1 +- update to 4.8.0-beta1 (http://rpm.org/wiki/Releases/4.8.0) +- rpm-build conflicts with current ocaml-runtime + +* Fri Dec 04 2009 Panu Matilainen - 4.7.2-2 +- missing error exit code from signing password checking (#496754) +- dont fail build on unrecognized data files (#532489) +- dont try to parse subkeys and secret keys (#436812) +- fix chmod test on selinux, breaking %%{_fixperms} macro (#543035) + +* Wed Nov 25 2009 Panu Matilainen - 4.7.2-1 +- update to 4.7.2 (http://rpm.org/wiki/Releases/4.7.2) +- fixes #464750, #529214 + +* Wed Nov 18 2009 Jindrich Novy - 4.7.1-10 +- rebuild against BDB-4.8.24 + +* Wed Nov 18 2009 Jindrich Novy - 4.7.1-9 +- drop versioned dependency to BDB + +* Wed Oct 28 2009 Panu Matilainen - 4.7.1-8 +- support multiple python implementations in brp-python-bytecompile (#531117) +- make disk space problem reporting a bit saner (#517418) + +* Tue Oct 06 2009 Panu Matilainen - 4.7.1-7 +- fix build with BDB 4.8.x by removing XA "support" from BDB backend +- perl dep extractor heredoc parsing improvements (#524929) + +* Mon Sep 21 2009 Panu Matilainen - 4.7.1-6 +- use relative paths within db environment (related to #507309, #507309...) +- remove db environment on close in chrooted operation (related to above) +- initialize rpmlib earlier in rpm2cpio (#523260) +- fix file dependency tag extension formatting (#523282) + +* Tue Sep 15 2009 Panu Matilainen - 4.7.1-5 +- fix duplicate dependency filtering on build (#490378) +- permit absolute paths in file lists again (#521760) +- use permissions 444 for all .debug files (#522194) +- add support for optional bugurl tag (#512774) + +* Fri Aug 14 2009 Jesse Keating - 4.7.1-4 +- Patch to make geode appear as i686 (#517475) + +* Thu Aug 06 2009 Jindrich Novy - 4.7.1-3 +- rebuild because of the new xz + +* Sun Jul 26 2009 Fedora Release Engineering - 4.7.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jul 21 2009 Panu Matilainen - 4.7.1-1 +- update to 4.7.1 ((http://rpm.org/wiki/Releases/4.7.1) +- fix source url + +* Mon Jul 20 2009 Bill Nottingham - 4.7.0-9 +- enable XZ support + +* Thu Jun 18 2009 Panu Matilainen - 4.7.0-8 +- updated OSGi dependency extractor (#506471) +- fix segfault in symlink fingerprinting (#505777) +- fix invalid memory access causing bogus file dependency errors (#506323) + +* Tue Jun 16 2009 Panu Matilainen - 4.7.0-7 +- add dwarf-3 support to debugedit (#505774) + +* Fri Jun 12 2009 Stepan Kasal - 4.7.0-6 +- require libcap >= 2.16 (#505596) + +* Wed Jun 03 2009 Panu Matilainen - 4.7.0-5 +- don't mess up problem altNEVR in python ts.check() (#501068) +- fix hardlink size calculation on build (#503020) + +* Thu May 14 2009 Panu Matilainen - 4.7.0-4 +- split cron-job into a sub-package to avoid silly deps on core rpm (#500722) +- rpm requires coreutils but not in %%post +- build with libcap and libacl +- fix pgp pubkey signature tag parsing + +* Tue Apr 21 2009 Panu Matilainen - 4.7.0-3 +- couple of merge-review fixes (#226377) + - eliminate bogus leftover rpm:rpm rpmdb ownership + - unescaped macro in changelog +- fix find-lang --with-kde with KDE3 (#466009) +- switch back to default file digest algorithm + +* Fri Apr 17 2009 Panu Matilainen - 4.7.0-2 +- file classification tweaks for text files (#494817) + - disable libmagic text token checks, it's way too error-prone + - consistently classify all text as such and include description + +* Thu Apr 16 2009 Panu Matilainen - 4.7.0-1 +- update to 4.7.0 final (http://rpm.org/wiki/Releases/4.7.0) +- fixes #494049, #495429 +- dont permit test-suite failure anymore + +* Thu Apr 09 2009 Panu Matilainen - 4.7.0-0.rc1.1 +- update to 4.7.0-rc1 +- fixes #493157, #493777, #493696, #491388, #487597, #493162 + +* Fri Apr 03 2009 Panu Matilainen - 4.7.0-0.beta1.9 +- fix recorded file state of otherwise skipped files (#492947) +- compress ChangeLog, drop old CHANGES file (#492440) + +* Thu Apr 2 2009 Tom "spot" Callaway - 4.7.0-0.beta1.8 +- Fix sparcv9v and sparc64v targets + +* Tue Mar 24 2009 Panu Matilainen - 4.7.0-0.beta1.7 +- prefer more specific types over generic "text" in classification (#491349) + +* Mon Mar 23 2009 Panu Matilainen - 4.7.0-0.beta1.6 +- with the fd leak gone, let libmagic look into compressed files again (#491596) + +* Mon Mar 23 2009 Panu Matilainen - 4.7.0-0.beta1.5 +- fix font provide generation on filenames with whitespace (#491597) + +* Thu Mar 12 2009 Panu Matilainen - 4.7.0-0.beta1.4 +- handle RSA V4 signatures (#436812) +- add alpha arch ISA-bits +- enable internal testsuite on build + +* Mon Mar 09 2009 Panu Matilainen - 4.7.0-0.beta1.3 +- fix _install_langs behavior (#489235) +- fix recording of file states into rpmdb on install + +* Sun Mar 08 2009 Panu Matilainen - 4.7.0-0.beta1.2 +- load macros before creating directories on src.rpm install (#489104) + +* Fri Mar 06 2009 Panu Matilainen - 4.7.0-0.beta1.1 +- update to 4.7.0-beta1 (http://rpm.org/wiki/Releases/4.7.0) + +* Fri Feb 27 2009 Panu Matilainen - 4.6.0-11 +- build rpm itself with md5 file digests for now to ensure upgradability + +* Thu Feb 26 2009 Panu Matilainen - 4.6.0-10 +- handle NULL passed as EVR in rpmdsSingle() again (#485616) + +* Wed Feb 25 2009 Panu Matilainen - 4.6.0-9 +- pull out python byte-compile syntax check for now + +* Mon Feb 23 2009 Panu Matilainen - 4.6.0-8 +- make -apidocs sub-package noarch +- fix source URL + +* Sat Feb 21 2009 Panu Matilainen - 4.6.0-7 +- loosen up restrictions on dependency names (#455119) +- handle inter-dependent pkg-config files for requires too (#473814) +- error/warn on elf binaries in noarch package in build + +* Fri Feb 20 2009 Panu Matilainen - 4.6.0-6 +- error out on uncompilable python code (Tim Waugh) + +* Tue Feb 17 2009 Jindrich Novy - 4.6.0-5 +- remove two offending hunks from anyarch patch causing that + RPMTAG_BUILDARCHS isn't written to SRPMs + +* Mon Feb 16 2009 Jindrich Novy - 4.6.0-4 +- inherit group tag from the main package (#470714) +- ignore BuildArch tags for anyarch actions (#442105) +- don't check package BuildRequires when doing --rmsource (#452477) +- don't fail because of missing sources when only spec removal + is requested (#472427) + +* Mon Feb 16 2009 Panu Matilainen - 4.6.0-3 +- updated fontconfig provide script - fc-query does all the hard work now + +* Mon Feb 09 2009 Panu Matilainen - 4.6.0-2 +- build against db 4.7.x + +* Fri Feb 06 2009 Panu Matilainen - 4.6.0-1 +- update to 4.6.0 final +- revert libmagic looking into compressed files for now, breaks ooffice build + +* Fri Feb 06 2009 Panu Matilainen - 4.6.0-0.rc4.5 +- enable fontconfig provides generation + +* Thu Feb 05 2009 Panu Matilainen - 4.6.0-0.rc4.4 +- fixup rpm translation lookup to match Fedora specspo (#436941) + +* Wed Feb 04 2009 Panu Matilainen - 4.6.0-0.rc4.3 +- extract mimehandler provides from .desktop files +- preliminaries for extracting font provides (not enabled yet) +- dont classify font metrics data as fonts +- only run script dep extraction once per file, duh + +* Sat Jan 31 2009 Panu Matilainen - 4.6.0-0.rc4.2 +- change platform sharedstatedir to something more sensible (#185862) +- add rpmdb_foo links to db utils for documentation compatibility + +* Fri Jan 30 2009 Panu Matilainen - 4.6.0-0.rc4.1 +- update to 4.6.0-rc4 +- fixes #475582, #478907, #476737, #479869, #476201 + +* Fri Dec 12 2008 Panu Matilainen - 4.6.0-0.rc3.2 +- add back defaultdocdir patch which hadn't been applied on 4.6.x branch yet + +* Fri Dec 12 2008 Panu Matilainen - 4.6.0-0.rc3.1 +- add dist-tag, rebuild + +* Tue Dec 09 2008 Panu Matilainen - 4.6.0-0.rc3.1 +- update to rpm 4.6.0-rc3 +- fixes #475214, #474550, #473239 + +* Wed Dec 3 2008 Jeremy Katz - 4.6.0-0.rc2.9 +- I built into the wrong place + +* Wed Dec 3 2008 Jeremy Katz - 4.6.0-0.rc2.8 +- python 2.6 rebuild again + +* Wed Dec 03 2008 Panu Matilainen +- make rpm-build require pkgconfig (#473978) + +* Tue Dec 02 2008 Panu Matilainen +- fix pkg-config provide generation when pc's depend on each other (#473814) + +* Mon Dec 01 2008 Jindrich Novy +- include rpmfileutil.h from rpmmacro.h, unbreaks + net-snmp (#473420) + +* Sun Nov 30 2008 Panu Matilainen +- rebuild for python 2.6 + +* Sat Nov 29 2008 Panu Matilainen +- update to 4.6.0-rc2 +- fixes #471820, #473167, #469355, #468319, #472507, #247374, #426672, #444661 +- enable automatic generation of pkg-config and libtool dependencies #465377 + +* Fri Oct 31 2008 Panu Matilainen +- adjust find-debuginfo for "file" output change (#468129) + +* Tue Oct 28 2008 Panu Matilainen +- Florian's improved fingerprinting hash algorithm from upstream + +* Sat Oct 25 2008 Panu Matilainen +- Make noarch sub-packages actually work +- Fix defaultdocdir logic in installplatform to avoid hardwiring mandir + +* Fri Oct 24 2008 Jindrich Novy +- update compat-db dependencies (#459710) + +* Wed Oct 22 2008 Panu Matilainen +- never add identical NEVRA to transaction more than once (#467822) + +* Sun Oct 19 2008 Panu Matilainen +- permit tab as macro argument separator (#467567) + +* Thu Oct 16 2008 Panu Matilainen +- update to 4.6.0-rc1 +- fixes #465586, #466597, #465409, #216221, #466503, #466009, #463447... +- avoid using %%configure macro for now, it has unwanted side-effects on rpm + +* Wed Oct 01 2008 Panu Matilainen +- update to official 4.5.90 alpha tarball +- a big pile of misc bugfixes + translation updates +- isa-macro generation fix for ppc (#464754) +- avoid pulling in pile of perl dependencies for an unused script +- handle both "invalid argument" and clear env version mismatch on posttrans + +* Thu Sep 25 2008 Jindrich Novy +- don't treat %%patch numberless if -P parameter is present (#463942) + +* Thu Sep 11 2008 Panu Matilainen +- add hack to support extracting gstreamer plugin provides (#438225) +- fix another macro argument handling regression (#461180) + +* Thu Sep 11 2008 Jindrich Novy +- create directory structure for rpmbuild prior to build if it doesn't exist (#455387) +- create _topdir if it doesn't exist when installing SRPM +- don't generate broken cpio in case of hardlink pointing on softlink, + thanks to pixel@mandriva.com + +* Sat Sep 06 2008 Jindrich Novy +- fail hard if patch isn't found (#461347) + +* Mon Sep 01 2008 Jindrich Novy +- fix parsing of boolean expressions in spec (#456103) + (unbreaks pam, jpilot and maybe other builds) + +* Tue Aug 26 2008 Jindrich Novy +- add support for noarch subpackages +- fix segfault in case of insufficient disk space detected (#460146) + +* Wed Aug 13 2008 Panu Matilainen +- 4.5.90-0.git8461.2 +- fix archivesize tag generation on ppc (#458817) + +* Fri Aug 08 2008 Panu Matilainen +- 4.5.90-0.git8461.1 +- new snapshot from upstream +- fixes #68290, #455972, #446202, #453364, #456708, #456103, #456321, #456913, + #458260, #458261 +- partial fix for #457360 + +* Thu Jul 31 2008 Florian Festi +- 4.5.90-0.git8427.1 +- new snapshot from upstream + +* Thu Jul 31 2008 Florian Festi +- 4.5.90-0.git8426.10 +- rpm-4.5.90-posttrans.patch +- use header from rpmdb in posttrans to make anaconda happy + +* Sat Jul 19 2008 Panu Matilainen +- 4.5.90-0.git8426.9 +- fix regression in patch number handling (#455872) + +* Tue Jul 15 2008 Panu Matilainen +- 4.5.90-0.git8426.8 +- fix regression in macro argument handling (#455333) + +* Mon Jul 14 2008 Panu Matilainen +- 4.5.90-0.git8426.7 +- fix mono dependency extraction (adjust for libmagic string change) + +* Sat Jul 12 2008 Panu Matilainen +- 4.5.90-0.git8426.6 +- fix type mismatch causing funky breakage on ppc64 + +* Fri Jul 11 2008 Panu Matilainen +- 4.5.90-0.git8426.5 +- flip back to external bdb +- fix tab vs spaces complaints from rpmlint +- add dep for lzma and require unzip instead of zip in build (#310694) +- add pkgconfig dependency to rpm-devel +- drop ISA-dependencies for initial introduction +- new snapshot from upstream for documentation fixes + +* Thu Jul 10 2008 Panu Matilainen +- 4.5.90-0.git8424.4 +- handle int vs external db in posttrans too + +* Wed Jul 09 2008 Panu Matilainen +- 4.5.90-0.git8424.3 +- require curl as external url helper + +* Wed Jul 09 2008 Panu Matilainen +- 4.5.90-0.git8424.2 +- add support for building with or without internal db + +* Wed Jul 09 2008 Panu Matilainen +- rpm 4.5.90-0.git8424.1 (alpha snapshot) +- adjust to build against Berkeley DB 4.5.20 from compat-db for now +- add posttrans to clean up db environment mismatch after upgrade +- forward-port devel autodeps patch + +* Tue Jul 08 2008 Panu Matilainen +- adjust for rpmdb index name change +- drop unnecessary vendor-macro patch for real +- add ISA-dependencies among rpm subpackages +- make lzma and sqlite deps conditional and disabled by default for now + +* Fri Feb 01 2008 Panu Matilainen +- spec largely rewritten, truncating changelog diff --git a/sources b/sources new file mode 100644 index 0000000..c030134 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (rpm-4.14.3.tar.bz2) = b329629efbcfa5ae66d28a899d3ac65ad31c10881f679cdcfd56014d9857ceafee620753ebac78689d2197245fa42ad05fc107abd33072450a70d562e3f60383 From 5bd5eb9e097fcfc1c14de72a7504c34420f56661 Mon Sep 17 00:00:00 2001 From: Davide Cavalca Date: Feb 21 2024 20:35:16 +0000 Subject: [PATCH 8/8] Merge branch 'c8s' into c8s-sig-hyperscale --- diff --git a/.gitignore b/.gitignore index 7c30adb..97e2195 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,34 @@ +/rpm-4.9.90.git11505.tar.bz2 +/rpm-4.9.90.git11519.tar.bz2 +/rpm-4.9.90.git11536.tar.bz2 +/rpm-4.10.0-beta1.tar.bz2 +/rpm-4.10.0.tar.bz2 +/rpm-4.10.1.tar.bz2 +/rpm-4.10.90.git11989.tar.bz2 +/rpm-4.11.0-beta1.tar.bz2 +/rpm-4.11.0.1.tar.bz2 +/rpm-4.11.1-rc1.tar.bz2 +/rpm-4.11.1-rc2.tar.bz2 +/rpm-4.11.1.tar.bz2 +/rpm-4.11.2-rc1.tar.bz2 +/rpm-4.11.2-rc2.tar.bz2 +/rpm-4.11.2.tar.bz2 +/rpm-4.11.90-git12844.tar.bz2 +/rpm-4.12.0-beta1.tar.bz2 +/rpm-4.12.0-rc1.tar.bz2 +/rpm-4.12.0.tar.bz2 +/rpm-4.12.0.1.tar.bz2 +/rpm-4.12.90.tar.bz2 +/rpm-4.13.0-rc1.tar.bz2 +/rpm-4.13.0-rc2.tar.bz2 +/rpm-4.13.0.tar.bz2 +/rpm-4.13.0.1.tar.bz2 +/rpm-4.13.90-git14002.tar.bz2 +/rpm-4.14.0-rc1.tar.bz2 +/rpm-4.14.0-rc2.tar.bz2 +/rpm-4.14.0.tar.bz2 +/rpm-4.14.1.tar.bz2 +/rpm-4.14.2-rc1.tar.bz2 +/rpm-4.14.2-rc2.tar.bz2 +/rpm-4.14.2.tar.bz2 /rpm-4.14.3.tar.bz2 diff --git a/0001-Add-optional-callback-on-directory-changes-during-rp.patch b/0001-Add-optional-callback-on-directory-changes-during-rp.patch new file mode 100644 index 0000000..bda7110 --- /dev/null +++ b/0001-Add-optional-callback-on-directory-changes-during-rp.patch @@ -0,0 +1,107 @@ +From 186e0ab025b9ad92d900697f611633a6f6162f3b Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch new file mode 100644 index 0000000..f910f38 --- /dev/null +++ b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch @@ -0,0 +1,30 @@ +From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Eliminate-code-duplication-from-rpmfiNext.patch b/0001-Eliminate-code-duplication-from-rpmfiNext.patch new file mode 100644 index 0000000..a5e0463 --- /dev/null +++ b/0001-Eliminate-code-duplication-from-rpmfiNext.patch @@ -0,0 +1,35 @@ +From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch new file mode 100644 index 0000000..29fb473 --- /dev/null +++ b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch @@ -0,0 +1,66 @@ +From c140768202e271b60910644c1e4bf848a50218d3 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch new file mode 100644 index 0000000..1d73765 --- /dev/null +++ b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch @@ -0,0 +1,46 @@ +From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch new file mode 100644 index 0000000..51ecf97 --- /dev/null +++ b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch @@ -0,0 +1,153 @@ +From ac7b0dbd5a18d2c57a942ca14ac856b8047425ff Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 { diff --git a/0001-Print-full-path-if-file-removal-fails.patch b/0001-Print-full-path-if-file-removal-fails.patch new file mode 100644 index 0000000..266bd69 --- /dev/null +++ b/0001-Print-full-path-if-file-removal-fails.patch @@ -0,0 +1,32 @@ +From f1503ab6e898430b80017c0f8347860f3a74d5bb Mon Sep 17 00:00:00 2001 +From: Florian Festi +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 + diff --git a/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch new file mode 100644 index 0000000..3210c07 --- /dev/null +++ b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch @@ -0,0 +1,90 @@ +From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Use-file-state-machine-from-rpm-4.19.patch b/0001-Use-file-state-machine-from-rpm-4.19.patch new file mode 100644 index 0000000..5b6653e --- /dev/null +++ b/0001-Use-file-state-machine-from-rpm-4.19.patch @@ -0,0 +1,1654 @@ +From 36ee14a07630668629a0d461fba8b5b2248d7d71 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 10 Oct 2023 16:46:17 +0200 +Subject: [PATCH] Use file state machine from rpm-4.19 + +This new implementation fixes several race conditions when placing down +files on disc +--- + lib/fsm.c | 1164 +++++++++++++++++++++++++--------------------- + lib/rpmarchive.h | 3 + + lib/rpmfiles.h | 3 + + +diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h +index c864e5b56..e5cda4f97 100644 +--- a/lib/rpmarchive.h ++++ b/lib/rpmarchive.h +@@ -26,6 +26,8 @@ enum rpmfilesErrorCodes { + RPMERR_FILE_SIZE = -12, + RPMERR_ITER_SKIP = -13, + RPMERR_EXIST_AS_DIR = -14, ++ RPMERR_INVALID_SYMLINK = -15, ++ RPMERR_ENOTDIR = -16, + + RPMERR_OPEN_FAILED = -32768, + RPMERR_CHMOD_FAILED = -32769, +@@ -47,6 +49,7 @@ enum rpmfilesErrorCodes { + RPMERR_COPY_FAILED = -32785, + RPMERR_LSETFCON_FAILED = -32786, + RPMERR_SETCAP_FAILED = -32787, ++ RPMERR_CLOSE_FAILED = -32788, + }; + + #ifdef __cplusplus +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index daf572cf4..e74bb2201 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e { + #define XFA_SKIPPING(_a) \ + ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) + ++#define XFA_CREATING(_a) \ ++ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) ++ + /** + * We pass these around as an array with a sentinel. + */ +--- rpm-4.14.3/lib/fsm.c.orig 2023-10-11 16:00:49.610090807 +0200 ++++ rpm-4.14.3/lib/fsm.c 2023-10-11 16:01:16.976451270 +0200 +@@ -5,9 +5,11 @@ + + #include "system.h" + ++#include + #include + #include +-#if WITH_CAP ++#include ++#ifdef WITH_CAP + #include + #endif + +@@ -17,10 +19,11 @@ + #include + + #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ +-#include "lib/fsm.h" +-#include "lib/rpmte_internal.h" /* XXX rpmfs */ +-#include "lib/rpmplugins.h" /* rpm plugins hooks */ +-#include "lib/rpmug.h" ++#include "fsm.h" ++#include "rpmte_internal.h" /* XXX rpmfs */ ++#include "rpmfi_internal.h" /* rpmfiSetOnChdir */ ++#include "rpmplugins.h" /* rpm plugins hooks */ ++#include "rpmug.h" + + #include "debug.h" + +@@ -38,172 +41,92 @@ + #define _dirPerms 0755 + #define _filePerms 0644 + ++enum filestage_e { ++ FILE_COMMIT = -1, ++ FILE_NONE = 0, ++ FILE_PRE = 1, ++ FILE_UNPACK = 2, ++ FILE_PREP = 3, ++ FILE_POST = 4, ++}; ++ ++struct filedata_s { ++ int stage; ++ int setmeta; ++ int skip; ++ rpmFileAction action; ++ const char *suffix; ++ char *fpath; ++ struct stat sb; ++}; ++ + /* + * XXX Forward declarations for previously exported functions to avoid moving + * things around needlessly + */ + static const char * fileActionString(rpmFileAction a); ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir); ++static int fsmClose(int *wfdp); + + /** \ingroup payload + * Build path to file from file info, optionally ornamented with suffix. ++ * "/" needs special handling to avoid appearing as empty path. + * @param fi file info iterator + * @param suffix suffix to use (NULL disables) +- * @retval path to file (malloced) ++ * @param[out] path to file (malloced) + */ + static char * fsmFsPath(rpmfi fi, const char * suffix) + { +- return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL); +-} +- +-/** \ingroup payload +- * Directory name iterator. +- */ +-typedef struct dnli_s { +- rpmfiles fi; +- char * active; +- int reverse; +- int isave; +- int i; +-} * DNLI_t; +- +-/** \ingroup payload +- * Destroy directory name iterator. +- * @param dnli directory name iterator +- * @retval NULL always +- */ +-static DNLI_t dnlFreeIterator(DNLI_t dnli) +-{ +- if (dnli) { +- if (dnli->active) free(dnli->active); +- free(dnli); +- } +- return NULL; ++ const char *bn = rpmfiBN(fi); ++ return rstrscat(NULL, *bn ? bn : "/", suffix ? suffix : "", NULL); + } + +-/** \ingroup payload +- * Create directory name iterator. +- * @param fi file info set +- * @param fs file state set +- * @param reverse traverse directory names in reverse order? +- * @return directory name iterator +- */ +-static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse) ++static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path) + { +- DNLI_t dnli; +- int i, j; +- int dc; +- +- if (fi == NULL) +- return NULL; +- dc = rpmfilesDC(fi); +- dnli = xcalloc(1, sizeof(*dnli)); +- dnli->fi = fi; +- dnli->reverse = reverse; +- dnli->i = (reverse ? dc : 0); +- +- if (dc) { +- dnli->active = xcalloc(dc, sizeof(*dnli->active)); +- int fc = rpmfilesFC(fi); +- +- /* Identify parent directories not skipped. */ +- for (i = 0; i < fc; i++) +- if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) +- dnli->active[rpmfilesDI(fi, i)] = 1; +- +- /* Exclude parent directories that are explicitly included. */ +- for (i = 0; i < fc; i++) { +- int dil; +- size_t dnlen, bnlen; ++ int rc = linkat(odirfd, opath, dirfd, path, 0); + +- if (!S_ISDIR(rpmfilesFMode(fi, i))) +- continue; +- +- dil = rpmfilesDI(fi, i); +- dnlen = strlen(rpmfilesDN(fi, dil)); +- bnlen = strlen(rpmfilesBN(fi, i)); +- +- for (j = 0; j < dc; j++) { +- const char * dnl; +- size_t jlen; +- +- if (!dnli->active[j] || j == dil) +- continue; +- dnl = rpmfilesDN(fi, j); +- jlen = strlen(dnl); +- if (jlen != (dnlen+bnlen+1)) +- continue; +- if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen)) +- continue; +- if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen)) +- continue; +- if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') +- continue; +- /* This directory is included in the package. */ +- dnli->active[j] = 0; +- break; +- } +- } +- +- /* Print only once per package. */ +- if (!reverse) { +- j = 0; +- for (i = 0; i < dc; i++) { +- if (!dnli->active[i]) continue; +- if (j == 0) { +- j = 1; +- rpmlog(RPMLOG_DEBUG, +- "========== Directories not explicitly included in package:\n"); +- } +- rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i)); +- } +- if (j) +- rpmlog(RPMLOG_DEBUG, "==========\n"); +- } ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } +- return dnli; ++ ++ if (rc < 0) ++ rc = RPMERR_LINK_FAILED; ++ return rc; + } + +-/** \ingroup payload +- * Return next directory name (from file info). +- * @param dnli directory name iterator +- * @return next directory name +- */ +-static +-const char * dnlNextIterator(DNLI_t dnli) ++#ifdef WITH_CAP ++static int cap_set_fileat(int dirfd, const char *path, cap_t fcaps) + { +- const char * dn = NULL; +- +- if (dnli) { +- rpmfiles fi = dnli->fi; +- int dc = rpmfilesDC(fi); +- int i = -1; +- +- if (dnli->active) +- do { +- i = (!dnli->reverse ? dnli->i++ : --dnli->i); +- } while (i >= 0 && i < dc && !dnli->active[i]); +- +- if (i >= 0 && i < dc) +- dn = rpmfilesDN(fi, i); +- else +- i = -1; +- dnli->isave = i; ++ int rc = -1; ++ int fd = fsmOpenat(dirfd, path, O_RDONLY|O_NOFOLLOW, 0); ++ if (fd >= 0) { ++ rc = cap_set_fd(fd, fcaps); ++ fsmClose(&fd); + } +- return dn; ++ return rc; + } ++#endif + +-static int fsmSetFCaps(const char *path, const char *captxt) ++static int fsmSetFCaps(int fd, int dirfd, const char *path, const char *captxt) + { + int rc = 0; +-#if WITH_CAP ++ ++#ifdef WITH_CAP + if (captxt && *captxt != '\0') { + cap_t fcaps = cap_from_text(captxt); +- if (fcaps == NULL || cap_set_file(path, fcaps) != 0) { +- rc = RPMERR_SETCAP_FAILED; ++ ++ if (fd >= 0) { ++ if (fcaps == NULL || cap_set_fd(fd, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; ++ } else { ++ if (fcaps == NULL || cap_set_fileat(dirfd, path, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; + } ++ + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- path, captxt, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %s) %s\n", __func__, ++ fd, dirfd, path, captxt, (rc < 0 ? strerror(errno) : "")); + } + cap_free(fcaps); + } +@@ -211,101 +134,104 @@ + return rc; + } + +-static void wfd_close(FD_t *wfdp) ++static int fsmClose(int *wfdp) + { +- if (wfdp && *wfdp) { ++ int rc = 0; ++ if (wfdp && *wfdp >= 0) { + int myerrno = errno; + static int oneshot = 0; + static int flush_io = 0; ++ int fdno = *wfdp; ++ + if (!oneshot) { +- flush_io = rpmExpandNumeric("%{?_flush_io}"); ++ flush_io = (rpmExpandNumeric("%{?_flush_io}") > 0); + oneshot = 1; + } + if (flush_io) { +- int fdno = Fileno(*wfdp); + fsync(fdno); + } +- Fclose(*wfdp); +- *wfdp = NULL; ++ if (close(fdno)) ++ rc = RPMERR_CLOSE_FAILED; ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__, ++ fdno, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = -1; + errno = myerrno; + } ++ return rc; + } + +-static int wfd_open(FD_t *wfdp, const char *dest) ++static int fsmOpen(int *wfdp, int dirfd, const char *dest) + { + int rc = 0; + /* Create the file with 0200 permissions (write by owner). */ +- { +- mode_t old_umask = umask(0577); +- *wfdp = Fopen(dest, "wx.ufdio"); +- umask(old_umask); +- } +- if (Ferror(*wfdp)) { ++ int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200); ++ ++ if (fd < 0) + rc = RPMERR_OPEN_FAILED; +- goto exit; +- } + +- return 0; ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__, ++ dest, fd, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = fd; + +-exit: +- wfd_close(wfdp); + return rc; + } + +-/** \ingroup payload +- * Create file from payload stream. +- * @return 0 on success +- */ +-static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) ++static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest) + { +- FD_t wfd = NULL; +- int rc; +- +- rc = wfd_open(&wfd, dest); +- if (rc != 0) +- goto exit; +- +- rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm); +- wfd_close(&wfd); +-exit: ++ FD_t fd = fdDup(fdno); ++ int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm); ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s %" PRIu64 " bytes [%d]) %s\n", __func__, ++ rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd), ++ (rc < 0 ? strerror(errno) : "")); ++ } ++ Fclose(fd); + return rc; + } + +-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, +- rpmpsm psm, int nodigest, int *setmeta, +- int * firsthardlink, FD_t *firstlinkfile) ++static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files, ++ rpmpsm psm, int nodigest, ++ struct filedata_s ** firstlink, int *firstlinkfile, ++ int *firstdir, int *fdp) + { + int rc = 0; +- int numHardlinks = rpmfiFNlink(fi); ++ int fd = -1; + +- if (numHardlinks > 1) { +- /* Create first hardlinked file empty */ +- if (*firsthardlink < 0) { +- *firsthardlink = rpmfiFX(fi); +- rc = wfd_open(firstlinkfile, dest); +- } else { +- /* Create hard links for others */ +- char *fn = rpmfilesFN(files, *firsthardlink); +- rc = link(fn, dest); +- if (rc < 0) { +- rc = RPMERR_LINK_FAILED; +- } +- free(fn); ++ if (*firstlink == NULL) { ++ /* First encounter, open file for writing */ ++ rc = fsmOpen(&fd, dirfd, fp->fpath); ++ /* If it's a part of a hardlinked set, the content may come later */ ++ if (fp->sb.st_nlink > 1) { ++ *firstlink = fp; ++ *firstlinkfile = fd; ++ *firstdir = dup(dirfd); ++ } ++ } else { ++ /* Create hard links for others and avoid redundant metadata setting */ ++ if (*firstlink != fp) { ++ rc = fsmLink(*firstdir, (*firstlink)->fpath, dirfd, fp->fpath); + } ++ fd = *firstlinkfile; + } +- /* Write normal files or fill the last hardlinked (already +- existing) file with content */ +- if (numHardlinks<=1) { +- if (!rc) +- rc = expandRegular(fi, dest, psm, nodigest); +- } else if (rpmfiArchiveHasContent(fi)) { ++ ++ /* If the file has content, unpack it */ ++ if (rpmfiArchiveHasContent(fi)) { + if (!rc) +- rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); +- wfd_close(firstlinkfile); +- *firsthardlink = -1; +- } else { +- *setmeta = 0; ++ rc = fsmUnpack(fi, fd, psm, nodigest); ++ /* Last file of hardlink set, ensure metadata gets set */ ++ if (*firstlink) { ++ fp->setmeta = 1; ++ *firstlink = NULL; ++ *firstlinkfile = -1; ++ fsmClose(firstdir); ++ } + } ++ *fdp = fd; + + return rc; + } +@@ -330,18 +256,15 @@ + return rc; + } + +-static int fsmStat(const char *path, int dolstat, struct stat *sb) ++static int fsmStat(int dirfd, const char *path, int dolstat, struct stat *sb) + { +- int rc; +- if (dolstat){ +- rc = lstat(path, sb); +- } else { +- rc = stat(path, sb); +- } ++ int flags = dolstat ? AT_SYMLINK_NOFOLLOW : 0; ++ int rc = fstatat(dirfd, path, sb, flags); ++ + if (_fsm_debug && rc && errno != ENOENT) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, ost) %s\n", + __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) { + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED); + /* Ensure consistent struct content on failure */ +@@ -350,12 +273,12 @@ + return rc; + } + +-static int fsmRmdir(const char *path) ++static int fsmRmdir(int dirfd, const char *path) + { +- int rc = rmdir(path); ++ int rc = unlinkat(dirfd, path, AT_REMOVEDIR); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + switch (errno) { + case ENOENT: rc = RPMERR_ENOENT; break; +@@ -365,172 +288,194 @@ + return rc; + } + +-static int fsmMkdir(const char *path, mode_t mode) ++static int fsmMkdir(int dirfd, const char *path, mode_t mode) + { +- int rc = mkdir(path, (mode & 07777)); ++ int rc = mkdirat(dirfd, path, (mode & 07777)); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", __func__, ++ dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_MKDIR_FAILED; + return rc; + } + +-static int fsmMkfifo(const char *path, mode_t mode) ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir) + { +- int rc = mkfifo(path, (mode & 07777)); +- +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", +- __func__, path, (unsigned)(mode & 07777), +- (rc < 0 ? strerror(errno) : "")); ++ struct stat lsb, sb; ++ int sflags = flags | O_NOFOLLOW; ++ int fd = openat(dirfd, path, sflags); ++ ++ /* ++ * Only ever follow symlinks by root or target owner. Since we can't ++ * open the symlink itself, the order matters: we stat the link *after* ++ * opening the target, and if the link ownership changed between the calls ++ * it could've only been the link owner or root. ++ */ ++ if (fd < 0 && errno == ELOOP && flags != sflags) { ++ int ffd = openat(dirfd, path, flags); ++ if (ffd >= 0) { ++ if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) { ++ if (fstat(ffd, &sb) == 0) { ++ if (lsb.st_uid == 0 || lsb.st_uid == sb.st_uid) { ++ fd = ffd; ++ } ++ } ++ } ++ if (ffd != fd) ++ close(ffd); ++ } + } + +- if (rc < 0) +- rc = RPMERR_MKFIFO_FAILED; +- +- return rc; ++ /* O_DIRECTORY equivalent */ ++ if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) { ++ errno = ENOTDIR; ++ fsmClose(&fd); ++ } ++ return fd; + } + +-static int fsmMknod(const char *path, mode_t mode, dev_t dev) ++static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn, ++ const char *apath, ++ int owned, mode_t mode, int *fdp) + { +- /* FIX: check S_IFIFO or dev != 0 */ +- int rc = mknod(path, (mode & ~07777), dev); ++ int rc; ++ rpmFsmOp op = (FA_CREATE); ++ if (!owned) ++ op |= FAF_UNOWNED; + +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", +- __func__, path, (unsigned)(mode & ~07777), +- (unsigned)dev, (rc < 0 ? strerror(errno) : "")); ++ /* Run fsm file pre hook for all plugins */ ++ rc = rpmpluginsCallFsmFilePre(plugins, NULL, apath, mode, op); ++ ++ if (!rc) ++ rc = fsmMkdir(dirfd, dn, mode); ++ ++ if (!rc) { ++ *fdp = fsmOpenat(dirfd, dn, O_RDONLY|O_NOFOLLOW, 1); ++ if (*fdp == -1) ++ rc = RPMERR_ENOTDIR; + } + +- if (rc < 0) +- rc = RPMERR_MKNOD_FAILED; ++ if (!rc) { ++ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, *fdp, apath, apath, mode, op); ++ } ++ ++ /* Run fsm file post hook for all plugins */ ++ rpmpluginsCallFsmFilePost(plugins, NULL, apath, mode, op, rc); ++ ++ if (!rc) { ++ rpmlog(RPMLOG_DEBUG, ++ "%s directory created with perms %04o\n", ++ apath, (unsigned)(mode & 07777)); ++ } + + return rc; + } + +-/** +- * Create (if necessary) directories not explicitly included in package. +- * @param files file data +- * @param fs file states +- * @param plugins rpm plugins handle +- * @return 0 on success +- */ +-static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins) ++static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create, ++ int quiet, int *dirfdp) + { +- DNLI_t dnli = dnlInitIterator(files, fs, 0); +- struct stat sb; +- const char *dpath; +- int dc = rpmfilesDC(files); ++ char *sp = NULL, *bn; ++ char *apath = NULL; ++ int oflags = O_RDONLY; + int rc = 0; +- int i; +- int ldnlen = 0; +- int ldnalloc = 0; +- char * ldn = NULL; +- short * dnlx = NULL; +- +- dnlx = (dc ? xcalloc(dc, sizeof(*dnlx)) : NULL); +- +- if (dnlx != NULL) +- while ((dpath = dnlNextIterator(dnli)) != NULL) { +- size_t dnlen = strlen(dpath); +- char * te, dn[dnlen+1]; +- +- dc = dnli->isave; +- if (dc < 0) continue; +- dnlx[dc] = dnlen; +- if (dnlen <= 1) +- continue; + +- if (dnlen <= ldnlen && rstreq(dpath, ldn)) +- continue; ++ if (*dirfdp >= 0) ++ return rc; + +- /* Copy as we need to modify the string */ +- (void) stpcpy(dn, dpath); ++ int dirfd = fsmOpenat(-1, "/", oflags, 1); ++ int fd = dirfd; /* special case of "/" */ + +- /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ +- for (i = 1, te = dn + 1; *te != '\0'; te++, i++) { +- if (*te != '/') +- continue; ++ char *path = xstrdup(p); ++ char *dp = path; + +- *te = '\0'; ++ while ((bn = strtok_r(dp, "/", &sp)) != NULL) { ++ fd = fsmOpenat(dirfd, bn, oflags, 1); ++ /* assemble absolute path for plugins benefit, sigh */ ++ apath = rstrscat(&apath, "/", bn, NULL); + +- /* Already validated? */ +- if (i < ldnlen && +- (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i)) +- { +- *te = '/'; +- /* Move pre-existing path marker forward. */ +- dnlx[dc] = (te - dn); +- continue; ++ if (fd < 0 && errno == ENOENT && create) { ++ mode_t mode = S_IFDIR | (_dirPerms & 07777); ++ rc = fsmDoMkDir(plugins, dirfd, bn, apath, owned, mode, &fd); ++ } ++ ++ fsmClose(&dirfd); ++ if (fd >= 0) { ++ dirfd = fd; ++ } else { ++ if (!quiet) { ++ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"), ++ bn, p, strerror(errno)); + } ++ rc = RPMERR_OPEN_FAILED; ++ break; ++ } + +- /* Validate next component of path. */ +- rc = fsmStat(dn, 1, &sb); /* lstat */ +- *te = '/'; +- +- /* Directory already exists? */ +- if (rc == 0 && S_ISDIR(sb.st_mode)) { +- /* Move pre-existing path marker forward. */ +- dnlx[dc] = (te - dn); +- } else if (rc == RPMERR_ENOENT) { +- *te = '\0'; +- mode_t mode = S_IFDIR | (_dirPerms & 07777); +- rpmFsmOp op = (FA_CREATE|FAF_UNOWNED); +- +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op); +- +- if (!rc) +- rc = fsmMkdir(dn, mode); +- +- if (!rc) { +- rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, +- mode, op); +- } ++ dp = NULL; ++ } + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc); ++ if (rc) { ++ fsmClose(&fd); ++ fsmClose(&dirfd); ++ } else { ++ rc = 0; ++ } ++ *dirfdp = dirfd; + +- if (!rc) { +- rpmlog(RPMLOG_DEBUG, +- "%s directory created with perms %04o\n", +- dn, (unsigned)(mode & 07777)); +- } +- *te = '/'; +- } +- if (rc) +- break; +- } +- if (rc) break; ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s: %d) %s\n", __func__, ++ p, dirfd, (rc < 0 ? strerror(errno) : "")); ++ } + +- /* Save last validated path. */ +- if (ldnalloc < (dnlen + 1)) { +- ldnalloc = dnlen + 100; +- ldn = xrealloc(ldn, ldnalloc); +- } +- if (ldn != NULL) { /* XXX can't happen */ +- strcpy(ldn, dn); +- ldnlen = dnlen; +- } ++ free(path); ++ free(apath); ++ return rc; ++} ++ ++static int fsmMkfifo(int dirfd, const char *path, mode_t mode) ++{ ++ int rc = mkfifoat(dirfd, path, (mode & 07777)); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & 07777), ++ (rc < 0 ? strerror(errno) : "")); ++ } ++ ++ if (rc < 0) ++ rc = RPMERR_MKFIFO_FAILED; ++ ++ return rc; ++} ++ ++static int fsmMknod(int dirfd, const char *path, mode_t mode, dev_t dev) ++{ ++ /* FIX: check S_IFIFO or dev != 0 */ ++ int rc = mknodat(dirfd, path, (mode & ~07777), dev); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%o, 0x%x) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & ~07777), ++ (unsigned)dev, (rc < 0 ? strerror(errno) : "")); + } +- free(dnlx); +- free(ldn); +- dnlFreeIterator(dnli); ++ ++ if (rc < 0) ++ rc = RPMERR_MKNOD_FAILED; + + return rc; + } + +-static void removeSBITS(const char *path) ++static void removeSBITS(int dirfd, const char *path) + { + struct stat stb; +- if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) { ++ /* We now know it's not a link so no need to worry about following */ + if ((stb.st_mode & 06000) != 0) { +- (void) chmod(path, stb.st_mode & 0777); ++ (void) fchmodat(dirfd, path, stb.st_mode & 0777, 0); + } +-#if WITH_CAP ++#ifdef WITH_CAP + if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { +- (void) cap_set_file(path, NULL); ++ (void) cap_set_fileat(dirfd, path, NULL); + } + #endif + } +@@ -546,13 +490,13 @@ + (fpath ? fpath : "")); + } + +-static int fsmSymlink(const char *opath, const char *path) ++static int fsmSymlink(const char *opath, int dirfd, const char *path) + { +- int rc = symlink(opath, path); ++ int rc = symlinkat(opath, dirfd, path); + + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%s, %d %s) %s\n", __func__, ++ opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } + + if (rc < 0) +@@ -560,96 +504,125 @@ + return rc; + } + +-static int fsmUnlink(const char *path) ++static int fsmUnlink(int dirfd, const char *path) + { + int rc = 0; +- removeSBITS(path); +- rc = unlink(path); ++ removeSBITS(dirfd, path); ++ rc = unlinkat(dirfd, path, 0); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED); + return rc; + } + +-static int fsmRename(const char *opath, const char *path) ++static int fsmRename(int odirfd, const char *opath, int dirfd, const char *path) + { +- removeSBITS(path); +- int rc = rename(opath, path); ++ removeSBITS(dirfd, path); ++ int rc = renameat(odirfd, opath, dirfd, path); + #if defined(ETXTBSY) && defined(__HPUX__) + /* XXX HP-UX (and other os'es) don't permit rename to busy files. */ + if (rc && errno == ETXTBSY) { + char *rmpath = NULL; + rstrscat(&rmpath, path, "-RPMDELETE", NULL); +- rc = rename(path, rmpath); +- if (!rc) rc = rename(opath, path); ++ /* Rename within the original directory */ ++ rc = renameat(odirfd, path, odirfd, rmpath); ++ if (!rc) rc = renameat(odirfd, opath, dirfd, path); + free(rmpath); + } + #endif + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED); + return rc; + } + +-static int fsmRemove(const char *path, mode_t mode) ++static int fsmRemove(int dirfd, const char *path, mode_t mode) + { +- return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path); ++ return S_ISDIR(mode) ? fsmRmdir(dirfd, path) : fsmUnlink(dirfd, path); + } + +-static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid) ++static int fsmChown(int fd, int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid) + { +- int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid) +- rc = 0; ++ int rc; ++ struct stat st; ++ ++ if (fd >= 0) { ++ rc = fchown(fd, uid, gid); ++ if (rc < 0) { ++ if (fstat(fd, &st) == 0 && (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } ++ } else { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ rc = fchownat(dirfd, path, uid, gid, flags); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, flags) == 0 && ++ (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } + } +- if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__, +- path, (int)uid, (int)gid, ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %d, %d) %s\n", __func__, ++ fd, dirfd, path, (int)uid, (int)gid, + (rc < 0 ? strerror(errno) : "")); ++ } + if (rc < 0) rc = RPMERR_CHOWN_FAILED; + return rc; + } + +-static int fsmChmod(const char *path, mode_t mode) ++static int fsmChmod(int fd, int dirfd, const char *path, mode_t mode) + { +- int rc = chmod(path, (mode & 07777)); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777)) +- rc = 0; ++ mode_t fmode = (mode & 07777); ++ int rc; ++ if (fd >= 0) { ++ rc = fchmod(fd, fmode); ++ if (rc < 0) { ++ struct stat st; ++ if (fstat(fd, &st) == 0 && (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } ++ } else { ++ rc = fchmodat(dirfd, path, fmode, 0); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, AT_SYMLINK_NOFOLLOW) == 0 && ++ (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } + } + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0%04o) %s\n", __func__, ++ fd, dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_CHMOD_FAILED; + return rc; + } + +-static int fsmUtime(const char *path, mode_t mode, time_t mtime) ++static int fsmUtime(int fd, int dirfd, const char *path, mode_t mode, time_t mtime) + { + int rc = 0; +- struct timeval stamps[2] = { +- { .tv_sec = mtime, .tv_usec = 0 }, +- { .tv_sec = mtime, .tv_usec = 0 }, ++ struct timespec stamps[2] = { ++ { .tv_sec = mtime, .tv_nsec = 0 }, ++ { .tv_sec = mtime, .tv_nsec = 0 }, + }; + +-#if HAVE_LUTIMES +- rc = lutimes(path, stamps); +-#else +- if (!S_ISLNK(mode)) +- rc = utimes(path, stamps); +-#endif ++ if (fd >= 0) ++ rc = futimens(fd, stamps); ++ else ++ rc = utimensat(dirfd, path, stamps, AT_SYMLINK_NOFOLLOW); + + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__, +- path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0x%x) %s\n", __func__, ++ fd, dirfd, path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_UTIME_FAILED; + /* ...but utime error is not critical for directories */ + if (rc && S_ISDIR(mode)) +@@ -657,24 +630,24 @@ + return rc; + } + +-static int fsmVerify(const char *path, rpmfi fi) ++static int fsmVerify(int dirfd, const char *path, rpmfi fi) + { + int rc; + int saveerrno = errno; + struct stat dsb; + mode_t mode = rpmfiFMode(fi); + +- rc = fsmStat(path, 1, &dsb); ++ rc = fsmStat(dirfd, path, 1, &dsb); + if (rc) + return rc; + + if (S_ISREG(mode)) { + /* HP-UX (and other os'es) don't permit unlink on busy files. */ + char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL); +- rc = fsmRename(path, rmpath); ++ rc = fsmRename(dirfd, path, dirfd, rmpath); + /* XXX shouldn't we take unlink return code here? */ + if (!rc) +- (void) fsmUnlink(rmpath); ++ (void) fsmUnlink(dirfd, rmpath); + else + rc = RPMERR_UNLINK_FAILED; + free(rmpath); +@@ -683,7 +656,7 @@ + if (S_ISDIR(dsb.st_mode)) return 0; + if (S_ISLNK(dsb.st_mode)) { + uid_t luid = dsb.st_uid; +- rc = fsmStat(path, 0, &dsb); ++ rc = fsmStat(dirfd, path, 0, &dsb); + if (rc == RPMERR_ENOENT) rc = 0; + if (rc) return rc; + errno = saveerrno; +@@ -709,7 +682,7 @@ + if (S_ISSOCK(dsb.st_mode)) return 0; + } + /* XXX shouldn't do this with commit/undo. */ +- rc = fsmUnlink(path); ++ rc = fsmUnlink(dirfd, path); + if (rc == 0) rc = RPMERR_ENOENT; + return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */ + } +@@ -723,7 +696,7 @@ + + + /* Rename pre-existing modified or unmanaged file. */ +-static int fsmBackup(rpmfi fi, rpmFileAction action) ++static int fsmBackup(int dirfd, rpmfi fi, rpmFileAction action) + { + int rc = 0; + const char *suffix = NULL; +@@ -744,9 +717,10 @@ + if (suffix) { + char * opath = fsmFsPath(fi, NULL); + char * path = fsmFsPath(fi, suffix); +- rc = fsmRename(opath, path); ++ rc = fsmRename(dirfd, opath, dirfd, path); + if (!rc) { +- rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path); ++ rpmlog(RPMLOG_WARNING, _("%s%s saved as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), path); + } + free(path); + free(opath); +@@ -754,7 +728,8 @@ + return rc; + } + +-static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins, ++static int fsmSetmeta(int fd, int dirfd, const char *path, ++ rpmfi fi, rpmPlugins plugins, + rpmFileAction action, const struct stat * st, + int nofcaps) + { +@@ -762,27 +737,28 @@ + const char *dest = rpmfiFN(fi); + + if (!rc && !getuid()) { +- rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid); ++ rc = fsmChown(fd, dirfd, path, st->st_mode, st->st_uid, st->st_gid); + } + if (!rc && !S_ISLNK(st->st_mode)) { +- rc = fsmChmod(path, st->st_mode); ++ rc = fsmChmod(fd, dirfd, path, st->st_mode); + } + /* Set file capabilities (if enabled) */ + if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) { +- rc = fsmSetFCaps(path, rpmfiFCaps(fi)); ++ rc = fsmSetFCaps(fd, dirfd, path, rpmfiFCaps(fi)); + } + if (!rc) { +- rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi)); ++ rc = fsmUtime(fd, dirfd, path, st->st_mode, rpmfiFMtime(fi)); + } + if (!rc) { + rc = rpmpluginsCallFsmFilePrepare(plugins, fi, +- path, dest, st->st_mode, action); ++ fd, path, dest, ++ st->st_mode, action); + } + + return rc; + } + +-static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix) ++static int fsmCommit(int dirfd, char **path, rpmfi fi, rpmFileAction action, const char *suffix) + { + int rc = 0; + +@@ -796,15 +772,18 @@ + + /* Rename temporary to final file name if needed. */ + if (dest != *path) { +- rc = fsmRename(*path, dest); +- if (!rc && nsuffix) { +- char * opath = fsmFsPath(fi, NULL); +- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), +- opath, dest); +- free(opath); +- } +- free(*path); +- *path = dest; ++ rc = fsmRename(dirfd, *path, dirfd, dest); ++ if (!rc) { ++ if (nsuffix) { ++ char * opath = fsmFsPath(fi, NULL); ++ rpmlog(RPMLOG_WARNING, _("%s%s created as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), dest); ++ free(opath); ++ } ++ free(*path); ++ *path = dest; ++ } else ++ free(dest); + } + } + +@@ -855,184 +834,277 @@ + } + } + ++struct diriter_s { ++ int dirfd; ++ int firstdir; ++}; ++ ++static int onChdir(rpmfi fi, void *data) ++{ ++ struct diriter_s *di = data; ++ ++ fsmClose(&(di->dirfd)); ++ return 0; ++} ++ ++static rpmfi fsmIter(FD_t payload, rpmfiles files, rpmFileIter iter, void *data) ++{ ++ rpmfi fi; ++ if (payload) ++ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ else ++ fi = rpmfilesIter(files, iter); ++ if (fi && data) ++ rpmfiSetOnChdir(fi, onChdir, data); ++ return fi; ++} ++ ++static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di) ++{ ++ fsmClose(&(di->dirfd)); ++ fsmClose(&(di->firstdir)); ++ return rpmfiFree(fi); ++} ++ + int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { + FD_t payload = rpmtePayload(te); +- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ rpmfi fi = NULL; + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; +- int saveerrno = errno; + int rc = 0; ++ int fx = -1; ++ int fc = rpmfilesFC(files); + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; +- int firsthardlink = -1; +- FD_t firstlinkfile = NULL; +- int skip; +- rpmFileAction action; ++ int firstlinkfile = -1; + char *tid = NULL; +- const char *suffix; +- char *fpath = NULL; +- +- if (fi == NULL) { +- rc = RPMERR_BAD_MAGIC; +- goto exit; +- } ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); ++ struct filedata_s *firstlink = NULL; ++ struct diriter_s di = { -1, -1 }; + + /* transaction id used for temporary path suffix while installing */ + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); + +- /* Detect and create directories not explicitly in package. */ +- rc = fsmMkdirs(files, fs, plugins); +- +- while (!rc) { +- /* Read next payload header. */ +- rc = rpmfiNext(fi); ++ /* Collect state data for the whole operation */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ if (rpmfiFFlags(fi) & RPMFILE_GHOST) ++ fp->action = FA_SKIP; ++ else ++ fp->action = rpmfsGetAction(fs, fx); ++ fp->skip = XFA_SKIPPING(fp->action); ++ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) ++ fp->suffix = tid; ++ fp->fpath = fsmFsPath(fi, fp->suffix); + +- if (rc < 0) { +- if (rc == RPMERR_ITER_END) +- rc = 0; +- break; +- } ++ /* Remap file perms, owner, and group. */ ++ rc = rpmfiStat(fi, 1, &fp->sb); + +- action = rpmfsGetAction(fs, rpmfiFX(fi)); +- skip = XFA_SKIPPING(action); +- if (action != FA_TOUCH) { +- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; +- } else { +- suffix = NULL; +- } +- fpath = fsmFsPath(fi, suffix); ++ /* Hardlinks are tricky and handled elsewhere for install */ ++ fp->setmeta = (fp->skip == 0) && ++ (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH); + +- /* Remap file perms, owner, and group. */ +- rc = rpmfiStat(fi, 1, &sb); ++ setFileState(fs, fx); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fp->stage = FILE_PRE; ++ } ++ fi = rpmfiFree(fi); + +- /* Exit on error. */ +- if (rc) +- break; ++ if (rc) ++ goto exit; + +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); +- if (rc) { +- skip = 1; +- } else { +- setFileState(fs, rpmfiFX(fi)); +- } ++ fi = fsmIter(payload, files, ++ payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + +- if (!skip) { +- int setmeta = 1; ++ if (fi == NULL) { ++ rc = RPMERR_BAD_MAGIC; ++ goto exit; ++ } + +- /* When touching we don't need any of this... */ +- if (action == FA_TOUCH) +- goto touch; ++ /* Process the payload */ ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* ++ * Tricksy case: this file is a being skipped, but it's part of ++ * a hardlinked set and has the actual content linked with it. ++ * Write the content to the first non-skipped file of the set ++ * instead. ++ */ ++ if (fp->skip && firstlink && rpmfiArchiveHasContent(fi)) ++ fp = firstlink; ++ ++ if (!fp->skip) { ++ int mayopen = 0; ++ int fd = -1; ++ rc = ensureDir(plugins, rpmfiDN(fi), 0, ++ (fp->action == FA_CREATE), 0, &di.dirfd); + + /* Directories replacing something need early backup */ +- if (!suffix) { +- rc = fsmBackup(fi, action); ++ if (!rc && !fp->suffix && fp != firstlink) { ++ rc = fsmBackup(di.dirfd, fi, fp->action); + } ++ ++ /* Run fsm file pre hook for all plugins */ ++ if (!rc) ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); ++ if (rc) ++ goto setmeta; /* for error notification */ ++ + /* Assume file does't exist when tmp suffix is in use */ +- if (!suffix) { +- rc = fsmVerify(fpath, fi); ++ if (!fp->suffix) { ++ if (fp->action == FA_TOUCH) { ++ struct stat sb; ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &sb); ++ } else { ++ rc = fsmVerify(di.dirfd, fp->fpath, fi); ++ } + } else { + rc = RPMERR_ENOENT; + } + +- if (S_ISREG(sb.st_mode)) { ++ /* See if the file was removed while our attention was elsewhere */ ++ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { ++ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", ++ fp->fpath); ++ fp->action = FA_CREATE; ++ fsmDebug(fp->fpath, fp->action, &fp->sb); ++ } ++ ++ /* When touching we don't need any of this... */ ++ if (fp->action == FA_TOUCH) ++ goto setmeta; ++ ++ if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fpath, files, psm, nodigest, +- &setmeta, &firsthardlink, &firstlinkfile); ++ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile, &di.firstdir, ++ &fd); + } +- } else if (S_ISDIR(sb.st_mode)) { ++ } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- mode_t mode = sb.st_mode; ++ mode_t mode = fp->sb.st_mode; + mode &= ~07777; + mode |= 00700; +- rc = fsmMkdir(fpath, mode); ++ rc = fsmMkdir(di.dirfd, fp->fpath, mode); + } +- } else if (S_ISLNK(sb.st_mode)) { ++ } else if (S_ISLNK(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmSymlink(rpmfiFLink(fi), fpath); ++ rc = fsmSymlink(rpmfiFLink(fi), di.dirfd, fp->fpath); + } +- } else if (S_ISFIFO(sb.st_mode)) { ++ } else if (S_ISFIFO(fp->sb.st_mode)) { + /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfifo(fpath, 0000); ++ rc = fsmMkfifo(di.dirfd, fp->fpath, 0000); + } +- } else if (S_ISCHR(sb.st_mode) || +- S_ISBLK(sb.st_mode) || +- S_ISSOCK(sb.st_mode)) ++ } else if (S_ISCHR(fp->sb.st_mode) || ++ S_ISBLK(fp->sb.st_mode) || ++ S_ISSOCK(fp->sb.st_mode)) + { + if (rc == RPMERR_ENOENT) { +- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); ++ rc = fsmMknod(di.dirfd, fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); + } + } else { + /* XXX Special case /dev/log, which shouldn't be packaged anyways */ +- if (!IS_DEV_LOG(fpath)) ++ if (!IS_DEV_LOG(fp->fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; + } + +-touch: +- /* Set permissions, timestamps etc for non-hardlink entries */ +- if (!rc && setmeta) { +- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); ++setmeta: ++ /* Special files require path-based ops */ ++ mayopen = S_ISREG(fp->sb.st_mode) || S_ISDIR(fp->sb.st_mode); ++ if (!rc && fd == -1 && mayopen) { ++ int flags = O_RDONLY; ++ /* Only follow safe symlinks, and never on temporary files */ ++ if (fp->suffix) ++ flags |= AT_SYMLINK_NOFOLLOW; ++ fd = fsmOpenat(di.dirfd, fp->fpath, flags, ++ S_ISDIR(fp->sb.st_mode)); ++ if (fd < 0) ++ rc = RPMERR_OPEN_FAILED; + } +- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { +- /* On FA_TOUCH no hardlinks are created thus this is skipped. */ +- /* we skip the hard linked file containing the content */ +- /* write the content to the first used instead */ +- char *fn = rpmfilesFN(files, firsthardlink); +- rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); +- wfd_close(&firstlinkfile); +- firsthardlink = -1; +- free(fn); +- } +- +- if (rc) { +- if (!skip) { +- /* XXX only erase if temp fn w suffix is in use */ +- if (suffix) { +- (void) fsmRemove(fpath, sb.st_mode); +- } +- errno = saveerrno; +- } +- } else { +- /* Notify on success. */ +- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); +- +- if (!skip) { +- /* Backup file if needed. Directories are handled earlier */ +- if (suffix) +- rc = fsmBackup(fi, action); + +- if (!rc) +- rc = fsmCommit(&fpath, fi, action, suffix); ++ if (!rc && fp->setmeta) { ++ rc = fsmSetmeta(fd, di.dirfd, fp->fpath, ++ fi, plugins, fp->action, ++ &fp->sb, nofcaps); + } ++ ++ if (fd != firstlinkfile) ++ fsmClose(&fd); + } + ++ /* Notify on success. */ + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ else ++ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); ++ fp->stage = FILE_UNPACK; ++ } ++ fi = fsmIterFini(fi, &di); + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); +- fpath = _free(fpath); ++ if (!rc && fx < 0 && fx != RPMERR_ITER_END) ++ rc = fx; ++ ++ /* If all went well, commit files to final destination */ ++ fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ if (!fp->skip) { ++ if (!rc) ++ rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd); ++ ++ /* Backup file if needed. Directories are handled earlier */ ++ if (!rc && fp->suffix) ++ rc = fsmBackup(di.dirfd, fi, fp->action); ++ ++ if (!rc) ++ rc = fsmCommit(di.dirfd, &fp->fpath, fi, fp->action, fp->suffix); ++ ++ if (!rc) ++ fp->stage = FILE_COMMIT; ++ else ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ ++ /* Run fsm file post hook for all plugins for all processed files */ ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); ++ } ++ } ++ fi = fsmIterFini(fi, &di); ++ ++ /* On failure, walk backwards and erase non-committed files */ ++ if (rc) { ++ fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); ++ while ((fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ if (fp->stage > FILE_NONE && !fp->skip) { ++ (void) fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); ++ } ++ } + } + + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + + exit: +- +- /* No need to bother with close errors on read */ +- rpmfiArchiveClose(fi); +- rpmfiFree(fi); ++ fi = fsmIterFini(fi, &di); + Fclose(payload); + free(tid); +- free(fpath); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); + + return rc; + } +@@ -1041,32 +1113,42 @@ + int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { +- rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); ++ struct diriter_s di = { -1, -1 }; ++ rpmfi fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; ++ int fc = rpmfilesFC(files); ++ int fx = -1; ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + int rc = 0; +- char *fpath = NULL; + +- while (!rc && rpmfiNext(fi) >= 0) { +- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); +- fpath = fsmFsPath(fi, NULL); +- rc = fsmStat(fpath, 1, &sb); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); ++ ++ if (XFA_SKIPPING(fp->action)) ++ continue; ++ ++ fp->fpath = fsmFsPath(fi, NULL); ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + + /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); + +- if (!XFA_SKIPPING(action)) +- rc = fsmBackup(fi, action); ++ rc = fsmBackup(di.dirfd, fi, fp->action); + + /* Remove erased files. */ +- if (action == FA_ERASE) { ++ if (fp->action == FA_ERASE) { + int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); + +- rc = fsmRemove(fpath, sb.st_mode); ++ rc = fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); + + /* + * Missing %ghost or %missingok entries are not errors. +@@ -1091,20 +1173,20 @@ + if (rc) { + int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING; + rpmlog(lvl, _("%s %s: remove failed: %s\n"), +- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), +- fpath, strerror(errno)); ++ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), ++ fp->fpath, strerror(errno)); + } + } + + /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); + + /* XXX Failure to remove is not (yet) cause for failure. */ + if (!strict_erasures) rc = 0; + + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); + + if (rc == 0) { + /* Notify on success. */ +@@ -1112,11 +1194,12 @@ + rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); + rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + } +- fpath = _free(fpath); + } + +- free(fpath); +- rpmfiFree(fi); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); ++ fsmIterFini(fi, &di); + + return rc; + } diff --git a/STAGE2-rpm b/STAGE2-rpm new file mode 100644 index 0000000..b2dcd2a --- /dev/null +++ b/STAGE2-rpm @@ -0,0 +1,34 @@ +#requires popt +#requires nss-softokn +#requires nss +#requires file +#requires libarchive +#requires libdb4 +#requires redhat-rpm-config +#requires lua +#requires autoconf +#requires pkgconfig + + +(cd $SRC/rpm-*/ && autoreconf -vif) + +mcd $BUILDDIR/rpm + +$SRC/rpm-*/configure $TCONFIGARGS \ + --build=${TARGET} \ + --host=${TARGET} \ + --target=${TARGET} \ + CPPFLAGS="-I/usr/include/nspr -I/usr/include/nss3 -DPACKAGE -DPACKAGE_VERSION" \ + --libdir=/usr/lib${SUFFIX} \ + --with-external-db \ + --disable-static \ + --with-lua \ + --localstatedir=/var + +make $J +make $J install + +mkdir -p /etc/rpm +mkdir -p /var/lib/rpm + +rpm --initdb diff --git a/brp-python-bytecompile-compatibility-with-newer-pyth.patch b/brp-python-bytecompile-compatibility-with-newer-pyth.patch new file mode 100644 index 0000000..ebe7230 --- /dev/null +++ b/brp-python-bytecompile-compatibility-with-newer-pyth.patch @@ -0,0 +1,46 @@ +From acbf558c486ee3518aca74045504f05872da4a58 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +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 + diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..7755c22 --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-8 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1-gating.functional} diff --git a/rpm-4.14.1-python-brp-bytecompile.patch b/rpm-4.14.1-python-brp-bytecompile.patch new file mode 100644 index 0000000..d99a271 --- /dev/null +++ b/rpm-4.14.1-python-brp-bytecompile.patch @@ -0,0 +1,15 @@ +diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile +index 894fa3459..47776215a 100644 +--- a/scripts/brp-python-bytecompile ++++ b/scripts/brp-python-bytecompile +@@ -87,6 +87,10 @@ if [ ! -x "$default_python" ]; then + exit 0 + 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 ++ + # 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" "/" + if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then diff --git a/rpm.spec b/rpm.spec index 8cebcb6..002ab02 100644 --- a/rpm.spec +++ b/rpm.spec @@ -42,7 +42,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 26.4 +%global rel 31.1 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -129,6 +129,16 @@ Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch 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 @@ -161,9 +171,12 @@ Patch1001: compile-with-Platform-Python-binary-where-relevant.patch # 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 -Patch1003: rpm-4.14.3-backport-multithreaded-zstd.patch +Patch1004: rpm-4.14.3-backport-multithreaded-zstd.patch %endif # fsverity support @@ -846,9 +859,20 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog +* Wed Feb 21 2024 Davide Cavalca - 4.14.3-31.1 +- Merge upstream changes for Hyperscale + * Wed Feb 21 2024 Davide Cavalca - 4.14.3-26.4 - Convert to dist-git layout +* Tue Dec 12 2023 Florian Festi - 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 - 4.14.3-27 +- Make brp-python-bytecompile script compatible with Python 3.10+ +Resolves: RHEL-6423 + * Wed Sep 13 2023 Richard Phibel - 4.14.3-26.3 - Fix IMA signature lengths assumed constant @@ -859,7 +883,7 @@ make check || cat tests/rpmtests.log * Wed Dec 21 2022 Davide Cavalca - 4.14.3-26.1 - Merge upstream changes for Hyperscale -* Mon Dec 19 2022 Florian Festi - 4.14.4-26 +* Mon Dec 19 2022 Florian Festi - 4.14.3-26 - Add --nocompression to rpm2archive (#2129345) * Fri Dec 16 2022 Davide Cavalca - 4.14.3-25.1