Add patches for next release

Resolves: RHEL-73186 RHEL-54386 RHEL-65378
This commit is contained in:
Michal Domonkos 2025-01-13 13:56:29 +01:00
parent 4783f4455f
commit a7bd5f6cf7
3 changed files with 359 additions and 1 deletions

View File

@ -0,0 +1,229 @@
From 6d8f3cbe56839c7417fe17714b92034eea044895 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 19 Aug 2024 11:03:10 +0300
Subject: [PATCH 1/2] 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 <ffesti@redhat.com>
Backported from commits:
14516542c113560dc0070df2f9102568a7a71b58
535eacc96ae6fe5289a2917bb0af43e491b0f4f4
Fixes: RHEL-73186
---
lib/fsm.c | 70 ++++++++++++++++++++++++++-------------------------
lib/rpmfi.c | 2 +-
tests/rpmi.at | 4 +--
3 files changed, 39 insertions(+), 37 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 36708acc3..5e073ce22 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;
@@ -1026,10 +1030,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 011d6787e..b35195e76 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -2487,7 +2487,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 = _("Invalid symlink"); break;
+ case RPMERR_INVALID_SYMLINK: s = _("Unsafe symlink"); break;
case RPMERR_ENOTDIR: s = strerror(ENOTDIR); break;
case RPMERR_ENOENT: s = strerror(ENOENT); break;
case RPMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
diff --git a/tests/rpmi.at b/tests/rpmi.at
index 95b4497be..ae8b24437 100644
--- a/tests/rpmi.at
+++ b/tests/rpmi.at
@@ -1555,8 +1555,8 @@ runroot --setenv SOURCE_DATE_EPOCH 1699955855 rpm -U /build/RPMS/noarch/replacet
],
[1],
[],
-[error: failed to open dir opt of /opt/: Not a directory
-error: unpacking of archive failed on file /opt/foo;6553448f: cpio: open failed - Not a directory
+[error: failed to open dir opt of /opt/: cpio: Unsafe symlink
+error: unpacking of archive failed on file /opt/foo;6553448f: cpio: Unsafe symlink
error: replacetest-1.0-1.noarch: install failed
])
RPMTEST_CLEANUP
--
2.47.1

View File

@ -0,0 +1,121 @@
From 5ae6dd32ea4b755a354facb54d5cecbdcf3df25a Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 18 Oct 2024 14:50:35 +0300
Subject: [PATCH 2/2] 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
Fixes: RHEL-54386
---
lib/fsm.c | 2 +-
tests/data/SPECS/pamupdate.spec | 21 +++++++++++++++++
tests/rpmi.at | 40 +++++++++++++++++++++++++++++++++
3 files changed, 62 insertions(+), 1 deletion(-)
create mode 100644 tests/data/SPECS/pamupdate.spec
diff --git a/lib/fsm.c b/lib/fsm.c
index 5e073ce22..19f28cade 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -1094,7 +1094,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);
}
}
diff --git a/tests/data/SPECS/pamupdate.spec b/tests/data/SPECS/pamupdate.spec
new file mode 100644
index 000000000..a458b9b73
--- /dev/null
+++ b/tests/data/SPECS/pamupdate.spec
@@ -0,0 +1,21 @@
+Name: pamupdate
+Version: 1.0
+Release: %{rel}
+Group: Testing
+License: Public domain
+Summary: Test config behavior on update failure
+BuildArch: noarch
+
+%description
+%{summary}
+
+%install
+mkdir -p ${RPM_BUILD_ROOT}/etc
+echo AAAA > ${RPM_BUILD_ROOT}/etc/my.conf
+echo BBBB > ${RPM_BUILD_ROOT}/etc/your.conf
+mkdir -p ${RPM_BUILD_ROOT}/var/run/faillock
+
+%files
+%config /etc/my.conf
+%config /etc/your.conf
+%dir /var/run/faillock
diff --git a/tests/rpmi.at b/tests/rpmi.at
index ae8b24437..804123b1a 100644
--- a/tests/rpmi.at
+++ b/tests/rpmi.at
@@ -1560,3 +1560,43 @@ error: unpacking of archive failed on file /opt/foo;6553448f: cpio: Unsafe symli
error: replacetest-1.0-1.noarch: install failed
])
RPMTEST_CLEANUP
+
+AT_SETUP([update on invalid symlinked directory])
+AT_KEYWORDS([install update symlink])
+RPMDB_INIT
+
+RPMTEST_CHECK([
+for r in 1 2; do
+ runroot rpmbuild --quiet --bb \
+ --define "rel ${r}" \
+ /data/SPECS/pamupdate.spec
+done
+],
+[0],
+[],
+[])
+
+RPMTEST_CHECK([
+runroot rpm -U /build/RPMS/noarch/pamupdate-1.0-1.noarch.rpm
+runroot rpm -V pamupdate
+],
+[0],
+[],
+[])
+
+RPMTEST_CHECK([
+runroot_other chown -h nobody:nobody /var/run
+runroot rpm -U /build/RPMS/noarch/pamupdate-1.0-2.noarch.rpm
+],
+[1],
+[],
+[ignore])
+
+RPMTEST_CHECK([
+# --nomtime shouldn't be needed but fixing that's another story
+runroot rpm -V --nomtime pamupdate
+],
+[0],
+[],
+[])
+RPMTEST_CLEANUP
--
2.47.1

View File

@ -27,7 +27,7 @@
%global rpmver 4.19.1.1 %global rpmver 4.19.1.1
#global snapver rc1 #global snapver rc1
%global baserelease 9 %global baserelease 10
%global sover 10 %global sover 10
%global srcver %{rpmver}%{?snapver:-%{snapver}} %global srcver %{rpmver}%{?snapver:-%{snapver}}
@ -146,6 +146,9 @@ rpm-4.18.90-weak-user-group.patch
0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch 0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch
0003-Declare-signCmd-static.patch 0003-Declare-signCmd-static.patch
0001-Report-unsafe-symlinks-during-installation-as-a-spec.patch
0002-Fix-FA_TOUCH-ed-files-getting-removed-on-failed-upda.patch
# These are not yet upstream # These are not yet upstream
rpm-4.7.1-geode-i686.patch rpm-4.7.1-geode-i686.patch
@ -628,6 +631,11 @@ fi
%doc %{_defaultdocdir}/rpm/API/ %doc %{_defaultdocdir}/rpm/API/
%changelog %changelog
* Mon Jan 13 2025 Michal Domonkos <mdomonko@redhat.com> - 4.19.1.1-10
- Report unsafe symlinks during installation as a specific case (RHEL-73186)
- Fix FA_TOUCH'ed files getting removed on failed update (RHEL-54386)
- Rebuild for ima-evm-utils 1.6 soname bump (RHEL-65378)
* Wed Dec 04 2024 Panu Matilainen <pmatilai@redhat.com> - 4.19.1.1-9 * Wed Dec 04 2024 Panu Matilainen <pmatilai@redhat.com> - 4.19.1.1-9
- Revert the gnupg/sequoia sub-packages, too much headache - Revert the gnupg/sequoia sub-packages, too much headache
- Ship sequoia-signing enablement macros as documentation instead - Ship sequoia-signing enablement macros as documentation instead