diff --git a/0001-Don-t-segfault-on-missing-priority-tag.patch b/0001-Don-t-segfault-on-missing-priority-tag.patch new file mode 100644 index 0000000..1d44007 --- /dev/null +++ b/0001-Don-t-segfault-on-missing-priority-tag.patch @@ -0,0 +1,40 @@ +From 91ed417e8cc0a4f1ed45b1d8f6242c2ef9f441d3 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Fri, 20 Aug 2021 15:14:16 +0200 +Subject: [PATCH 1/5] Don't segfault on missing priority tag + +(cherry picked from commit fd57fc716231c8296d340fdb4c0f6eac176f7f7c) + +Fixes: RHEL-39894 +--- + lib/rpmtriggers.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c +index c652981be..a9e63a241 100644 +--- a/lib/rpmtriggers.c ++++ b/lib/rpmtriggers.c +@@ -523,7 +523,8 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense, + if (matchFunc(ts, te, pfx, sense)) { + for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) { + struct rpmtd_s priorities; +- unsigned int priority; ++ unsigned int priority = 0; ++ unsigned int *priority_ptr; + unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i); + unsigned int tix = rpmdbIndexIteratorTagNum(ii, i); + +@@ -541,7 +542,9 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense, + trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offset); + headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM); + rpmtdSetIndex(&priorities, tix); +- priority = *rpmtdGetUint32(&priorities); ++ priority_ptr = rpmtdGetUint32(&priorities); ++ if (priority_ptr) ++ priority = *priority_ptr; + headerFree(trigH); + + /* Store file trigger in array */ +-- +2.47.0 + diff --git a/0002-Fix-IMA-signature-fubar-take-III-1833-RhBug-2018937.patch b/0002-Fix-IMA-signature-fubar-take-III-1833-RhBug-2018937.patch new file mode 100644 index 0000000..3cadf9a --- /dev/null +++ b/0002-Fix-IMA-signature-fubar-take-III-1833-RhBug-2018937.patch @@ -0,0 +1,221 @@ +From eb3ee2ab221f12937fb35d304ba96d1f626aee4b Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Tue, 10 Oct 2017 15:04:38 +0300 +Subject: [PATCH 2/5] Fix IMA signature fubar, take III (#1833, RhBug:2018937) + +At least ECDSA and RSA signatures can vary in length, but the IMA code +assumes constant lengths and thus may either place invalid signatures on +disk from either truncating or overshooting, and segfault if the stars are +just so. + +As we can't assume static lengths and attempts to use maximum length +have proven problematic for other reasons, use a data structure that +can actually handle variable length data properly: store offsets into +the decoded binary blob and use them to calculate lengths when needed, +empty data is simply consequtive identical offsets. This avoids a whole +class of silly overflow issues with multiplying, makes zero-length data +actually presentable in the data structure and saves memory too. + +Add tests to show behavior with variable length signatures and missing +signatures. + +Additionally update the signing code to store the largest IMA signature +length rather than what happened to be last to be on the safe side. +We can't rely on this value due to invalid packages being out there, +but then we need to calculate the lengths on rpmfiles populate so there's +not a lot to gain anyhow. + +Backported from commits: +5af8ab60c652cda0bffcd4d65130bb57b5666ff0 +07f1d3132f0c7b7ecb69a47a9930edb534a9250e + +Tests are excluded from this backport since they would need significant +rework, the use case will be covered by Beaker. + +Fixes: RHEL-39896 +--- + lib/rpmfi.c | 61 +++++++++++++++++++++++++++++++++++++++------ + sign/rpmsignfiles.c | 30 ++++++++-------------- + 2 files changed, 64 insertions(+), 27 deletions(-) + +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 6c631fdb5..0aacd9f85 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -117,7 +117,7 @@ struct rpmfiles_s { + struct fingerPrint_s * fps; /*!< File fingerprint(s). */ + + int digestalgo; /*!< File digest algorithm */ +- int signaturelength; /*!< File signature length */ ++ uint32_t *signatureoffs; /*!< File signature offsets */ + unsigned char * digests; /*!< File digests in binary. */ + unsigned char * signatures; /*!< File signatures in binary. */ + +@@ -589,10 +589,15 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len) + const unsigned char *signature = NULL; + + if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) { +- if (fi->signatures != NULL) +- signature = fi->signatures + (fi->signaturelength * ix); ++ size_t slen = 0; ++ if (fi->signatures != NULL && fi->signatureoffs != NULL) { ++ uint32_t off = fi->signatureoffs[ix]; ++ slen = fi->signatureoffs[ix+1] - off; ++ if (slen > 0) ++ signature = fi->signatures + off; ++ } + if (len) +- *len = fi->signaturelength; ++ *len = slen; + } + return signature; + } +@@ -1276,6 +1281,7 @@ rpmfiles rpmfilesFree(rpmfiles fi) + fi->flangs = _free(fi->flangs); + fi->digests = _free(fi->digests); + fi->signatures = _free(fi->signatures); ++ fi->signatureoffs = _free(fi->signatureoffs); + fi->fcaps = _free(fi->fcaps); + + fi->cdict = _free(fi->cdict); +@@ -1504,6 +1510,48 @@ err: + return; + } + ++/* ++ * Convert a tag of variable len hex strings to binary presentation, ++ * accessed via offsets to a contiguous binary blob. Empty values ++ * are represented by identical consequtive offsets. The offsets array ++ * always has one extra element to allow calculating the size of the ++ * last element. ++ */ ++static uint8_t *hex2binv(Header h, rpmTagVal tag, rpm_count_t num, ++ uint32_t **offsetp) ++{ ++ struct rpmtd_s td; ++ uint8_t *bin = NULL; ++ uint32_t *offs = NULL; ++ ++ if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) { ++ const char *s; ++ int i = 0; ++ uint8_t *t = bin = xmalloc(((rpmtdSize(&td) / 2) + 1)); ++ offs = xmalloc((num + 1) * sizeof(*offs)); ++ ++ while ((s = rpmtdNextString(&td))) { ++ uint32_t slen = strlen(s); ++ uint32_t len = slen / 2; ++ if (slen % 2) { ++ bin = rfree(bin); ++ offs = rfree(offs); ++ goto exit; ++ } ++ offs[i] = t - bin; ++ for (int j = 0; j < len; j++, t++, s += 2) ++ *t = (rnibble(s[0]) << 4) | rnibble(s[1]); ++ i++; ++ } ++ offs[i] = t - bin; ++ *offsetp = offs; ++ } ++ ++exit: ++ rpmtdFreeData(&td); ++ return bin; ++} ++ + /* Convert a tag of hex strings to binary presentation */ + static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len) + { +@@ -1595,9 +1643,8 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) + fi->signatures = NULL; + /* grab hex signatures from header and store in binary format */ + if (!(flags & RPMFI_NOFILESIGNATURES)) { +- fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH); +- fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES, +- totalfc, fi->signaturelength); ++ fi->signatures = hex2binv(h, RPMTAG_FILESIGNATURES, ++ totalfc, &fi->signatureoffs); + } + + /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */ +diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c +index 61b73bd40..3b87ae875 100644 +--- a/sign/rpmsignfiles.c ++++ b/sign/rpmsignfiles.c +@@ -33,7 +33,7 @@ static const char *hash_algo_name[] = { + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + + static char *signFile(const char *algo, const char *fdigest, int diglen, +-const char *key, char *keypass) ++const char *key, char *keypass, uint32_t *siglenp) + { + char *fsignature; + unsigned char digest[diglen]; +@@ -60,32 +60,18 @@ const char *key, char *keypass) + return NULL; + } + ++ *siglenp = siglen + 1; + /* convert file signature binary to hex */ + fsignature = pgpHexStr(signature, siglen+1); + return fsignature; + } + +-static uint32_t signatureLength(const char *algo, int diglen, const char *key, +-char *keypass) +-{ +- unsigned char digest[diglen]; +- unsigned char signature[MAX_SIGNATURE_LENGTH]; +- +- memset(digest, 0, diglen); +- memset(signature, 0, MAX_SIGNATURE_LENGTH); +- signature[0] = '\x03'; +- +- uint32_t siglen = sign_hash(algo, digest, diglen, key, keypass, +- signature+1); +- return siglen + 1; +-} +- + rpmRC rpmSignFiles(Header h, const char *key, char *keypass) + { + struct rpmtd_s digests; + int algo; + int diglen; +- uint32_t siglen; ++ uint32_t siglen = 0; + const char *algoname; + const char *digest; + char *signature; +@@ -109,12 +95,11 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass) + + headerDel(h, RPMTAG_FILESIGNATURELENGTH); + headerDel(h, RPMTAG_FILESIGNATURES); +- siglen = signatureLength(algoname, diglen, key, keypass); +- headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1); + + headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM); + while ((digest = rpmtdNextString(&digests))) { +- signature = signFile(algoname, digest, diglen, key, keypass); ++ uint32_t slen = 0; ++ signature = signFile(algoname, digest, diglen, key, keypass, &slen); + if (!signature) { + rpmlog(RPMLOG_ERR, _("signFile failed\n")); + rc = RPMRC_FAIL; +@@ -127,8 +112,13 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass) + goto exit; + } + free(signature); ++ if (slen > siglen) ++ siglen = slen; + } + ++ if (siglen > 0) ++ headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1); ++ + exit: + rpmtdFreeData(&digests); + return rc; +-- +2.47.0 + diff --git a/0003-Fix-root-relocation-regression.patch b/0003-Fix-root-relocation-regression.patch new file mode 100644 index 0000000..f39f89b --- /dev/null +++ b/0003-Fix-root-relocation-regression.patch @@ -0,0 +1,94 @@ +From 9d01648f6752785be07a96498af0505d04170ec1 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 26 Jul 2024 10:43:50 +0200 +Subject: [PATCH 3/5] Fix root relocation regression + +When relocating the root directory, make sure we insert the new path's +dirname to dirNames[] even if the root itself is owned by the package. + +This appears to have been the intention from the first version (largely +untouched since) of this code as we allow the root to pass through the +first checks (by setting len to 0 in that case) as well as the second +for loop where we do the relocations. + +This allows fsm to properly create and remove the relocated directory +since we're now using fd-based calls (#1919) and the parent directory +needs to be opened first. + +No need to do string comparison here, the empty basename signals that +we're processing the root directory, so just use that. + +Building a relocatable package that owns the root directory seems to be +a handy way to create user-installable packages (see RHEL-28967) and it +happened to work before with the path-based calls so this technically +was a regression. Add a test that emulates this use case. + +Backported from commits: +31c14ba6610568c2d634647fed1fb57221178da9 +308ac60677732e9979b9ce11e5a3085906da1901 + +Tests are excluded from this backport since they would need significant +rework, the use case will be covered by Beaker. + +Fixes: RHEL-49494 +--- + lib/relocation.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/relocation.c b/lib/relocation.c +index 3ba4cfeab..8c35bc1a7 100644 +--- a/lib/relocation.c ++++ b/lib/relocation.c +@@ -123,7 +123,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + char ** baseNames; + char ** dirNames; + uint32_t * dirIndexes; +- rpm_count_t fileCount, dirCount; ++ rpm_count_t fileCount, dirCount, dirCountOrig; + int nrelocated = 0; + int fileAlloced = 0; + char * fn = NULL; +@@ -162,7 +162,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + baseNames = bnames.data; + dirIndexes = dindexes.data; + fileCount = rpmtdCount(&bnames); +- dirCount = rpmtdCount(&dnames); ++ dirCount = dirCountOrig = rpmtdCount(&dnames); + /* XXX TODO: use rpmtdDup() instead */ + dirNames = dnames.data = duparray(dnames.data, dirCount); + dnames.flags |= RPMTD_PTR_ALLOCED; +@@ -179,8 +179,9 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + rpmFileTypes ft; + int fnlen; + ++ size_t baselen = strlen(baseNames[i]); + size_t len = maxlen + +- strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; ++ strlen(dirNames[dirIndexes[i]]) + baselen + 1; + if (len >= fileAlloced) { + fileAlloced = len * 2; + fn = xrealloc(fn, fileAlloced); +@@ -242,8 +243,9 @@ assert(fn != NULL); /* XXX can't happen */ + continue; + } + +- /* Relocation on full paths only, please. */ +- if (fnlen != len) continue; ++ /* Relocation on '/' and full paths only, please. */ ++ if (baselen && fnlen != len) ++ continue; + + rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", + fn, relocations[j].newPath); +@@ -294,7 +296,7 @@ assert(fn != NULL); /* XXX can't happen */ + } + + /* Finish off by relocating directories. */ +- for (i = dirCount - 1; i >= 0; i--) { ++ for (i = dirCountOrig - 1; i >= 0; i--) { + for (j = numRelocations - 1; j >= 0; j--) { + + if (relocations[j].oldPath == NULL) /* XXX can't happen */ +-- +2.47.0 + diff --git a/0004-Report-unsafe-symlinks-during-installation-as-a-spec.patch b/0004-Report-unsafe-symlinks-during-installation-as-a-spec.patch new file mode 100644 index 0000000..229e58a --- /dev/null +++ b/0004-Report-unsafe-symlinks-during-installation-as-a-spec.patch @@ -0,0 +1,215 @@ +From 1e6cdb256c06b084501f5016d10bb5c8465c8287 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 19 Aug 2024 11:03:10 +0300 +Subject: [PATCH 4/5] Report unsafe symlinks during installation as a specific + case + +RPM refuses to follow non root owned symlinks pointing to files owned by +another user for security reasons. This case was lumped in with +O_DIRECTORY behavior, leading to confusing error message as the symlink +often indeed points at a directory. Emit a more meaningful error message +when encountering unsafe symlinks. + +We already detect the error condition in the main if block here, might +as well set the error code right there and then so we don't need to +redetect later. We previously only tested for the unsafe link condition +when our O_DIRECTORY equivalent was set, but that seems wrong. Probably +doesn't matter with the existing callers, but we really must not +follow those unsafe symlinks no matter what. + +Co-authored-by: Florian Festi + +Backported from commits: +14516542c113560dc0070df2f9102568a7a71b58 +535eacc96ae6fe5289a2917bb0af43e491b0f4f4 + +Tests are excluded from this backport since they would need significant +rework, the use case will be covered by Beaker. + +Fixes: RHEL-39897 +--- + lib/fsm.c | 70 +++++++++++++++++++++++++++-------------------------- + lib/rpmfi.c | 1 + + 2 files changed, 37 insertions(+), 34 deletions(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 9dd50b784..720d4a2ec 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -65,7 +65,7 @@ struct filedata_s { + * things around needlessly + */ + static const char * fileActionString(rpmFileAction a); +-static int fsmOpenat(int dirfd, const char *path, int flags, int dir); ++static int fsmOpenat(int *fdp, int dirfd, const char *path, int flags, int dir); + static int fsmClose(int *wfdp); + + /** \ingroup payload +@@ -98,9 +98,9 @@ static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path) + #ifdef WITH_CAP + static int cap_set_fileat(int dirfd, const char *path, cap_t fcaps) + { +- int rc = -1; +- int fd = fsmOpenat(dirfd, path, O_RDONLY|O_NOFOLLOW, 0); +- if (fd >= 0) { ++ int fd = -1; ++ int rc = fsmOpenat(&fd, dirfd, path, O_RDONLY|O_NOFOLLOW, 0); ++ if (!rc) { + rc = cap_set_fd(fd, fcaps); + fsmClose(&fd); + } +@@ -299,12 +299,12 @@ static int fsmMkdir(int dirfd, const char *path, mode_t mode) + return rc; + } + +-static int fsmOpenat(int dirfd, const char *path, int flags, int dir) ++static int fsmOpenat(int *wfdp, 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; ++ int rc = 0; + + /* + * Only ever follow symlinks by root or target owner. Since we can't +@@ -313,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) { +- ffd = openat(dirfd, path, flags); ++ int ffd = openat(dirfd, path, flags); + if (ffd >= 0) { + if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) { + if (fstat(ffd, &sb) == 0) { +@@ -322,17 +322,26 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir) + } + } + } +- if (ffd != fd) ++ /* Symlink with non-matching owners */ ++ if (ffd != fd) { + close(ffd); ++ rc = RPMERR_INVALID_SYMLINK; ++ } + } + } + + /* O_DIRECTORY equivalent */ +- if (dir && ((fd != ffd) || (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)))) { +- errno = ENOTDIR; ++ if (!rc && dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) ++ rc = RPMERR_ENOTDIR; ++ ++ if (!rc && fd < 0) ++ rc = RPMERR_OPEN_FAILED; ++ ++ if (rc) + fsmClose(&fd); +- } +- return fd; ++ ++ *wfdp = fd; ++ return rc; + } + + static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn, +@@ -351,9 +360,7 @@ static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn, + rc = fsmMkdir(dirfd, dn, mode); + + if (!rc) { +- *fdp = fsmOpenat(dirfd, dn, O_RDONLY|O_NOFOLLOW, 1); +- if (*fdp == -1) +- rc = RPMERR_ENOTDIR; ++ rc = fsmOpenat(fdp, dirfd, dn, O_RDONLY|O_NOFOLLOW, 1); + } + + if (!rc) { +@@ -378,47 +385,44 @@ static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create, + char *sp = NULL, *bn; + char *apath = NULL; + int oflags = O_RDONLY; +- int rc = 0; + + if (*dirfdp >= 0) +- return rc; ++ return 0; + +- int dirfd = fsmOpenat(-1, "/", oflags, 1); ++ int dirfd = -1; ++ int rc = fsmOpenat(&dirfd, -1, "/", oflags, 1); + int fd = dirfd; /* special case of "/" */ + + char *path = xstrdup(p); + char *dp = path; + + while ((bn = strtok_r(dp, "/", &sp)) != NULL) { +- fd = fsmOpenat(dirfd, bn, oflags, 1); ++ rc = fsmOpenat(&fd, dirfd, bn, oflags, 1); + /* assemble absolute path for plugins benefit, sigh */ + apath = rstrscat(&apath, "/", bn, NULL); + +- if (fd < 0 && errno == ENOENT && create) { ++ if (rc && 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; ++ if (rc) + break; +- } + ++ dirfd = fd; + dp = NULL; + } + + if (rc) { ++ if (!quiet) { ++ char *msg = rpmfileStrerror(rc); ++ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"), ++ bn, p, msg); ++ free(msg); ++ } + fsmClose(&fd); + fsmClose(&dirfd); +- } else { +- rc = 0; + } + *dirfdp = dirfd; + +@@ -1025,10 +1029,8 @@ setmeta: + /* Only follow safe symlinks, and never on temporary files */ + if (fp->suffix) + flags |= AT_SYMLINK_NOFOLLOW; +- fd = fsmOpenat(di.dirfd, fp->fpath, flags, ++ rc = fsmOpenat(&fd, di.dirfd, fp->fpath, flags, + S_ISDIR(fp->sb.st_mode)); +- if (fd < 0) +- rc = RPMERR_OPEN_FAILED; + } + + if (!rc && fp->setmeta) { +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 0aacd9f85..821bae875 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -2432,6 +2432,7 @@ char * rpmfileStrerror(int rc) + case RPMERR_DIGEST_MISMATCH: s = _("Digest mismatch"); break; + case RPMERR_INTERNAL: s = _("Internal error"); break; + case RPMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break; ++ case RPMERR_INVALID_SYMLINK: s = _("Unsafe symlink"); break; + case RPMERR_ENOENT: s = strerror(ENOENT); break; + case RPMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break; + case RPMERR_EXIST_AS_DIR: +-- +2.47.0 + diff --git a/0005-Fix-FA_TOUCH-ed-files-getting-removed-on-failed-upda.patch b/0005-Fix-FA_TOUCH-ed-files-getting-removed-on-failed-upda.patch new file mode 100644 index 0000000..0adc177 --- /dev/null +++ b/0005-Fix-FA_TOUCH-ed-files-getting-removed-on-failed-upda.patch @@ -0,0 +1,46 @@ +From 79b3aa74dda434dadb3a4477f0be6981fbe5ad74 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Fri, 18 Oct 2024 14:50:35 +0300 +Subject: [PATCH 5/5] Fix FA_TOUCH'ed files getting removed on failed update + +On install/update, most files are laid down with a temporary suffix +and if the update fails, removing those at the end of the loop is +the right thing to do. However FA_TOUCH'ed files were already there, +we only update their metadata, and we better not remove them! + +AFAICS this all versions since rpm >= 4.14 in one way or the other. +If %_minimize_writes is enabled then it affects way more than just +unmodified config files. + +The test is a simplified version of pam update failing in the original +report. Technically, --nomtime should not be needed for the test +verification but we don't even try to restore the metadata on failure, +and fixing that is way out of scope here. + +Backported from commits: +027ef640b33b38ca257bb301bb302e9c71d43c27 + +Tests are excluded from this backport since they would need significant +rework, the use case will be covered by Beaker. + +Fixes: RHEL-63069 +--- + lib/fsm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/fsm.c b/lib/fsm.c +index 720d4a2ec..91155c13c 100644 +--- a/lib/fsm.c ++++ b/lib/fsm.c +@@ -1093,7 +1093,7 @@ setmeta: + if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) + continue; + +- if (fp->stage > FILE_NONE && !fp->skip) { ++ if (fp->stage > FILE_NONE && !fp->skip && fp->action != FA_TOUCH) { + (void) fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); + } + } +-- +2.47.0 + diff --git a/rpm.spec b/rpm.spec index a52c767..79d7b31 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.14.3 #global snapver rc2 -%global rel 31 +%global rel 32 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x} @@ -141,6 +141,11 @@ 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 +Patch510: 0001-Don-t-segfault-on-missing-priority-tag.patch +Patch511: 0002-Fix-IMA-signature-fubar-take-III-1833-RhBug-2018937.patch +Patch512: 0003-Fix-root-relocation-regression.patch +Patch513: 0004-Report-unsafe-symlinks-during-installation-as-a-spec.patch +Patch514: 0005-Fix-FA_TOUCH-ed-files-getting-removed-on-failed-upda.patch # These are not yet upstream # Audit support @@ -711,6 +716,13 @@ make check || cat tests/rpmtests.log %doc doc/librpm/html/* %changelog +* Mon Oct 21 2024 Michal Domonkos - 4.14.3-32 +- Fix FA_TOUCH'ed files getting removed on failed update (RHEL-63069) +- Fix IMA signature lengths assumed constant (RHEL-39896) +- Fix root relocation regression (RHEL-49494) +- Report unsafe symlinks during installation as a specific case (RHEL-39897) +- Don't segfault on missing priority tag (RHEL-39894) + * 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