diff --git a/SOURCES/0001-Improve-error-handling-on-keystore-load.patch b/SOURCES/0001-Improve-error-handling-on-keystore-load.patch new file mode 100644 index 0000000..8d16b69 --- /dev/null +++ b/SOURCES/0001-Improve-error-handling-on-keystore-load.patch @@ -0,0 +1,168 @@ +From 38ccf257f278e6b71f73dee9ccb568fe2ad3037a Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 31 Oct 2025 11:21:28 +0100 +Subject: [PATCH 1/2] Obtain nvr string only once, before the loop + +Refactor loadKeyringFromDB() a bit so that the nvr string can be reused +in multiple places. This will be handy in the next commit. + +No functional change. +--- + lib/rpmts.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/lib/rpmts.c b/lib/rpmts.c +index 69888acfc..ceb021789 100644 +--- a/lib/rpmts.c ++++ b/lib/rpmts.c +@@ -327,10 +327,12 @@ static int loadKeyringFromDB(rpmts ts) + while ((h = rpmdbNextIterator(mi)) != NULL) { + struct rpmtd_s pubkeys; + const char *key; ++ char *nvr; + + if (!headerGet(h, RPMTAG_PUBKEYS, &pubkeys, HEADERGET_MINMEM)) + continue; + ++ nvr = headerGetAsString(h, RPMTAG_NVR); + while ((key = rpmtdNextString(&pubkeys))) { + uint8_t *pkt; + size_t pktlen; +@@ -341,9 +343,7 @@ static int loadKeyringFromDB(rpmts ts) + rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount); + + if (rpmKeyringAddKey(ts->keyring, key) == 0) { +- char *nvr = headerGetAsString(h, RPMTAG_NVR); + rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", nvr); +- free(nvr); + nkeys++; + } + rpmPubkeyFree(key); +@@ -352,12 +352,10 @@ static int loadKeyringFromDB(rpmts ts) + rpmPubkey subkey = subkeys[i]; + + if (rpmKeyringAddKey(ts->keyring, subkey) == 0) { +- char *nvr = headerGetAsString(h, RPMTAG_NVR); + rpmlog(RPMLOG_DEBUG, + "added subkey %d of main key %s to keyring\n", + i, nvr); + +- free(nvr); + nkeys++; + } + rpmPubkeyFree(subkey); +@@ -367,6 +365,7 @@ static int loadKeyringFromDB(rpmts ts) + } + } + rpmtdFreeData(&pubkeys); ++ free(nvr); + } + rpmdbFreeIterator(mi); + +-- +2.51.1 + + +From c68a557146c594458fb00109863565651cbe8f0a Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 31 Oct 2025 14:17:25 +0100 +Subject: [PATCH 2/2] Improve error handling on keystore load + +Report a failure to load a key, but only as a non-fatal warning so that +other keys can still be loaded, if any. This behavior is in the spirit +of #3996, too. + +Only emit *one* warning in the keystore_rpmdb, to keep the (code) noise +down. This covers all three steps (rpmBase64Decode, rpmPubkeyNew and +rpmKeyringAddKey). We don't need to check if key is NULL since that's +handled by rpmKeyringAddKey() which returns immediately if that's the +case. + +In the other two backends, we already handle a failure to *read* a key, +so keep that and just add another warning for a failed addition. + +This would be difficult to test (especially in the rpmdb backend) so +skimping on that here. + +(backported from commit 75de4f3eb28c686e7f73b750ca116a8e57b7a690) +--- + lib/rpmts.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/lib/rpmts.c b/lib/rpmts.c +index ceb021789..f6fe38c7a 100644 +--- a/lib/rpmts.c ++++ b/lib/rpmts.c +@@ -281,6 +281,7 @@ static int loadKeyringFromFiles(rpmts ts) + } + + for (char **f = files; *f; f++) { ++ int rc = 1; + int subkeysCount, i; + rpmPubkey *subkeys; + rpmPubkey key = rpmPubkeyRead(*f); +@@ -289,7 +290,7 @@ static int loadKeyringFromFiles(rpmts ts) + rpmlog(RPMLOG_ERR, _("%s: reading of public key failed.\n"), *f); + continue; + } +- if (rpmKeyringAddKey(ts->keyring, key) == 0) { ++ if ((rc = rpmKeyringAddKey(ts->keyring, key)) == 0) { + nkeys++; + rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", *f); + } +@@ -305,10 +306,15 @@ static int loadKeyringFromFiles(rpmts ts) + i, *f); + + nkeys++; ++ } else { ++ rc = 1; + } + rpmPubkeyFree(subkey); + } + free(subkeys); ++ ++ if (rc) ++ rpmlog(RPMLOG_WARNING, _("Could not load key %s\n"), *f); + } + exit: + free(pkpath); +@@ -334,15 +340,16 @@ static int loadKeyringFromDB(rpmts ts) + + nvr = headerGetAsString(h, RPMTAG_NVR); + while ((key = rpmtdNextString(&pubkeys))) { ++ int rc = 1; + uint8_t *pkt; + size_t pktlen; + +- if (rpmBase64Decode(key, (void **) &pkt, &pktlen) == 0) { ++ if ((rc = rpmBase64Decode(key, (void **) &pkt, &pktlen)) == 0) { + rpmPubkey key = rpmPubkeyNew(pkt, pktlen); + int subkeysCount, i; + rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount); + +- if (rpmKeyringAddKey(ts->keyring, key) == 0) { ++ if ((rc = rpmKeyringAddKey(ts->keyring, key)) == 0) { + rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", nvr); + nkeys++; + } +@@ -357,12 +364,17 @@ static int loadKeyringFromDB(rpmts ts) + i, nvr); + + nkeys++; ++ } else { ++ rc = 1; + } + rpmPubkeyFree(subkey); + } + free(subkeys); + free(pkt); + } ++ ++ if (rc) ++ rpmlog(RPMLOG_WARNING, _("Could not load key %s\n"), nvr); + } + rpmtdFreeData(&pubkeys); + free(nvr); +-- +2.51.1 + diff --git a/SOURCES/0001-Sort-files-before-passing-to-file-attribute-dependen.patch b/SOURCES/0001-Sort-files-before-passing-to-file-attribute-dependen.patch new file mode 100644 index 0000000..0f4c312 --- /dev/null +++ b/SOURCES/0001-Sort-files-before-passing-to-file-attribute-dependen.patch @@ -0,0 +1,61 @@ +From 08d5e162c2ec3a415a5e657fd8b63f0cdf14ddd8 Mon Sep 17 00:00:00 2001 +From: Chris Riches +Date: Thu, 5 Jun 2025 09:47:02 +0000 +Subject: [PATCH] Sort files before passing to file attribute dependency + generators + +The fc->fahash map is constructed in parallel, and so ends up with +non-deterministic ordering of files. Passing this unordered list through +to file attribute dependency generators can therefore result in +non-reproducible RPM builds. + +In theory, a file attribute generator should only care about each +individual file it is given, and so the order should not matter. +However, some generators track state in-between files and so this +property does not hold. Notably, the python3-rpm-generators in RHEL +(ab)use this system to apply package-level dependencies that are based +on the package name rather than the content of any particular file, and +simply apply this to the first file that they see from a matching +package. Therefore, different input file orderings will result in +different files getting the dependency, and therefore different output +RPMs. + +To avoid this, sort the files before passing them to the generators. +Since the fc->fn array is already sorted by filename, we just need to +sort the list of indices into that array. + +(backported from commit bc0b94026bc5651435819043394cbe9a766a4fd5) +--- + build/rpmfc.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/build/rpmfc.c b/build/rpmfc.c +index c3015ffcb..b5fb611db 100644 +--- a/build/rpmfc.c ++++ b/build/rpmfc.c +@@ -1010,6 +1010,13 @@ static const struct applyDep_s applyDepTable[] = { + { 0, 0, NULL }, + }; + ++static int compareInts(const void *a, const void *b) ++{ ++ int ia = *((int*)a); ++ int ib = *((int*)b); ++ return ia > ib ? 1 : ia < ib ? -1 : 0; ++} ++ + static int applyAttr(rpmfc fc, int aix, const char *aname, + const struct exclreg_s *excl, + const struct applyDep_s *dep) +@@ -1032,6 +1039,8 @@ static int applyAttr(rpmfc fc, int aix, const char *aname, + + if (!rstreq(cmd, "")) { + char *ns = rpmfcAttrMacro(aname, "namespace", NULL); ++ /* Sort for reproducibility - hashmap was constructed in parallel */ ++ qsort(ixs, n, sizeof(*ixs), compareInts); + for (int i = 0; i < n; i++) { + if (rpmfcHelper(fc, ixs[i], excl, dep->type, dep->tag, + ns, cmd, callable)) +-- +2.51.1 + diff --git a/SPECS/rpm.spec b/SPECS/rpm.spec index 4d5b214..b665b69 100644 --- a/SPECS/rpm.spec +++ b/SPECS/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 39 +%global rel 40 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -121,6 +121,8 @@ Patch152: 0001-Fix-a-race-condition-in-brp-strip.patch Patch153: 0002-Store-configurable-digest-s-on-packages-from-verific.patch Patch154: 0003-Add-support-for-spec-local-file-attributes-and-gener.patch Patch155: 0001-Allow-an-optional-override-clock-for-deterministic-t.patch +Patch156: 0001-Improve-error-handling-on-keystore-load.patch +Patch157: 0001-Sort-files-before-passing-to-file-attribute-dependen.patch # These are not yet upstream Patch906: rpm-4.7.1-geode-i686.patch @@ -673,6 +675,10 @@ fi %doc doc/librpm/html/* %changelog +* Fri Nov 21 2025 Michal Domonkos - 4.16.1.3-40 +- Improve error handling on keystore load (RHEL-114837) +- Sort files before passing to file attr dependency generators (RHEL-95376) + * Wed Aug 20 2025 Michal Domonkos - 4.16.1.3-39 - Allow an optional "override clock" for deterministic timestamps (RHEL-106672)