From f35ca8f4b60b2563e88240d9f1db60e64a2f1f97 Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Fri, 29 Mar 2024 16:27:43 +0300 Subject: [PATCH] import rpm-4.14.3-31.el8 --- .gitignore | 1 + .rpm.metadata | 1 + ...strip-g-instead-of-full-strip-on-DSO.patch | 93 + .../0001-Add-limits-to-autopatch-macro.patch | 44 + ...lback-on-directory-changes-during-rp.patch | 107 + ...0001-Always-close-libelf-handle-1313.patch | 32 + ...verify-in-the-man-page-RhBug-1646458.patch | 37 + ...-missing-user-group-on-skipped-files.patch | 30 + ...nate-code-duplication-from-rpmfiNext.patch | 35 + ...for-file-disposition-diagnostics-on-.patch | 66 + ...files-with-suid-sgid-bits-and-or-cap.patch | 152 ++ ...brp-strip-static-archive-parallelism.patch | 41 + ...dErase-not-raising-exception-on-not-.patch | 102 + ...ource-leaks-on-zstd-open-error-paths.patch | 50 + ...-code-on-O_DIRECTORY-open-of-invalid.patch | 46 + ...ON-from-configure-when-running-tests.patch | 53 + ...rn-all-our-string-data-as-surrogate-.patch | 656 +++++ ...nums-and-source_nums-Lua-variables-i.patch | 63 + ...ild_ncpus-and-use-it-for-_smp_mflags.patch | 41 + ...root-check-the-build-files-in-parall.patch | 31 + ...s-with-associated-problems-as-failed.patch | 28 + ...h-payload-on-verify-if-actually-need.patch | 76 + ...ass-RPM_BUILD_NCPUS-to-build-scripts.patch | 27 + ...ptor-to-file-prepare-plugin-hook-use.patch | 153 ++ ...rint-full-path-if-file-removal-fails.patch | 32 + ...L-string-as-None-from-utf8FromString.patch | 41 + ...fd-basename-based-operation-within-t.patch | 90 + ...Unblock-signals-in-forked-scriptlets.patch | 37 + ...LD_NCPUS-in-brp-strip-static-archive.patch | 58 + ...Use-file-state-machine-from-rpm-4.19.patch | 1654 +++++++++++ ...-to-avoid-sub-processes-in-find-debu.patch | 29 + ...-delimiter-to-avoid-xargs-messing-up.patch | 26 + ...same-thing-more-than-once-use-a-loop.patch | 38 + ...y-signature-region-preventing-resign.patch | 44 + ...or-reading-writing-of-relocated-valu.patch | 490 ++++ ...002-Handle-.debug_macro-in-debugedit.patch | 304 +++ ...compatible-exception-syntax-in-tests.patch | 77 + ...tes-vs-strings-issues-in-Python-test.patch | 44 + ...ackages-before-signing-RhBug-1646388.patch | 114 + ...ure-.debug_line-old-new-idx-start-eq.patch | 30 + ...um-Python-version-requirement-to-2.7.patch | 109 + ...ary-Python-2-vs-3-incompatibility-fr.patch | 41 + ...ompile-compatibility-with-newer-pyth.patch | 46 + ...latform-Python-binary-where-relevant.patch | 26 + SOURCES/disable-python-extra.patch | 11 + SOURCES/rpm-4-14.3-selinux-log-error.patch | 11 + SOURCES/rpm-4.11.x-siteconfig.patch | 12 + SOURCES/rpm-4.12.0-rpm2cpio-hack.patch | 18 + SOURCES/rpm-4.13.0-fedora-specspo.patch | 95 + SOURCES/rpm-4.13.90-ldflags.patch | 16 + ...hat-will-be-present-during-RPM-build.patch | 28 + .../rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch | 107 + SOURCES/rpm-4.14.2-audit-3.patch | 275 ++ SOURCES/rpm-4.14.2-unversioned-python.patch | 12 + ...-files-strip-when-debuginfo-disabled.patch | 14 + ...PG-Switch-back-to-pipe-7-for-signing.patch | 186 ++ .../rpm-4.14.3-add-fapolicyd-rpm-plugin.patch | 378 +++ .../rpm-4.14.3-add-path-query-option.patch | 197 ++ ...4.3-add-read-only-support-for-sqlite.patch | 798 ++++++ ...he-limit-of-signature-header-to-64MB.patch | 12 + ...4.3-fapolicyd-make-write-nonblocking.patch | 167 ++ ...biguous-diagnostics-on-file-triggers.patch | 101 + ...ous-transfiletriggerpostun-execution.patch | 184 ++ ...-4.14.3-hdrblobInit-add-bounds-check.patch | 100 + SOURCES/rpm-4.14.3-imp-covscan-fixes.patch | 327 +++ ...roize-find-debuginfo-script-location.patch | 38 + ...rpm-4.14.3-more-careful-sig-hdr-copy.patch | 162 ++ SOURCES/rpm-4.14.3-python3.diff | 13 + ...4.14.3-rpm2archive-Don-t-print-usage.patch | 29 + ...rpm-4.14.3-rpm2archive-nocompression.patch | 138 + ....14.3-rpm2archive-parse-popt-options.patch | 36 + ...3-skip-recorded-symlinks-in-setperms.patch | 40 + ...date-and-require-subkey-binding-sigs.patch | 401 +++ ...-4.16.1.3-rpm2archive-error-handling.patch | 51 + SOURCES/rpm-4.7.1-geode-i686.patch | 14 + SOURCES/rpm-4.8.1-use-gpg2.patch | 12 + SOURCES/rpm-4.9.90-no-man-dirs.patch | 12 + SPECS/rpm.spec | 2425 +++++++++++++++++ 78 files changed, 11715 insertions(+) create mode 100644 .gitignore create mode 100644 .rpm.metadata create mode 100644 SOURCES/0001-Add-flag-to-use-strip-g-instead-of-full-strip-on-DSO.patch create mode 100644 SOURCES/0001-Add-limits-to-autopatch-macro.patch create mode 100644 SOURCES/0001-Add-optional-callback-on-directory-changes-during-rp.patch create mode 100644 SOURCES/0001-Always-close-libelf-handle-1313.patch create mode 100644 SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch create mode 100644 SOURCES/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch create mode 100644 SOURCES/0001-Eliminate-code-duplication-from-rpmfiNext.patch create mode 100644 SOURCES/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch create mode 100644 SOURCES/0001-Fix-FA_TOUCH-on-files-with-suid-sgid-bits-and-or-cap.patch create mode 100644 SOURCES/0001-Fix-brp-strip-static-archive-parallelism.patch create mode 100644 SOURCES/0001-Fix-python-ts.addErase-not-raising-exception-on-not-.patch create mode 100644 SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch create mode 100644 SOURCES/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch create mode 100644 SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch create mode 100644 SOURCES/0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch create mode 100644 SOURCES/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch create mode 100644 SOURCES/0001-Isolate-_smp_build_ncpus-and-use-it-for-_smp_mflags.patch create mode 100644 SOURCES/0001-Make-check-buildroot-check-the-build-files-in-parall.patch create mode 100644 SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch create mode 100644 SOURCES/0001-Only-read-through-payload-on-verify-if-actually-need.patch create mode 100644 SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch create mode 100644 SOURCES/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch create mode 100644 SOURCES/0001-Print-full-path-if-file-removal-fails.patch create mode 100644 SOURCES/0001-Return-NULL-string-as-None-from-utf8FromString.patch create mode 100644 SOURCES/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch create mode 100644 SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch create mode 100644 SOURCES/0001-Use-RPM_BUILD_NCPUS-in-brp-strip-static-archive.patch create mode 100644 SOURCES/0001-Use-file-state-machine-from-rpm-4.19.patch create mode 100644 SOURCES/0001-Use-in-condition-to-avoid-sub-processes-in-find-debu.patch create mode 100644 SOURCES/0001-Use-newline-as-a-delimiter-to-avoid-xargs-messing-up.patch create mode 100644 SOURCES/0001-When-doing-the-same-thing-more-than-once-use-a-loop.patch create mode 100644 SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch create mode 100644 SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch create mode 100644 SOURCES/0002-Handle-.debug_macro-in-debugedit.patch create mode 100644 SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch create mode 100644 SOURCES/0003-Fix-couple-of-bytes-vs-strings-issues-in-Python-test.patch create mode 100644 SOURCES/0003-Verify-packages-before-signing-RhBug-1646388.patch create mode 100644 SOURCES/0003-debugedit-Make-sure-.debug_line-old-new-idx-start-eq.patch create mode 100644 SOURCES/0004-Bump-the-minimum-Python-version-requirement-to-2.7.patch create mode 100644 SOURCES/0005-Drop-an-unnecessary-Python-2-vs-3-incompatibility-fr.patch create mode 100644 SOURCES/brp-python-bytecompile-compatibility-with-newer-pyth.patch create mode 100644 SOURCES/compile-with-Platform-Python-binary-where-relevant.patch create mode 100644 SOURCES/disable-python-extra.patch create mode 100644 SOURCES/rpm-4-14.3-selinux-log-error.patch create mode 100644 SOURCES/rpm-4.11.x-siteconfig.patch create mode 100644 SOURCES/rpm-4.12.0-rpm2cpio-hack.patch create mode 100644 SOURCES/rpm-4.13.0-fedora-specspo.patch create mode 100644 SOURCES/rpm-4.13.90-ldflags.patch create mode 100644 SOURCES/rpm-4.14.1-Add-envvar-that-will-be-present-during-RPM-build.patch create mode 100644 SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch create mode 100644 SOURCES/rpm-4.14.2-audit-3.patch create mode 100644 SOURCES/rpm-4.14.2-unversioned-python.patch create mode 100644 SOURCES/rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch create mode 100644 SOURCES/rpm-4.14.3-GPG-Switch-back-to-pipe-7-for-signing.patch create mode 100644 SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch create mode 100644 SOURCES/rpm-4.14.3-add-path-query-option.patch create mode 100644 SOURCES/rpm-4.14.3-add-read-only-support-for-sqlite.patch create mode 100644 SOURCES/rpm-4.14.3-bump-up-the-limit-of-signature-header-to-64MB.patch create mode 100644 SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch create mode 100644 SOURCES/rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch create mode 100644 SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch create mode 100644 SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch create mode 100644 SOURCES/rpm-4.14.3-imp-covscan-fixes.patch create mode 100644 SOURCES/rpm-4.14.3-macroize-find-debuginfo-script-location.patch create mode 100644 SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch create mode 100644 SOURCES/rpm-4.14.3-python3.diff create mode 100644 SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch create mode 100644 SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch create mode 100644 SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch create mode 100644 SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch create mode 100644 SOURCES/rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch create mode 100644 SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch create mode 100644 SOURCES/rpm-4.7.1-geode-i686.patch create mode 100644 SOURCES/rpm-4.8.1-use-gpg2.patch create mode 100644 SOURCES/rpm-4.9.90-no-man-dirs.patch create mode 100644 SPECS/rpm.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f8a22a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/rpm-4.14.3.tar.bz2 diff --git a/.rpm.metadata b/.rpm.metadata new file mode 100644 index 0000000..4c84542 --- /dev/null +++ b/.rpm.metadata @@ -0,0 +1 @@ +3f8c3ef08f93eaeef12008055a43f6872306f8a2 SOURCES/rpm-4.14.3.tar.bz2 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..5601c58 --- /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 + } +@@ -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 new file mode 100644 index 0000000..3235922 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Add-optional-callback-on-directory-changes-during-rp.patch b/SOURCES/0001-Add-optional-callback-on-directory-changes-during-rp.patch new file mode 100644 index 0000000..bda7110 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Always-close-libelf-handle-1313.patch b/SOURCES/0001-Always-close-libelf-handle-1313.patch new file mode 100644 index 0000000..81a1296 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch b/SOURCES/0001-Document-noverify-in-the-man-page-RhBug-1646458.patch new file mode 100644 index 0000000..df0aaab --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch b/SOURCES/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch new file mode 100644 index 0000000..f910f38 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Eliminate-code-duplication-from-rpmfiNext.patch b/SOURCES/0001-Eliminate-code-duplication-from-rpmfiNext.patch new file mode 100644 index 0000000..a5e0463 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch b/SOURCES/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch new file mode 100644 index 0000000..29fb473 --- /dev/null +++ b/SOURCES/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/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-brp-strip-static-archive-parallelism.patch b/SOURCES/0001-Fix-brp-strip-static-archive-parallelism.patch new file mode 100644 index 0000000..a1583f9 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..809f065 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch b/SOURCES/0001-Fix-resource-leaks-on-zstd-open-error-paths.patch new file mode 100644 index 0000000..b3c2f4b --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch b/SOURCES/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch new file mode 100644 index 0000000..1d73765 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch b/SOURCES/0001-Honor-PYTHON-from-configure-when-running-tests.patch new file mode 100644 index 0000000..b39c52b --- /dev/null +++ b/SOURCES/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/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-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch b/SOURCES/0001-Introduce-patch_nums-and-source_nums-Lua-variables-i.patch new file mode 100644 index 0000000..ccf39e3 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..a95ea7c --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..bba479b --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch b/SOURCES/0001-Mark-elements-with-associated-problems-as-failed.patch new file mode 100644 index 0000000..320385d --- /dev/null +++ b/SOURCES/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/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..f77c039 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch b/SOURCES/0001-Pass-RPM_BUILD_NCPUS-to-build-scripts.patch new file mode 100644 index 0000000..0e28f75 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/SOURCES/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch new file mode 100644 index 0000000..51ecf97 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Print-full-path-if-file-removal-fails.patch b/SOURCES/0001-Print-full-path-if-file-removal-fails.patch new file mode 100644 index 0000000..266bd69 --- /dev/null +++ b/SOURCES/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/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-Swap-over-to-dirfd-basename-based-operation-within-t.patch b/SOURCES/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch new file mode 100644 index 0000000..3210c07 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch b/SOURCES/0001-Unblock-signals-in-forked-scriptlets.patch new file mode 100644 index 0000000..fb1e8d4 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..2863a98 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Use-file-state-machine-from-rpm-4.19.patch b/SOURCES/0001-Use-file-state-machine-from-rpm-4.19.patch new file mode 100644 index 0000000..5b6653e --- /dev/null +++ b/SOURCES/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/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-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 new file mode 100644 index 0000000..14cf5d2 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..9e9ee45 --- /dev/null +++ b/SOURCES/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/SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch b/SOURCES/0001-Work-around-buggy-signature-region-preventing-resign.patch new file mode 100644 index 0000000..54dd45f --- /dev/null +++ b/SOURCES/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/SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch b/SOURCES/0001-debugedit-Refactor-reading-writing-of-relocated-valu.patch new file mode 100644 index 0000000..ac45734 --- /dev/null +++ b/SOURCES/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/SOURCES/0002-Handle-.debug_macro-in-debugedit.patch b/SOURCES/0002-Handle-.debug_macro-in-debugedit.patch new file mode 100644 index 0000000..368beb8 --- /dev/null +++ b/SOURCES/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/SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch b/SOURCES/0002-Use-Python-3-compatible-exception-syntax-in-tests.patch new file mode 100644 index 0000000..5b08ce7 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..713d336 --- /dev/null +++ b/SOURCES/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/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/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 new file mode 100644 index 0000000..5bdc8f0 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..7e31e41 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..fe0ffef --- /dev/null +++ b/SOURCES/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/SOURCES/brp-python-bytecompile-compatibility-with-newer-pyth.patch b/SOURCES/brp-python-bytecompile-compatibility-with-newer-pyth.patch new file mode 100644 index 0000000..ebe7230 --- /dev/null +++ b/SOURCES/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/SOURCES/compile-with-Platform-Python-binary-where-relevant.patch b/SOURCES/compile-with-Platform-Python-binary-where-relevant.patch new file mode 100644 index 0000000..7b0da28 --- /dev/null +++ b/SOURCES/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/SOURCES/disable-python-extra.patch b/SOURCES/disable-python-extra.patch new file mode 100644 index 0000000..8cb7595 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4-14.3-selinux-log-error.patch b/SOURCES/rpm-4-14.3-selinux-log-error.patch new file mode 100644 index 0000000..f16a908 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.11.x-siteconfig.patch b/SOURCES/rpm-4.11.x-siteconfig.patch new file mode 100644 index 0000000..f32f859 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.12.0-rpm2cpio-hack.patch b/SOURCES/rpm-4.12.0-rpm2cpio-hack.patch new file mode 100644 index 0000000..38c7dbd --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.13.0-fedora-specspo.patch b/SOURCES/rpm-4.13.0-fedora-specspo.patch new file mode 100644 index 0000000..64416c7 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.13.90-ldflags.patch b/SOURCES/rpm-4.13.90-ldflags.patch new file mode 100644 index 0000000..99152e8 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..361e1a4 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch b/SOURCES/rpm-4.14.2-RPMTAG_MODULARITYLABEL.patch new file mode 100644 index 0000000..4c7c52c --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.2-audit-3.patch b/SOURCES/rpm-4.14.2-audit-3.patch new file mode 100644 index 0000000..65a2b3f --- /dev/null +++ b/SOURCES/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/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/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 new file mode 100644 index 0000000..05ca170 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..8e4e835 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch b/SOURCES/rpm-4.14.3-add-fapolicyd-rpm-plugin.patch new file mode 100644 index 0000000..3a9e808 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-add-path-query-option.patch b/SOURCES/rpm-4.14.3-add-path-query-option.patch new file mode 100644 index 0000000..0504ec8 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..419d754 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..58606e9 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch b/SOURCES/rpm-4.14.3-fapolicyd-make-write-nonblocking.patch new file mode 100644 index 0000000..343bd02 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..48039c7 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch b/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch new file mode 100644 index 0000000..6b26ec5 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch b/SOURCES/rpm-4.14.3-hdrblobInit-add-bounds-check.patch new file mode 100644 index 0000000..8321161 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-imp-covscan-fixes.patch b/SOURCES/rpm-4.14.3-imp-covscan-fixes.patch new file mode 100644 index 0000000..679c474 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch b/SOURCES/rpm-4.14.3-more-careful-sig-hdr-copy.patch new file mode 100644 index 0000000..4a4f4ae --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-python3.diff b/SOURCES/rpm-4.14.3-python3.diff new file mode 100644 index 0000000..7ec81b5 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch b/SOURCES/rpm-4.14.3-rpm2archive-Don-t-print-usage.patch new file mode 100644 index 0000000..ff9d1a3 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch b/SOURCES/rpm-4.14.3-rpm2archive-nocompression.patch new file mode 100644 index 0000000..92c84ae --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch b/SOURCES/rpm-4.14.3-rpm2archive-parse-popt-options.patch new file mode 100644 index 0000000..0170c35 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch b/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch new file mode 100644 index 0000000..ee12010 --- /dev/null +++ b/SOURCES/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/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 new file mode 100644 index 0000000..7d4e85b --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch b/SOURCES/rpm-4.16.1.3-rpm2archive-error-handling.patch new file mode 100644 index 0000000..4a8a6f5 --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.7.1-geode-i686.patch b/SOURCES/rpm-4.7.1-geode-i686.patch new file mode 100644 index 0000000..2e8692a --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.8.1-use-gpg2.patch b/SOURCES/rpm-4.8.1-use-gpg2.patch new file mode 100644 index 0000000..61ef55e --- /dev/null +++ b/SOURCES/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/SOURCES/rpm-4.9.90-no-man-dirs.patch b/SOURCES/rpm-4.9.90-no-man-dirs.patch new file mode 100644 index 0000000..04f276a --- /dev/null +++ b/SOURCES/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/SPECS/rpm.spec b/SPECS/rpm.spec new file mode 100644 index 0000000..9b5c83e --- /dev/null +++ b/SPECS/rpm.spec @@ -0,0 +1,2425 @@ +# 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 +# build with new db format +%bcond_with 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 31 + +%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 +# 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 +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 +# 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 +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 + +%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 +%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} + +%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}. + +%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_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 + +%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* +%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 +* Fri Mar 29 2024 MSVSphere Packaging Team - 4.14.3-31 +- Rebuilt for MSVSphere 8.10 beta + +* 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 + +* 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 +- Make write() nonblocking in fapolicyd plugin (#2110787) + +* Tue Apr 05 2022 Michal Domonkos - 4.14.3-23 +- Fix minor ABI regression in rpmcli.h (#1940895) + +* Tue Feb 15 2022 Michal Domonkos - 4.14.3-22 +- Fix spurious %transfiletriggerpostun execution (#2023693) +- Skip recorded symlinks in --setperms (#1900662) + +* 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 + +* Wed Oct 06 2021 Michal Domonkos - 4.14.3-19 +- Unbreak in-tree kmod strip by reverting brp-strip fix (#1967291) + +* 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) + +* 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) + +* Thu May 27 2021 Michal Domonkos - 4.14.3-14 +- Be more careful about copying data from signature header (#1958477) +- Fixes CVE-2021-20271 + +* 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