From 83a7c7e9569ce961863fbb0c77624508b5ecf9f6 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 05 2019 20:54:05 +0000 Subject: import rpm-4.14.2-25.el8 --- 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 new file mode 100644 index 0000000..43dfe47 --- /dev/null +++ b/SOURCES/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 + } +@@ -409,8 +426,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 ;; + esac + $skip_mini || add_minidebug "${debugfn}" "$f" diff --git a/SOURCES/0001-Correct-rpm-ql-exit-value-when-optional-p-is-omitted.patch b/SOURCES/0001-Correct-rpm-ql-exit-value-when-optional-p-is-omitted.patch new file mode 100644 index 0000000..9f123ba --- /dev/null +++ b/SOURCES/0001-Correct-rpm-ql-exit-value-when-optional-p-is-omitted.patch @@ -0,0 +1,38 @@ +From ce11f04ed529cd84de8981b82c1185c0a30dfdcf Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Thu, 14 Mar 2019 13:23:13 +0100 +Subject: [PATCH] Correct rpm -ql exit value when optional -p is omitted + (RhBug:1680610) + +--- + lib/query.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/lib/query.c b/lib/query.c +index e47189ed0..e5408e211 100644 +--- a/lib/query.c ++++ b/lib/query.c +@@ -568,16 +568,18 @@ int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv) + break; + default: + for (ARGV_const_t arg = argv; arg && *arg; arg++) { ++ int ecLocal; + rpmdbMatchIterator mi = initQueryIterator(qva, ts, *arg); +- ec += rpmcliShowMatches(qva, ts, mi); ++ ecLocal = rpmcliShowMatches(qva, ts, mi); + if (mi == NULL && qva->qva_source == RPMQV_PACKAGE) { + size_t l = strlen(*arg); + if (l > 4 && !strcmp(*arg + l - 4, ".rpm")) { + rpmgi gi = rpmgiNew(ts, giFlags, argv); +- ec += rpmgiShowMatches(qva, ts, gi); ++ ecLocal = rpmgiShowMatches(qva, ts, gi); + rpmgiFree(gi); + } + } ++ ec += ecLocal; + rpmdbFreeIterator(mi); + } + break; +-- +2.17.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 new file mode 100644 index 0000000..df98eaa --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Fix-a-blindingly-obvious-memleak-in-package-verify-s.patch b/SOURCES/0001-Fix-a-blindingly-obvious-memleak-in-package-verify-s.patch new file mode 100644 index 0000000..0dc7f30 --- /dev/null +++ b/SOURCES/0001-Fix-a-blindingly-obvious-memleak-in-package-verify-s.patch @@ -0,0 +1,26 @@ +From 788935c9ea9d2f469f24be10a9fa998594046731 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Fri, 7 Sep 2018 11:52:33 +0300 +Subject: [PATCH] Fix a blindingly obvious memleak in package verify step + +Erm. Introduced in commit 765e2c72ae8be369ada41d4747b8999519a0e327, +but how on earth did this go unnoticed... *blush* +--- + lib/transaction.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/transaction.c b/lib/transaction.c +index 205c3f388..3969ad3fc 100644 +--- a/lib/transaction.c ++++ b/lib/transaction.c +@@ -1261,6 +1261,7 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) + rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0); + + vd.msg = _free(vd.msg); ++ rpmvsFree(vs); + } + rpmtsNotify(ts, NULL, RPMCALLBACK_VERIFY_STOP, total, total); + +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-ancient-python-GIL-locking-bug-on-callback-RhBug.patch b/SOURCES/0001-Fix-ancient-python-GIL-locking-bug-on-callback-RhBug.patch new file mode 100644 index 0000000..494634d --- /dev/null +++ b/SOURCES/0001-Fix-ancient-python-GIL-locking-bug-on-callback-RhBug.patch @@ -0,0 +1,46 @@ +From 531dc8495cd3aabd3f659ecab604106fdbacbe98 Mon Sep 17 00:00:00 2001 +Message-Id: <531dc8495cd3aabd3f659ecab604106fdbacbe98.1554974459.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 3 Oct 2018 11:51:38 +0300 +Subject: [PATCH] Fix ancient python GIL locking bug on callback + (RhBug:1632488) + +Introduced in commit c7881d801745b4c156a8aa2afc17b95f97481e34 back in 2002, +synthesizing a python object for the callback occurs before retaking +the GIL lock, which is not allowed. Somehow this has managed to stay +latent all these years, and even now requires fairly specific conditions: +when the callback gets called without an associated key, such as erasures +or file trigger script start/stop events (in the case of RhBug:1632488), +when Python 3 is running in PYTHONMALLOC=debug mode, +it crashes with "Python memory allocator called without holding the GIL". + +Simply retake the lock before any Python operations take place to fix. +--- + python/rpmts-py.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/python/rpmts-py.c b/python/rpmts-py.c +index e4c5e1250..1ddfc9a1e 100644 +--- a/python/rpmts-py.c ++++ b/python/rpmts-py.c +@@ -495,6 +495,8 @@ rpmtsCallback(const void * hd, const rpmCallbackType what, + + if (cbInfo->cb == Py_None) return NULL; + ++ PyEval_RestoreThread(cbInfo->_save); ++ + /* Synthesize a python object for callback (if necessary). */ + if (pkgObj == NULL) { + if (h) { +@@ -506,8 +508,6 @@ rpmtsCallback(const void * hd, const rpmCallbackType what, + } else + Py_INCREF(pkgObj); + +- PyEval_RestoreThread(cbInfo->_save); +- + args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data); + result = PyEval_CallObject(cbInfo->cb, args); + Py_DECREF(args); +-- +2.20.1 + diff --git a/SOURCES/0001-Fix-memleak-during-transaction-verify-step-in-the-NO.patch b/SOURCES/0001-Fix-memleak-during-transaction-verify-step-in-the-NO.patch new file mode 100644 index 0000000..d1bb187 --- /dev/null +++ b/SOURCES/0001-Fix-memleak-during-transaction-verify-step-in-the-NO.patch @@ -0,0 +1,30 @@ +From 5188a7b35eb3672c9b15e96433e033ee36f8e6a8 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Tue, 6 Aug 2019 13:06:16 +0300 +Subject: [PATCH] Fix memleak during transaction verify step in the NOKEY case. + +Found during RhBug:1714657 QA testing. +In addition, add a comment to clarify the fallthrough as intentional. +--- + lib/transaction.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/lib/transaction.c b/lib/transaction.c +index 6e4d4be65..e51cff25a 100644 +--- a/lib/transaction.c ++++ b/lib/transaction.c +@@ -1226,8 +1226,10 @@ static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata) + */ + if (!(vd->vfylevel & RPMSIG_SIGNATURE_TYPE)) + sinfo->rc = RPMRC_OK; ++ /* fallthrough */ + default: +- vd->msg = rpmsinfoMsg(sinfo); ++ if (sinfo->rc) ++ vd->msg = rpmsinfoMsg(sinfo); + break; + } + return (sinfo->rc == 0); +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-rpmfiles-memory-leak-on-postuntrans-file-trigger.patch b/SOURCES/0001-Fix-rpmfiles-memory-leak-on-postuntrans-file-trigger.patch new file mode 100644 index 0000000..ff18186 --- /dev/null +++ b/SOURCES/0001-Fix-rpmfiles-memory-leak-on-postuntrans-file-trigger.patch @@ -0,0 +1,25 @@ +From 475af64f64cbc210c87588d425fa9a14cd9760b6 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 29 May 2019 11:38:53 +0300 +Subject: [PATCH] Fix rpmfiles memory leak on %postuntrans file trigger + preparation + +--- + lib/rpmtriggers.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c +index cb2441c5a..b7c76e7fc 100644 +--- a/lib/rpmtriggers.c ++++ b/lib/rpmtriggers.c +@@ -154,6 +154,7 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) + } + } + rpmdbFreeIterator(mi); ++ rpmfilesFree(files); + } + + int runPostUnTransFileTrigs(rpmts ts) +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-segfault-on-fingerprinting-symlink-round-RhBug-1.patch b/SOURCES/0001-Fix-segfault-on-fingerprinting-symlink-round-RhBug-1.patch new file mode 100644 index 0000000..a3faebb --- /dev/null +++ b/SOURCES/0001-Fix-segfault-on-fingerprinting-symlink-round-RhBug-1.patch @@ -0,0 +1,60 @@ +From 050b392f8c11d111379e0d2bac52762beb97b3ae Mon Sep 17 00:00:00 2001 +Message-Id: <050b392f8c11d111379e0d2bac52762beb97b3ae.1559645935.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Tue, 2 Apr 2019 12:57:11 +0300 +Subject: [PATCH] Fix segfault on fingerprinting symlink round (RhBug:1660232) + +Both yum and dnf perform a test-transaction before the real thing, +and both neglet to check for an error code from the test-transaction +when there are no problem objects to return. Which can happen in +some special cases, such a using different vsflags between initial +package read and transaction (which is what both yum and dnf do), +which can cause the in-transaction package open fail on corrupt packages. +And when this failed transaction is fed back to rpmtsRun(), it +segfaults in fingerprinting as the second loop of symlink checking +doesn't check for NULL's element files like the first loop does. + +Add the missing NULL check and remove bogus "can't happen" comment to fix. + +FWIW, the scenario with different vsflags and corrupted packages doesn't +happen by default in rpm >= 4.14.2, the corrupt package gets caught +in the verify stage which does create problem objects and thus both +yum and dnf abort as they should. +--- + lib/fprint.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/lib/fprint.c b/lib/fprint.c +index b810e4d2b..ab1891961 100644 +--- a/lib/fprint.c ++++ b/lib/fprint.c +@@ -488,7 +488,7 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount) + (void) rpmsqPoll(); + + if ((fi = rpmteFiles(p)) == NULL) +- continue; /* XXX can't happen */ ++ continue; + + (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); + rpmfilesFpLookup(fi, fpc); +@@ -522,6 +522,9 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount) + while ((p = rpmtsiNext(pi, 0)) != NULL) { + (void) rpmsqPoll(); + ++ if ((fi = rpmteFiles(p)) == NULL) ++ continue; ++ + fs = rpmteGetFileStates(p); + fc = rpmfsFC(fs); + (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); +@@ -531,6 +534,7 @@ void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount) + fpLookupSubdir(symlinks, fpc, p, i); + } + (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); ++ rpmfilesFree(fi); + } + rpmtsiFree(pi); + +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-testing-for-wrong-variable-in-selinux-plugin-deb.patch b/SOURCES/0001-Fix-testing-for-wrong-variable-in-selinux-plugin-deb.patch new file mode 100644 index 0000000..7d99a49 --- /dev/null +++ b/SOURCES/0001-Fix-testing-for-wrong-variable-in-selinux-plugin-deb.patch @@ -0,0 +1,28 @@ +From 66e0c929b203d684a4f58135f42435fcc29cdd51 Mon Sep 17 00:00:00 2001 +Message-Id: <66e0c929b203d684a4f58135f42435fcc29cdd51.1554982695.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 10 Oct 2018 12:00:19 +0300 +Subject: [PATCH] Fix testing for wrong variable in selinux plugin debug log + +The strerror() case couldn't be reached as we were testing for the +wrong rc, spotted by covscan. +--- + plugins/selinux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/selinux.c b/plugins/selinux.c +index 3c9d9e4ab..accd47416 100644 +--- a/plugins/selinux.c ++++ b/plugins/selinux.c +@@ -169,7 +169,7 @@ static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + + if (rpmIsDebug()) { + rpmlog(RPMLOG_DEBUG, "lsetfilecon: (%s, %s) %s\n", +- path, scon, (rc < 0 ? strerror(errno) : "")); ++ path, scon, (conrc < 0 ? strerror(errno) : "")); + } + + if (conrc == 0 || (conrc < 0 && errno == EOPNOTSUPP)) +-- +2.20.1 + diff --git a/SOURCES/0001-Fully-shutdown-DBUS-on-systemd_inhibit-cleanup-RhBug.patch b/SOURCES/0001-Fully-shutdown-DBUS-on-systemd_inhibit-cleanup-RhBug.patch new file mode 100644 index 0000000..54519f0 --- /dev/null +++ b/SOURCES/0001-Fully-shutdown-DBUS-on-systemd_inhibit-cleanup-RhBug.patch @@ -0,0 +1,40 @@ +From d5f201345f6d27b6280750e5c6502f4418614fbc Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 29 May 2019 12:09:20 +0300 +Subject: [PATCH] Fully shutdown DBUS on systemd_inhibit cleanup + (RhBug:1714657) + +dbus_shutdown() frees internal DBUS memory allocations that will otherwise +show up as memory leaks. This is of little consequence in practise +but shuts up valgrind... +--- + plugins/systemd_inhibit.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/plugins/systemd_inhibit.c b/plugins/systemd_inhibit.c +index e2cbcffbb..0628188ba 100644 +--- a/plugins/systemd_inhibit.c ++++ b/plugins/systemd_inhibit.c +@@ -80,6 +80,11 @@ static rpmRC systemd_inhibit_init(rpmPlugin plugin, rpmts ts) + return RPMRC_NOTFOUND; + } + ++static void systemd_inhibit_cleanup(rpmPlugin plugin) ++{ ++ dbus_shutdown(); ++} ++ + static rpmRC systemd_inhibit_tsm_pre(rpmPlugin plugin, rpmts ts) + { + if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)) +@@ -106,6 +111,7 @@ static rpmRC systemd_inhibit_tsm_post(rpmPlugin plugin, rpmts ts, int res) + + struct rpmPluginHooks_s systemd_inhibit_hooks = { + .init = systemd_inhibit_init, ++ .cleanup = systemd_inhibit_cleanup, + .tsm_pre = systemd_inhibit_tsm_pre, + .tsm_post = systemd_inhibit_tsm_post, + }; +-- +2.21.0 + 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 new file mode 100644 index 0000000..35f12c2 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Log-RPMLOG_ERR-level-messages-on-actual-errors-in-se.patch b/SOURCES/0001-Log-RPMLOG_ERR-level-messages-on-actual-errors-in-se.patch new file mode 100644 index 0000000..312d9cc --- /dev/null +++ b/SOURCES/0001-Log-RPMLOG_ERR-level-messages-on-actual-errors-in-se.patch @@ -0,0 +1,86 @@ +From 8cbe8baf9c3ff4754369bcd29441df14ecc6889d Mon Sep 17 00:00:00 2001 +Message-Id: <8cbe8baf9c3ff4754369bcd29441df14ecc6889d.1554982512.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 14 Feb 2019 13:12:49 +0200 +Subject: [PATCH] Log RPMLOG_ERR level messages on actual errors in selinux + plugin, doh. + +When there's an actual error, people will want to know without having +to rerun in verbose mode. Such as in RhBug:1641631 where configured +selinux policy differs from what is installed - the former message + + error: Plugin selinux: hook tsm_pre failed + +...is not particularly helpful to anybody, whereas this actually provides +some clues now: + + error: selabel_open: (/etc/selinux/ponies/contexts/files/file_contexts) No such file or directory + error: Plugin selinux: hook tsm_pre failed +--- + plugins/selinux.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/plugins/selinux.c b/plugins/selinux.c +index accd47416..f1caf257c 100644 +--- a/plugins/selinux.c ++++ b/plugins/selinux.c +@@ -12,6 +12,11 @@ + + static struct selabel_handle * sehandle = NULL; + ++static inline rpmlogLvl loglvl(int iserror) ++{ ++ return iserror ? RPMLOG_ERR : RPMLOG_DEBUG; ++} ++ + static void sehandle_fini(int close_status) + { + if (sehandle) { +@@ -47,7 +52,7 @@ static rpmRC sehandle_init(int open_status) + + sehandle = selabel_open(SELABEL_CTX_FILE, opts, 1); + +- rpmlog(RPMLOG_DEBUG, "selabel_open: (%s) %s\n", ++ rpmlog(loglvl(sehandle == NULL), "selabel_open: (%s) %s\n", + path, (sehandle == NULL ? strerror(errno) : "")); + + return (sehandle != NULL) ? RPMRC_OK : RPMRC_FAIL; +@@ -125,10 +130,8 @@ static rpmRC selinux_scriptlet_fork_post(rpmPlugin plugin, + if ((xx = setexeccon(newcon)) == 0) + rc = RPMRC_OK; + +- if (rpmIsDebug()) { +- rpmlog(RPMLOG_DEBUG, "setexeccon: (%s, %s) %s\n", ++ rpmlog(loglvl(xx < 0), "setexeccon: (%s, %s) %s\n", + path, newcon, (xx < 0 ? strerror(errno) : "")); +- } + + exit: + context_free(con); +@@ -143,10 +146,8 @@ exit: + if ((xx = setexecfilecon(path, "rpm_script_t") == 0)) + rc = RPMRC_OK; + +- if (rpmIsDebug()) { +- rpmlog(RPMLOG_DEBUG, "setexecfilecon: (%s) %s\n", ++ rpmlog(loglvl(xx < 0), "setexecfilecon: (%s) %s\n", + path, (xx < 0 ? strerror(errno) : "")); +- } + #endif + /* If selinux is not enforcing, we don't care either */ + if (rc && security_getenforce() < 1) +@@ -167,10 +168,8 @@ static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + if (selabel_lookup_raw(sehandle, &scon, dest, file_mode) == 0) { + int conrc = lsetfilecon(path, scon); + +- if (rpmIsDebug()) { +- rpmlog(RPMLOG_DEBUG, "lsetfilecon: (%s, %s) %s\n", ++ rpmlog(loglvl(conrc < 0), "lsetfilecon: (%s, %s) %s\n", + path, scon, (conrc < 0 ? strerror(errno) : "")); +- } + + if (conrc == 0 || (conrc < 0 && errno == EOPNOTSUPP)) + rc = RPMRC_OK; +-- +2.20.1 + diff --git a/SOURCES/0001-Make-rpmsign-exit-values-more-consistent-with-our-ot.patch b/SOURCES/0001-Make-rpmsign-exit-values-more-consistent-with-our-ot.patch new file mode 100644 index 0000000..c186017 --- /dev/null +++ b/SOURCES/0001-Make-rpmsign-exit-values-more-consistent-with-our-ot.patch @@ -0,0 +1,49 @@ +From 2ec0832287bd1443ebf336f8a98293f30bfa2036 Mon Sep 17 00:00:00 2001 +Message-Id: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Mon, 18 Mar 2019 15:24:54 +0200 +Subject: [PATCH 1/3] Make rpmsign exit values more consistent with our other + tools + +rpmPkgSign*() return -1 for failure, which is not that helpful when +returned to shell and the way it was counted could easily wrap around +when signing multiple packages. Return number of failures similarly to +how rpm -q and frieds does, avoid overflows and xargs special value 255. +--- + rpmsign.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/rpmsign.c b/rpmsign.c +index ae86f666d..1a5cd59c2 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -134,7 +134,8 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + const char *arg; + rc = 0; + while ((arg = poptGetArg(optCon)) != NULL) { +- rc += rpmPkgSign(arg, sargs); ++ if (rpmPkgSign(arg, sargs) < 0) ++ rc++; + } + + exit: +@@ -175,7 +176,8 @@ int main(int argc, char *argv[]) + case MODE_DELSIGN: + ec = 0; + while ((arg = poptGetArg(optCon)) != NULL) { +- ec += rpmPkgDelSign(arg, &sargs); ++ if (rpmPkgDelSign(arg, &sargs) < 0) ++ ec++; + } + break; + case MODE_NONE: +@@ -188,5 +190,5 @@ int main(int argc, char *argv[]) + + exit: + rpmcliFini(optCon); +- return ec; ++ return RETVAL(ec); + } +-- +2.20.1 + diff --git a/SOURCES/0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch b/SOURCES/0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch new file mode 100644 index 0000000..6df9fab --- /dev/null +++ b/SOURCES/0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch @@ -0,0 +1,89 @@ +From 13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4 Mon Sep 17 00:00:00 2001 +Message-Id: <13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4.1554886141.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Wed, 10 Apr 2019 11:24:44 +0300 +Subject: [PATCH] Monkey-patch .decode() method to our strings as a temporary + compat crutch + +As a temporary crutch to support faster deployment of the sane +string behavior on python3, monkey-patch a decode method into all +strings we return. This seems to be enough to fix practically all +API users who have already adapted to the long-standing broken API +on Python 3. API users compatible with both Python 2 and 3 never needed +this anyway. Issue a warning with pointer to the relevant bug when the +fake decode() method is used to alert users to the issue. + +This is certainly an evil thing to do and will be removed as soon as +the critical users have been fixed to work with the new, corrected +behavior. +--- + python/rpm/__init__.py | 3 +++ + python/rpmmodule.c | 1 + + python/rpmsystem-py.h | 22 ++++++++++++++++++++-- + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/python/rpm/__init__.py b/python/rpm/__init__.py +index 54728bbd4..6d69eda7b 100644 +--- a/python/rpm/__init__.py ++++ b/python/rpm/__init__.py +@@ -61,6 +61,9 @@ except ImportError: + # backwards compatibility + give the same class both ways + ts = TransactionSet + ++def _fakedecode(self, encoding='utf-8', errors='strict'): ++ warnings.warn("decode() called on unicode string, see https://bugzilla.redhat.com/show_bug.cgi?id=1693751", UnicodeWarning, stacklevel=2) ++ return self + + def headerLoad(*args, **kwds): + """DEPRECATED! Use rpm.hdr() instead.""" +diff --git a/python/rpmmodule.c b/python/rpmmodule.c +index 05032edc7..2a76cfbd0 100644 +--- a/python/rpmmodule.c ++++ b/python/rpmmodule.c +@@ -28,6 +28,7 @@ + */ + + PyObject * pyrpmError; ++PyObject * fakedecode = NULL; + + static PyObject * archScore(PyObject * self, PyObject * arg) + { +diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h +index 25938464a..803da0fc1 100644 +--- a/python/rpmsystem-py.h ++++ b/python/rpmsystem-py.h +@@ -19,12 +19,29 @@ + #define PyInt_AsSsize_t PyLong_AsSsize_t + #endif + ++PyObject * fakedecode; ++ + static inline PyObject * utf8FromString(const char *s) + { + /* In Python 3, we return all strings as surrogate-escaped utf-8 */ + #if PY_MAJOR_VERSION >= 3 +- if (s != NULL) +- return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape"); ++ if (s != NULL) { ++ PyObject *o = PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape"); ++ /* fish the fake decode function from python side if not done yet */ ++ if (fakedecode == NULL) { ++ PyObject *n = PyUnicode_FromString("rpm"); ++ PyObject *m = PyImport_Import(n); ++ PyObject *md = PyModule_GetDict(m); ++ fakedecode = PyDict_GetItemString(md, "_fakedecode"); ++ Py_DECREF(m); ++ Py_DECREF(n); ++ } ++ if (fakedecode && o) { ++ /* monkey-patch it into the string object as "decode" */ ++ PyDict_SetItemString(Py_TYPE(o)->tp_dict, "decode", fakedecode); ++ } ++ return o; ++ } + #else + if (s != NULL) + return PyBytes_FromString(s); +-- +2.20.1 + 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 new file mode 100644 index 0000000..6da9775 --- /dev/null +++ b/SOURCES/0001-Only-read-through-payload-on-verify-if-actually-need.patch @@ -0,0 +1,80 @@ +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; +diff --git a/lib/rpmvs.h b/lib/rpmvs.h +index b27d9a612..a836d5c94 100644 +--- a/lib/rpmvs.h ++++ b/lib/rpmvs.h +@@ -75,6 +75,9 @@ void rpmvsInitRange(struct rpmvs_s *sis, int range); + RPM_GNUC_INTERNAL + void rpmvsFiniRange(struct rpmvs_s *sis, int range); + ++RPM_GNUC_INTERNAL ++int rpmvsRange(struct rpmvs_s *vs); ++ + RPM_GNUC_INTERNAL + int rpmvsVerify(struct rpmvs_s *sis, int type, + rpmsinfoCb cb, void *cbdata); +-- +2.20.1 + diff --git a/SOURCES/0001-Remove-capabilities-instead-of-setting-empty-caps-vi.patch b/SOURCES/0001-Remove-capabilities-instead-of-setting-empty-caps-vi.patch new file mode 100644 index 0000000..23ddb28 --- /dev/null +++ b/SOURCES/0001-Remove-capabilities-instead-of-setting-empty-caps-vi.patch @@ -0,0 +1,49 @@ +From b4178c979fff344a1c5142a305f274dd9aff8f45 Mon Sep 17 00:00:00 2001 +From: Markus Linnala +Date: Sun, 28 Oct 2018 14:59:52 +0200 +Subject: [PATCH] Remove capabilities instead of setting empty caps via. + --setcaps + +If a file in a package does not have any capabilities rpm --setcaps should +remove capabilities of the file. Prior to this patch capabilities of the file +were set as empty. + +Empty capabilities mean more than no capabilities. A file with no capabilities +can inherit capabilities, but file with empty capabilities can not. + +When ever package does not have any capabilities set %|FILECAPS? is false. +If some files have capabilities, %|FILECAPS? is true but %{FILECAPS} is '' +when the file does not have capabilities and '= ' when there is some. + +Reported and patch created by Markus Linnala +Commit message edited by Pavlina Moravcova Varekova and Florian Festi. + +Fixes #585 +Fixes #586 +--- + rpmpopt.in | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/rpmpopt.in b/rpmpopt.in +index 42d3416a3..557050a24 100644 +--- a/rpmpopt.in ++++ b/rpmpopt.in +@@ -57,8 +57,13 @@ rpm alias --setugids -q --qf \ + --POPTdesc=$"set user/group ownership of files in a package" + + rpm alias --setcaps -q --qf \ +- "[\[ -f %{FILENAMES:shescape} -a ! -L %{FILENAMES:shescape} \] \ +- && setcap %|FILECAPS?{%{FILECAPS:shescape}}:{''}| %{FILENAMES:shescape}\n]" \ ++ "[if \[ -f %{FILENAMES:shescape} -a ! -L %{FILENAMES:shescape} \]; then\n\ ++%|FILECAPS?{ if \[ -n %{FILECAPS:shescape} \]; then\n\ ++ setcap %{FILECAPS:shescape} %{FILENAMES:shescape}\n\ ++ el}:{ }|if \[ -n \"\$(getcap %{FILENAMES:shescape})\" \]; then\n\ ++ setcap -r %{FILENAMES:shescape}\n\ ++ fi\n\ ++fi\n]" \ + --pipe "sh" \ + --POPTdesc=$"set capabilities of files in a package" + +-- +2.21.0 + diff --git a/SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch b/SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch new file mode 100644 index 0000000..e91db6f --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Show-list-of-files-only-once-when-use-rpm-ql-and-mul.patch b/SOURCES/0001-Show-list-of-files-only-once-when-use-rpm-ql-and-mul.patch new file mode 100644 index 0000000..863ac43 --- /dev/null +++ b/SOURCES/0001-Show-list-of-files-only-once-when-use-rpm-ql-and-mul.patch @@ -0,0 +1,57 @@ +From 8dd8e37acc79da1ce0a36c3f86650defa474a6a9 Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Thu, 14 Mar 2019 13:56:26 +0100 +Subject: [PATCH] Show list of files only once when use rpm -ql and multiple + rpm files + +--- + lib/query.c | 3 ++- + tests/rpmquery.at | 18 ++++++++++++++++++ + 2 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/lib/query.c b/lib/query.c +index e5408e211..7568f67aa 100644 +--- a/lib/query.c ++++ b/lib/query.c +@@ -574,7 +574,8 @@ int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv) + if (mi == NULL && qva->qva_source == RPMQV_PACKAGE) { + size_t l = strlen(*arg); + if (l > 4 && !strcmp(*arg + l - 4, ".rpm")) { +- rpmgi gi = rpmgiNew(ts, giFlags, argv); ++ char * const argFirst[2] = { arg[0], NULL }; ++ rpmgi gi = rpmgiNew(ts, giFlags, argFirst); + ecLocal = rpmgiShowMatches(qva, ts, gi); + rpmgiFree(gi); + } +diff --git a/tests/rpmquery.at b/tests/rpmquery.at +index ab7bb3c46..0dc6d78b6 100644 +--- a/tests/rpmquery.at ++++ b/tests/rpmquery.at +@@ -61,6 +61,24 @@ hello.spec + [ignore]) + AT_CLEANUP + ++# ------------------------------ ++AT_SETUP([rpm -ql multiple *.rpm]) ++AT_KEYWORDS([query]) ++AT_CHECK([ ++runroot rpm \ ++ -ql \ ++ /data/SRPMS/hello-1.0-1.src.rpm /data/RPMS/hello-1.0-1.i386.rpm ++], ++[0], ++[hello-1.0.tar.gz ++hello.spec ++/usr/local/bin/hello ++/usr/share/doc/hello-1.0 ++/usr/share/doc/hello-1.0/FAQ ++], ++[ignore]) ++AT_CLEANUP ++ + # ------------------------------ + AT_SETUP([rpmspec -q]) + AT_KEYWORDS([query]) +-- +2.17.2 + diff --git a/SOURCES/0001-Sort-list-of-hard-linked-files-in-find-debuginfo.sh-.patch b/SOURCES/0001-Sort-list-of-hard-linked-files-in-find-debuginfo.sh-.patch new file mode 100644 index 0000000..ae7d4e0 --- /dev/null +++ b/SOURCES/0001-Sort-list-of-hard-linked-files-in-find-debuginfo.sh-.patch @@ -0,0 +1,27 @@ +From 35b09eed946a7e2f2f327531b692c9f768bf9e3b Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Sun, 7 Apr 2019 07:23:47 +0200 +Subject: [PATCH] Sort list of hard linked files in find-debuginfo.sh + (RhBug:1421272) + +It helps to make build results reproducible. Based on Mark Wielaard's idea. +--- + 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 c75d176ac..23286139e 100755 +--- a/scripts/find-debuginfo.sh ++++ b/scripts/find-debuginfo.sh +@@ -350,7 +350,7 @@ trap 'rm -rf "$temp"' EXIT + touch "$temp/primary" + find "$RPM_BUILD_ROOT" ! -path "${debugdir}/*.debug" -type f \ + \( -perm -0100 -or -perm -0010 -or -perm -0001 \) \ +- -print | ++ -print | LC_ALL=C sort | + file -N -f - | sed -n -e 's/^\(.*\):[ ]*.*ELF.*, not stripped.*/\1/p' | + xargs --no-run-if-empty stat -c '%h %D_%i %n' | + while read nlinks inum f; do +-- +2.17.2 + diff --git a/SOURCES/0001-Use-dpbath-only-with-full-path-RhBug-1696408.patch b/SOURCES/0001-Use-dpbath-only-with-full-path-RhBug-1696408.patch new file mode 100644 index 0000000..f753e38 --- /dev/null +++ b/SOURCES/0001-Use-dpbath-only-with-full-path-RhBug-1696408.patch @@ -0,0 +1,29 @@ +From d313baf1d3a4756447e398ee55f8c6760f942d50 Mon Sep 17 00:00:00 2001 +From: Pavlina Moravcova Varekova +Date: Wed, 24 Apr 2019 10:29:14 +0200 +Subject: [PATCH] Use --dpbath only with full path (RhBug:1696408) + +Before the patch rpm treats the relative path as a full path. +The new behavior is similar to the "--root" option. +--- + lib/poptALL.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/poptALL.c b/lib/poptALL.c +index 9983c1e62..69fd49846 100644 +--- a/lib/poptALL.c ++++ b/lib/poptALL.c +@@ -147,6 +147,10 @@ static void rpmcliAllArgCallback( poptContext con, + break; + case POPT_DBPATH: + rpmcliConfigured(); ++ if (arg && arg[0] != '/') { ++ fprintf(stderr, _("arguments to --dbpath must begin with '/'\n")); ++ exit(EXIT_FAILURE); ++ } + rpmPushMacro(NULL, "_dbpath", NULL, arg, RMIL_CMDLINE); + break; + case POPT_SHOWVERSION: +-- +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 new file mode 100644 index 0000000..6053ca2 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-rpmsign-man-page-Add-line-about-rpmsign-requiring-a-.patch b/SOURCES/0001-rpmsign-man-page-Add-line-about-rpmsign-requiring-a-.patch new file mode 100644 index 0000000..8ddd2a3 --- /dev/null +++ b/SOURCES/0001-rpmsign-man-page-Add-line-about-rpmsign-requiring-a-.patch @@ -0,0 +1,28 @@ +From be3347b5bff6142e86e533174fe0ec352405d159 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Thu, 18 Jul 2019 07:45:53 +0200 +Subject: [PATCH] rpmsign man page: Add line about rpmsign requiring a valid + checksum + +and the limitations in FIPS mode +--- + doc/rpmsign.8 | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 +index 80ffb6a32..d895a3b8c 100644 +--- a/doc/rpmsign.8 ++++ b/doc/rpmsign.8 +@@ -21,6 +21,9 @@ options generate and insert new signatures for each package + existing signatures. There are two options for historical reasons, + there is no difference in behavior currently. + ++To create a signature rpm needs to verify the package's checksum. As a result ++packages with a MD5/SHA1 checksums cannot be signed in FIPS mode. ++ + \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR + + .PP +-- +2.21.0 + diff --git a/SOURCES/0002-Drop-internal-only-visibility-on-rpmvs-related-API.patch b/SOURCES/0002-Drop-internal-only-visibility-on-rpmvs-related-API.patch new file mode 100644 index 0000000..e2212eb --- /dev/null +++ b/SOURCES/0002-Drop-internal-only-visibility-on-rpmvs-related-API.patch @@ -0,0 +1,64 @@ +From 3fd79a5564df97d512be283c5c8a4da2e7ef8bce Mon Sep 17 00:00:00 2001 +Message-Id: <3fd79a5564df97d512be283c5c8a4da2e7ef8bce.1554983206.git.pmatilai@redhat.com> +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:29:18 +0200 +Subject: [PATCH 2/3] Drop internal-only visibility on rpmvs-related API + +Makes it possible to use rpmvs API from eg librpmsign which we'll +need in the next commit. We need to make select parts of this +actually public eventually but for now... +--- + lib/rpmvs.h | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/lib/rpmvs.h b/lib/rpmvs.h +index a836d5c94..025895500 100644 +--- a/lib/rpmvs.h ++++ b/lib/rpmvs.h +@@ -48,41 +48,29 @@ typedef int (*rpmsinfoCb)(struct rpmsinfo_s *sinfo, void *cbdata); + extern "C" { + #endif + +-RPM_GNUC_INTERNAL + const char *rpmsinfoDescr(struct rpmsinfo_s *sinfo); + +-RPM_GNUC_INTERNAL + char *rpmsinfoMsg(struct rpmsinfo_s *sinfo); + +-RPM_GNUC_INTERNAL + struct rpmvs_s *rpmvsCreate(int vfylevel, rpmVSFlags vsflags, rpmKeyring keyring); + +-RPM_GNUC_INTERNAL + void rpmvsInit(struct rpmvs_s *vs, hdrblob blob, rpmDigestBundle bundle); + +-RPM_GNUC_INTERNAL + rpmVSFlags rpmvsFlags(struct rpmvs_s *vs); + +-RPM_GNUC_INTERNAL + struct rpmvs_s *rpmvsFree(struct rpmvs_s *sis); + +-RPM_GNUC_INTERNAL + void rpmvsAppendTag(struct rpmvs_s *sis, hdrblob blob, rpmTagVal tag); + +-RPM_GNUC_INTERNAL + void rpmvsInitRange(struct rpmvs_s *sis, int range); + +-RPM_GNUC_INTERNAL + void rpmvsFiniRange(struct rpmvs_s *sis, int range); + +-RPM_GNUC_INTERNAL + int rpmvsRange(struct rpmvs_s *vs); + +-RPM_GNUC_INTERNAL + int rpmvsVerify(struct rpmvs_s *sis, int type, + rpmsinfoCb cb, void *cbdata); + +-RPM_GNUC_INTERNAL + rpmRC rpmpkgRead(struct rpmvs_s *vs, FD_t fd, + hdrblob *sigblobp, hdrblob *blobp, char **emsg); + +-- +2.20.1 + diff --git a/SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch b/SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch new file mode 100644 index 0000000..c950748 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.2-unversioned-python.patch b/SOURCES/rpm-4.14.2-unversioned-python.patch new file mode 100644 index 0000000..7e9ba8d --- /dev/null +++ b/SOURCES/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/SPECS/rpm.spec b/SPECS/rpm.spec index d5455fe..9675ce1 100644 --- a/SPECS/rpm.spec +++ b/SPECS/rpm.spec @@ -30,7 +30,7 @@ %global rpmver 4.14.2 #global snapver rc2 -%global rel 11 +%global rel 25 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -77,8 +77,35 @@ Patch101: rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch Patch102: 0001-Document-noverify-in-the-man-page-RhBug-1646458.patch Patch103: 0001-Handle-unsupported-digests-the-same-as-disabled-ones.patch Patch104: 0001-Mark-elements-with-associated-problems-as-failed.patch -Patch105: 0001-Fix-packages-getting-erased-on-failed-update-with-dn.patch -Patch106: 0001-Fix-off-by-one-in-hdrblobGet-making-last-entry-unrea.patch +Patch105: 0001-Fix-ancient-python-GIL-locking-bug-on-callback-RhBug.patch +Patch106: 0001-Fix-testing-for-wrong-variable-in-selinux-plugin-deb.patch +Patch107: 0001-Log-RPMLOG_ERR-level-messages-on-actual-errors-in-se.patch +Patch108: 0001-Only-read-through-payload-on-verify-if-actually-need.patch +Patch109: 0001-Make-rpmsign-exit-values-more-consistent-with-our-ot.patch +Patch110: 0002-Drop-internal-only-visibility-on-rpmvs-related-API.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 +Patch113: 0001-Sort-list-of-hard-linked-files-in-find-debuginfo.sh-.patch +Patch114: 0001-Correct-rpm-ql-exit-value-when-optional-p-is-omitted.patch +Patch115: 0001-Show-list-of-files-only-once-when-use-rpm-ql-and-mul.patch +Patch116: 0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch +Patch117: 0001-Fix-segfault-on-fingerprinting-symlink-round-RhBug-1.patch +Patch118: 0001-Fix-packages-getting-erased-on-failed-update-with-dn.patch +Patch119: 0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch +Patch120: 0001-rpmsign-man-page-Add-line-about-rpmsign-requiring-a-.patch +Patch121: 0001-Use-dpbath-only-with-full-path-RhBug-1696408.patch +Patch122: 0001-Fix-a-blindingly-obvious-memleak-in-package-verify-s.patch +Patch123: 0001-Fix-rpmfiles-memory-leak-on-postuntrans-file-trigger.patch +Patch124: 0001-Fully-shutdown-DBUS-on-systemd_inhibit-cleanup-RhBug.patch +Patch125: 0001-Remove-capabilities-instead-of-setting-empty-caps-vi.patch +Patch126: 0001-Fix-off-by-one-in-hdrblobGet-making-last-entry-unrea.patch +Patch127: 0001-Fix-memleak-during-transaction-verify-step-in-the-NO.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 +# Temporary compat crutch, not upstream +Patch502: 0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch # These are not yet upstream # Audit support @@ -96,6 +123,8 @@ 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 # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -618,11 +647,60 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog -* Fri Aug 16 2019 Panu Matilainen - 4.14.2-11 -- Fix off-by-one in hdrblobGet() breaking large package verification (#1736821) +* Wed Aug 07 2019 Florian Festi - 4.14.2-25 +- Fix memory leak in verify code (#1714657) -* Wed Jun 12 2019 Panu Matilainen - 4.14.2-10 -- Fix packages getting removed on failed update via dnf (#1718236) +* 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)