!156 rpm: fix CVE-2021-25937,CVE-2021-25938,CVE-2021-25939

From: @xujing99 
Reviewed-by: @licunlong 
Signed-off-by: @licunlong
This commit is contained in:
openeuler-ci-bot 2022-09-07 13:45:26 +00:00 committed by Gitee
commit dc59f85034
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
21 changed files with 2415 additions and 1 deletions

View File

@ -0,0 +1,43 @@
From 25a435e90844ea98fe5eb7bef22c1aecf3a9c033 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 14 Feb 2022 14:29:33 +0200
Subject: [PATCH] Set file metadata via fd-based ops for everything but
symlinks
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/25a435e90844ea98fe5eb7bef22c1aecf3a9c033
Regular file ops are fd-based already, for the rest we need to open them
manually. Files with temporary suffix must never be followed, for
directories (and pre-existing FA_TOUCHed files) use the rpm symlink
"root or target owner allowed" rule wrt following.
This mostly fixes CVE-2021-35938, but as we're not yet using dirfd-based
operatiosn for everything there are corner cases left undone. And then
there's the plugin API which needs updating for all this.
---
lib/fsm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/lib/fsm.c b/lib/fsm.c
index 913e9de2d..6f781c64d 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -990,6 +990,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = RPMERR_UNKNOWN_FILETYPE;
}
+ if (!rc && fd == -1 && !S_ISLNK(fp->sb.st_mode)) {
+ /* Only follow safe symlinks, and never on temporary files */
+ fd = fsmOpenat(di.dirfd, fp->fpath,
+ fp->suffix ? AT_SYMLINK_NOFOLLOW : 0);
+ if (fd < 0)
+ rc = RPMERR_OPEN_FAILED;
+ }
+
setmeta:
if (!rc && fp->setmeta) {
rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
--
2.27.0

View File

@ -0,0 +1,285 @@
From 96ec957e281220f8e137a2d5eb23b83a6377d556 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 10 Feb 2022 14:32:43 +0200
Subject: [PATCH] Validate intermediate symlinks during installation,
CVE-2021-35939
Conflict:adapt context; adapt configure.ac because c223d84fbf,f8b8e86ae3,
9fe75561f9 is not merged.
Reference:https://github.com/rpm-software-management/rpm/commit/96ec957e281220f8e137a2d5eb23b83a6377d556
Whenever directory changes during unpacking, walk the entire tree from
starting from / and validate any symlinks crossed, fail the install
on invalid links.
This is the first of step of many towards securing our file operations
against local tamperers and besides plugging that one CVE, paves the way
for the next step by adding the necessary directory fd tracking.
This also bumps the rpm OS requirements to a whole new level by requiring
the *at() family of calls from POSIX-1.2008.
This necessarily does a whole lot of huffing and puffing we previously
did not do. It should be possible to cache secure (ie root-owned)
directory structures to avoid validating everything a million times
but for now, just keeping things simple.
---
INSTALL | 2 +
configure.ac | 3 +-
lib/fsm.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 142 insertions(+), 7 deletions(-)
diff --git a/INSTALL b/INSTALL
index 677ef88c4..961a160e0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -103,6 +103,8 @@ option to configure). For GCC, OpenMP 4.5 is fully supported since GCC 6.1,
of GPG, available from
http://www.gnupg.org/
+Rpm requires a POSIX.1-2008 level operating system.
+
To compile RPM:
--------------
diff --git a/configure.ac b/configure.ac
index 3ee340726..0099e5f34 100644
--- a/configure.ac
+++ b/configure.ac
@@ -580,7 +580,8 @@ AC_CHECK_FUNCS([secure_getenv __secure_getenv])
AC_CHECK_FUNCS(
[mkstemp getcwd basename dirname realpath setenv unsetenv regcomp lchown \
- utimes getline],
+ utimes getline \
+ openat mkdirat fstatat ],
[], [AC_MSG_ERROR([function required by rpm])])
AC_LIBOBJ(fnmatch)
diff --git a/lib/fsm.c b/lib/fsm.c
index 911898347..b6b152ab1 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -8,6 +8,7 @@
#include <utime.h>
#include <errno.h>
+#include <fcntl.h>
#if WITH_CAP
#include <sys/capability.h>
#endif
@@ -20,6 +21,7 @@
#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
#include "lib/fsm.h"
#include "lib/rpmte_internal.h" /* XXX rpmfs */
+#include "lib/rpmfi_internal.h" /* rpmfiSetOnChdir */
#include "lib/rpmplugins.h" /* rpm plugins hooks */
#include "lib/rpmug.h"
@@ -406,17 +408,118 @@ static int fsmRmdir(const char *path)
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 fsmOpenat(int dirfd, const char *path, int flags)
+{
+ 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 && 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;
+ } else {
+ close(ffd);
+ }
+ }
+ }
+ }
+ return fd;
+}
+
+static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn,
+ int owned, mode_t mode)
+{
+ int rc;
+ rpmFsmOp op = (FA_CREATE);
+ if (!owned)
+ op |= FAF_UNOWNED;
+
+ /* Run fsm file pre hook for all plugins */
+ rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
+
+ if (!rc)
+ rc = fsmMkdir(dirfd, dn, mode);
+
+ if (!rc) {
+ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, mode, op);
+ }
+
+ /* Run fsm file post hook for all plugins */
+ rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc);
+
+ if (!rc) {
+ rpmlog(RPMLOG_DEBUG,
+ "%s directory created with perms %04o\n",
+ dn, (unsigned)(mode & 07777));
+ }
+
+ return rc;
+}
+
+static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create)
+{
+ char *path = xstrdup(p);
+ char *dp = path;
+ char *sp = NULL, *bn;
+ int oflags = O_RDONLY;
+
+ int dirfd = fsmOpenat(-1, "/", oflags);
+ int fd = dirfd; /* special case of "/" */
+
+ while ((bn = strtok_r(dp, "/", &sp)) != NULL) {
+ struct stat sb;
+ fd = fsmOpenat(dirfd, bn, oflags);
+
+ if (fd < 0 && errno == ENOENT && create) {
+ mode_t mode = S_IFDIR | (_dirPerms & 07777);
+ if (fsmDoMkDir(plugins, dirfd, bn, owned, mode) == 0) {
+ fd = fsmOpenat(dirfd, bn, oflags|O_NOFOLLOW);
+ }
+ }
+
+ if (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ close(fd);
+ errno = ENOTDIR;
+ fd = -1;
+ }
+
+ close(dirfd);
+ if (fd >= 0) {
+ dirfd = fd;
+ } else {
+ dirfd = -1;
+ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"),
+ bn, p, strerror(errno));
+ break;
+ }
+
+ dp = NULL;
+ }
+
+ free(path);
+ return dirfd;
+}
+
static int fsmMkfifo(const char *path, mode_t mode)
{
int rc = mkfifo(path, (mode & 07777));
@@ -507,7 +610,7 @@ static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
if (!rc)
- rc = fsmMkdir(dn, mode);
+ rc = fsmMkdir(-1, dn, mode);
if (!rc) {
rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn,
@@ -874,6 +977,21 @@ static void setFileState(rpmfs fs, int i)
}
}
+struct diriter_s {
+ int dirfd;
+};
+
+static int onChdir(rpmfi fi, void *data)
+{
+ struct diriter_s *di = data;
+
+ if (di->dirfd >= 0) {
+ close(di->dirfd);
+ di->dirfd = -1;
+ }
+ return 0;
+}
+
int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmpsm psm, char ** failedFile)
{
@@ -890,6 +1008,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
char *tid = NULL;
struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
struct filedata_s *firstlink = NULL;
+ struct diriter_s di = { -1 };
/* transaction id used for temporary path suffix while installing */
rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
@@ -932,6 +1051,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = RPMERR_BAD_MAGIC;
goto exit;
}
+ rpmfiSetOnChdir(fi, onChdir, &di);
/* Detect and create directories not explicitly in package. */
if (!rc)
@@ -946,6 +1066,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!fp->suffix) {
rc = fsmBackup(fi, fp->action);
}
+
+ if (di.dirfd == -1) {
+ di.dirfd = ensureDir(plugins, rpmfiDN(fi), 0,
+ (fp->action == FA_CREATE));
+ if (di.dirfd == -1) {
+ rc = RPMERR_OPEN_FAILED;
+ break;
+ }
+ }
+
/* Assume file does't exist when tmp suffix is in use */
if (!fp->suffix) {
rc = fsmVerify(fp->fpath, fi);
@@ -980,7 +1110,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
mode_t mode = fp->sb.st_mode;
mode &= ~07777;
mode |= 00700;
- rc = fsmMkdir(fp->fpath, mode);
+ rc = fsmMkdir(di.dirfd, fp->fpath, mode);
}
} else if (S_ISLNK(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -1022,6 +1152,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
fp->stage = FILE_UNPACK;
}
fi = rpmfiFree(fi);
+ close(di.dirfd);
+ di.dirfd = -1;
if (!rc && fx < 0 && fx != RPMERR_ITER_END)
rc = fx;
--
2.27.0

View File

@ -0,0 +1,47 @@
From f9b90179b7c80a170969d9ab4c77c0a311635e3f Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 11 Feb 2021 14:18:37 +0200
Subject: [PATCH] Add diagnostics to archive unpacking
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/f9b90179b7c80a170969d9ab4c77c0a311635e3f
Move to a clearly defined helper function, add fsmdebug output.
---
lib/fsm.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index bd2481a50..c065bd55a 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -297,6 +297,17 @@ static int fsmOpen(FD_t *wfdp, const char *dest)
return rc;
}
+static int fsmUnpack(rpmfi fi, FD_t fd, rpmpsm psm, int nodigest)
+{
+ int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm);
+ if (_fsm_debug) {
+ rpmlog(RPMLOG_DEBUG, " %8s (%s %lu bytes [%d]) %s\n", __func__,
+ rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd),
+ (rc < 0 ? strerror(errno) : ""));
+ }
+ return rc;
+}
+
static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
struct filedata_s ** firstlink, FD_t *firstlinkfile)
@@ -324,7 +335,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
/* If the file has content, unpack it */
if (rpmfiArchiveHasContent(fi)) {
if (!rc)
- rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm);
+ rc = fsmUnpack(fi, fd, psm, nodigest);
/* Last file of hardlink set, ensure metadata gets set */
if (*firstlink) {
(*firstlink)->setmeta = 1;
--
2.27.0

View File

@ -0,0 +1,52 @@
From bbd30984dcedd2de4762b96c92b62a32f9448b03 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 11 Feb 2021 09:54:41 +0200
Subject: [PATCH] Add hardlink helper to fsm to make it debuggable
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/bbd30984dcedd2de4762b96c92b62a32f9448b03
---
lib/fsm.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 6efd25bdd..f8038e09b 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -211,6 +211,20 @@ const char * dnlNextIterator(DNLI_t dnli)
return dn;
}
+static int fsmLink(const char *opath, const char *path)
+{
+ int rc = link(opath, path);
+
+ if (_fsm_debug) {
+ rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
+ opath, path, (rc < 0 ? strerror(errno) : ""));
+ }
+
+ if (rc < 0)
+ rc = RPMERR_LINK_FAILED;
+ return rc;
+}
+
static int fsmSetFCaps(const char *path, const char *captxt)
{
int rc = 0;
@@ -304,10 +318,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
rc = wfd_open(firstlinkfile, fp->fpath);
} else {
/* Create hard links for others */
- rc = link((*firstlink)->fpath, fp->fpath);
- if (rc < 0) {
- rc = RPMERR_LINK_FAILED;
- }
+ rc = fsmLink((*firstlink)->fpath, fp->fpath);
}
}
/* Write normal files or fill the last hardlinked (already
--
2.27.0

View File

@ -0,0 +1,108 @@
From fb13f7fd9eff012cb7b9dbf94ac5381c69404055 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 9 Feb 2022 14:47:14 +0200
Subject: [PATCH] Add optional callback on directory changes during rpmfi
iteration
Conflict:adapt rpmfi.c because 318efbaec is not merged.
Reference:https://github.com/rpm-software-management/rpm/commit/fb13f7fd9eff012cb7b9dbf94ac5381c69404055
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, 40 insertions(+), 1 deletion(-)
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 4673fbb85..e8e7d08bf 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -55,6 +55,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 */
@@ -303,6 +306,17 @@ rpm_count_t rpmfiDC(rpmfi fi)
}
#endif
+int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data)
+{
+ int rc = -1;
+ if (fi != NULL) {
+ fi->onChdir = cb;
+ fi->onChdirData = data;
+ rc = 0;
+ }
+ return rc;
+}
+
int rpmfiFX(rpmfi fi)
{
return (fi != NULL ? fi->i : -1);
@@ -313,9 +327,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;
}
@@ -1780,9 +1802,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.27.0

View File

@ -0,0 +1,132 @@
From bbc270d78fb361bd78eac9a9117070caeb537d4a Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 14 Feb 2022 12:35:58 +0200
Subject: [PATCH] Bury rpmio FD use to fsmUnpack()
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/bbc270d78fb361bd78eac9a9117070caeb537d4a
fsmUnpack() is the only place in FSM that needs to deal with rpmio FD
types, everywhere else they are nothing but a hindrance that need to
be converted to OS level descriptors for use. Better deal with OS
level descriptors to begin with.
---
lib/fsm.c | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 13b114220..b019f5711 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -110,14 +110,14 @@ static int fsmSetFCaps(const char *path, const char *captxt)
return rc;
}
-static int fsmClose(FD_t *wfdp)
+static int fsmClose(int *wfdp)
{
int rc = 0;
- if (wfdp && *wfdp) {
+ if (wfdp && *wfdp >= 0) {
int myerrno = errno;
static int oneshot = 0;
static int flush_io = 0;
- int fdno = Fileno(*wfdp);
+ int fdno = *wfdp;
if (!oneshot) {
flush_io = rpmExpandNumeric("%{?_flush_io}");
@@ -126,61 +126,56 @@ static int fsmClose(FD_t *wfdp)
if (flush_io) {
fsync(fdno);
}
- if (Fclose(*wfdp))
+ if (close(fdno))
rc = RPMERR_CLOSE_FAILED;
if (_fsm_debug) {
rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__,
fdno, (rc < 0 ? strerror(errno) : ""));
}
- *wfdp = NULL;
+ *wfdp = -1;
errno = myerrno;
}
return rc;
}
-static int fsmOpen(FD_t *wfdp, int dirfd, 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). */
int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200);
- if (fd >= 0) {
- *wfdp = fdDup(fd);
- close(fd);
- }
-
- if (fd < 0 || Ferror(*wfdp))
+ if (fd < 0)
rc = RPMERR_OPEN_FAILED;
if (_fsm_debug) {
rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__,
- dest, Fileno(*wfdp), (rc < 0 ? strerror(errno) : ""));
+ dest, fd, (rc < 0 ? strerror(errno) : ""));
}
-
- if (rc)
- fsmClose(wfdp);
+ *wfdp = fd;
return rc;
}
-static int fsmUnpack(rpmfi fi, FD_t fd, rpmpsm psm, int nodigest)
+static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest)
{
+ FD_t fd = fdDup(fdno);
int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm);
if (_fsm_debug) {
rpmlog(RPMLOG_DEBUG, " %8s (%s %lu bytes [%d]) %s\n", __func__,
rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd),
(rc < 0 ? strerror(errno) : ""));
}
+ Fclose(fd);
return rc;
}
static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
- struct filedata_s ** firstlink, FD_t *firstlinkfile)
+ struct filedata_s ** firstlink, int *firstlinkfile)
{
int rc = 0;
- FD_t fd = NULL;
+ int fd = -1;
if (*firstlink == NULL) {
/* First encounter, open file for writing */
@@ -206,7 +201,7 @@ static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
if (*firstlink) {
fp->setmeta = 1;
*firstlink = NULL;
- *firstlinkfile = NULL;
+ *firstlinkfile = -1;
}
}
@@ -811,7 +806,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
int fc = rpmfilesFC(files);
int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
- FD_t firstlinkfile = NULL;
+ int firstlinkfile = -1;
char *tid = NULL;
struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
struct filedata_s *firstlink = NULL;
--
2.27.0

View File

@ -0,0 +1,70 @@
From 073bcf7ff6d580e5bafee0ef762cf7ce71bc486d Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 8 Feb 2021 10:45:59 +0200
Subject: [PATCH] Clean up file unpack iteration logic a bit
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/073bcf7ff6d580e5bafee0ef762cf7ce71bc486d
Handle rpmfiNext() in the while-condition directly to make it more like
similar other constructs elsewhere, adjust for the end of iteration
code after the loop. Also take the file index from rpmfiNext() so
we don't need multiple calls to rpmfiFX() later.
---
lib/fsm.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 35dcda081..7c291adb0 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -841,6 +841,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
struct stat sb;
int saveerrno = errno;
int rc = 0;
+ int fx = -1;
int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
int firsthardlink = -1;
@@ -862,17 +863,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* Detect and create directories not explicitly in package. */
rc = fsmMkdirs(files, fs, plugins);
- while (!rc) {
- /* Read next payload header. */
- rc = rpmfiNext(fi);
-
- if (rc < 0) {
- if (rc == RPMERR_ITER_END)
- rc = 0;
- break;
- }
-
- action = rpmfsGetAction(fs, rpmfiFX(fi));
+ while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ action = rpmfsGetAction(fs, fx);
skip = XFA_SKIPPING(action);
if (action != FA_TOUCH) {
suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
@@ -896,7 +888,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (rc) {
skip = 1;
} else {
- setFileState(fs, rpmfiFX(fi));
+ setFileState(fs, fx);
}
if (!skip) {
@@ -1005,6 +997,9 @@ touch:
fpath = _free(fpath);
}
+ if (!rc && fx != RPMERR_ITER_END)
+ rc = fx;
+
rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
--
2.27.0

View File

@ -0,0 +1,59 @@
From cc22fc694d30a64862f0b16d137deaab5416382d Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 11 Feb 2022 13:05:45 +0200
Subject: [PATCH] Consolidate skipped hardlink with content case with the
others
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/cc22fc694d30a64862f0b16d137deaab5416382d
Handling this in a separate clause makes the logic much clearer and
(in theory at least) lets us handle hardlinks to any content, not
just regular files.
---
lib/fsm.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index ec6ee2c36..82610c77d 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -832,9 +832,18 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
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) {
/* Directories replacing something need early backup */
- if (!fp->suffix) {
+ if (!fp->suffix && fp != firstlink) {
rc = fsmBackup(fi, fp->action);
}
@@ -904,15 +913,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!IS_DEV_LOG(fp->fpath))
rc = RPMERR_UNKNOWN_FILETYPE;
}
- } else if (firstlink && rpmfiArchiveHasContent(fi)) {
- /*
- * 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.
- */
- rc = fsmMkfile(fi, firstlink, files, psm, nodigest,
- &firstlink, &firstlinkfile);
}
/* Notify on success. */
--
2.27.0

View File

@ -0,0 +1,192 @@
From b599e28112ce5cee98b9ffa7bd96886ec5155e9c Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 11 Feb 2022 15:35:16 +0200
Subject: [PATCH] Convert the file creation steps the *at() family of calls
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/b599e28112ce5cee98b9ffa7bd96886ec5155e9c
Supposedly no functional changes here, we just need all these things
converted before we can swap over to relative paths.
---
configure.ac | 2 +-
lib/fsm.c | 59 ++++++++++++++++++++++++++--------------------------
2 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/configure.ac b/configure.ac
index 0099e5f34..ac9003768 100644
--- a/configure.ac
+++ b/configure.ac
@@ -581,7 +581,7 @@ AC_CHECK_FUNCS([secure_getenv __secure_getenv])
AC_CHECK_FUNCS(
[mkstemp getcwd basename dirname realpath setenv unsetenv regcomp lchown \
utimes getline \
- openat mkdirat fstatat ],
+ openat mkdirat fstatat linkat symlinkat mkfifoat mknodat ],
[], [AC_MSG_ERROR([function required by rpm])])
AC_LIBOBJ(fnmatch)
diff --git a/lib/fsm.c b/lib/fsm.c
index ae1bd3f48..8443954f2 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -77,13 +77,13 @@ const char * dnlNextIterator(DNLI_t dnli)
return dn;
}
-static int fsmLink(const char *opath, const char *path)
+static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path)
{
- int rc = link(opath, path);
+ int rc = linkat(odirfd, opath, dirfd, path, 0);
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)
@@ -139,17 +139,18 @@ static int fsmClose(FD_t *wfdp)
return rc;
}
-static int fsmOpen(FD_t *wfdp, const char *dest)
+static int fsmOpen(FD_t *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);
+ int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200);
+
+ if (fd >= 0) {
+ *wfdp = fdDup(fd);
+ close(fd);
}
- if (Ferror(*wfdp))
+ if (fd < 0 || Ferror(*wfdp))
rc = RPMERR_OPEN_FAILED;
if (_fsm_debug) {
@@ -174,7 +175,7 @@ static int fsmUnpack(rpmfi fi, FD_t fd, rpmpsm psm, int nodigest)
return rc;
}
-static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
+static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
struct filedata_s ** firstlink, FD_t *firstlinkfile)
{
@@ -183,7 +184,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
if (*firstlink == NULL) {
/* First encounter, open file for writing */
- rc = fsmOpen(&fd, fp->fpath);
+ 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;
@@ -192,7 +193,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
} else {
/* Create hard links for others and avoid redundant metadata setting */
if (*firstlink != fp) {
- rc = fsmLink((*firstlink)->fpath, fp->fpath);
+ rc = fsmLink(dirfd, (*firstlink)->fpath, dirfd, fp->fpath);
}
fd = *firstlinkfile;
}
@@ -382,13 +383,13 @@ static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create)
return dirfd;
}
-static int fsmMkfifo(const char *path, mode_t mode)
+static int fsmMkfifo(int dirfd, const char *path, mode_t mode)
{
- int rc = mkfifo(path, (mode & 07777));
+ int rc = mkfifoat(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) : ""));
}
@@ -398,14 +399,14 @@ static int fsmMkfifo(const char *path, mode_t mode)
return rc;
}
-static int fsmMknod(const char *path, mode_t mode, dev_t dev)
+static int fsmMknod(int dirfd, const char *path, mode_t mode, dev_t dev)
{
/* FIX: check S_IFIFO or dev != 0 */
- int rc = mknod(path, (mode & ~07777), dev);
+ int rc = mknodat(dirfd, path, (mode & ~07777), dev);
if (_fsm_debug) {
- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n",
- __func__, path, (unsigned)(mode & ~07777),
+ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%o, 0x%x) %s\n",
+ __func__, dirfd, path, (unsigned)(mode & ~07777),
(unsigned)dev, (rc < 0 ? strerror(errno) : ""));
}
@@ -440,13 +441,13 @@ static void fsmDebug(const char *fpath, rpmFileAction action,
(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)
@@ -884,7 +885,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
- rc = fsmMkfile(fi, fp, files, psm, nodigest,
+ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
&firstlink, &firstlinkfile);
}
} else if (S_ISDIR(fp->sb.st_mode)) {
@@ -896,19 +897,19 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
}
} else if (S_ISLNK(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
- rc = fsmSymlink(rpmfiFLink(fi), fp->fpath);
+ rc = fsmSymlink(rpmfiFLink(fi), di.dirfd, fp->fpath);
}
} 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(fp->fpath, 0000);
+ rc = fsmMkfifo(di.dirfd, fp->fpath, 0000);
}
} 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(fp->fpath, fp->sb.st_mode, fp->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 */
--
2.27.0

View File

@ -0,0 +1,31 @@
From 8a9147f7d182e1a5aa55ac019c32a4ba765fae62 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Feb 2021 08:25:28 +0200
Subject: [PATCH] Drop unused filename variable
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/8a9147f7d182e1a5aa55ac019c32a4ba765fae62
---
lib/fsm.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 7c291adb0..41b6267dd 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -959,11 +959,9 @@ touch:
/* 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) {
--
2.27.0

View File

@ -0,0 +1,70 @@
From dce44771b2a3325b3dc1ebfe41027df9910a39fd Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 11 Feb 2022 13:18:11 +0200
Subject: [PATCH] Fix + sanitize the hardlink metadata setting logic
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/dce44771b2a3325b3dc1ebfe41027df9910a39fd
Fix the initial setmeta value to something meaningful: we will never
set metadata on skipped files, and hardlinks are handled with a special
logic during install. They'd need different kind of special logic on
FA_TOUCH so just play it safe and always apply metadata on those.
Harlink metadata setting on install should happen on the *last* entry
of hardlinked set that gets installed (wrt various skip scenarios)
as otherwise creating those additional links affects the timestamp.
Note in particular the "last file of..." case in fsmMkfile() where we
the comment said just that, but set the metadata on the *first* file
which would then be NULL'ed away.
This all gets current masked by the fact that we do the metadata setting on
a separate round, but that is about to change plus this makes the overall
logic clearer anyhow.
---
lib/fsm.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 82610c77d..d9cfe6fa9 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -193,7 +193,6 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
/* Create hard links for others and avoid redundant metadata setting */
if (*firstlink != fp) {
rc = fsmLink((*firstlink)->fpath, fp->fpath);
- fp->setmeta = 0;
}
fd = *firstlinkfile;
}
@@ -204,7 +203,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
rc = fsmUnpack(fi, fd, psm, nodigest);
/* Last file of hardlink set, ensure metadata gets set */
if (*firstlink) {
- (*firstlink)->setmeta = 1;
+ fp->setmeta = 1;
*firstlink = NULL;
*firstlinkfile = NULL;
}
@@ -797,7 +796,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
else
fp->action = rpmfsGetAction(fs, fx);
fp->skip = XFA_SKIPPING(fp->action);
- fp->setmeta = 1;
if (fp->action != FA_TOUCH) {
fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
} else {
@@ -805,6 +803,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* Remap file perms, owner, and group. */
rc = rpmfiStat(fi, 1, &fp->sb);
+ /* Hardlinks are tricky and handled elsewhere for install */
+ fp->setmeta = (fp->skip == 0) &&
+ (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
+
setFileState(fs, fx);
fsmDebug(fp->fpath, fp->action, &fp->sb);
--
2.27.0

View File

@ -0,0 +1,261 @@
From a82251b44ee2d2802ee8aea1b3d89f88beee4bad Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Feb 2021 14:15:33 +0200
Subject: [PATCH] Handle file install failures more gracefully
Conflict:adapt context; delete testcode
Reference:https://github.com/rpm-software-management/rpm/commit/a82251b44ee2d2802ee8aea1b3d89f88beee4bad
Run the file installation in multiple stages:
1) gather intel
2) unpack the archive to temporary files
3) set file metadatas
4) commit files to final location
5) mop up leftovers on failure
This means we no longer leave behind a trail of untracked, potentially
harmful junk on installation failure.
If commit step fails the package can still be left in an inconsistent stage,
this could be further improved by first backing up old files to temporary
location to allow undo on failure, but leaving that for some other day.
Also unowned directories will still be left behind.
And yes, this is a somewhat scary change as it's the biggest ever change
to how rpm lays down files on install. Adopt the hardlink test spec
over to install tests and add some more tests for the new behavior.
Fixes: #967 (+ multiple reports over the years)
---
lib/fsm.c | 147 ++++++++++++++++++++------------
1 files changed, 93 insertions(+), 54 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index f86383a98..6efd25bdd 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -38,7 +38,17 @@ static int strict_erasures = 0;
#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;
@@ -844,10 +854,9 @@ 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);
- int saveerrno = errno;
int rc = 0;
int fx = -1;
int fc = rpmfilesFC(files);
@@ -858,20 +867,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
struct filedata_s *firstlink = NULL;
- if (fi == NULL) {
- rc = RPMERR_BAD_MAGIC;
- goto exit;
- }
-
/* 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);
-
+ /* 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];
- fp->action = rpmfsGetAction(fs, fx);
+ if (rpmfiFFlags(fi) & RPMFILE_GHOST)
+ fp->action = FA_SKIP;
+ else
+ fp->action = rpmfsGetAction(fs, fx);
fp->skip = XFA_SKIPPING(fp->action);
fp->setmeta = 1;
if (fp->action != FA_TOUCH) {
@@ -881,20 +887,32 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* Remap file perms, owner, and group. */
rc = rpmfiStat(fi, 1, &fp->sb);
+ setFileState(fs, fx);
fsmDebug(fp->fpath, fp->action, &fp->sb);
- /* Exit on error. */
- if (rc)
- break;
-
/* Run fsm file pre hook for all plugins */
rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
fp->sb.st_mode, fp->action);
- if (rc) {
- fp->skip = 1;
- } else {
- setFileState(fs, fx);
- }
+ fp->stage = FILE_PRE;
+ }
+ fi = rpmfiFree(fi);
+
+ if (rc)
+ goto exit;
+
+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
+ if (fi == NULL) {
+ rc = RPMERR_BAD_MAGIC;
+ goto exit;
+ }
+
+ /* Detect and create directories not explicitly in package. */
+ if (!rc)
+ rc = fsmMkdirs(files, fs, plugins);
+
+ /* Process the payload */
+ while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ struct filedata_s *fp = &fdata[fx];
if (!fp->skip) {
/* Directories replacing something need early backup */
@@ -918,7 +936,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* When touching we don't need any of this... */
if (fp->action == FA_TOUCH)
- goto touch;
+ continue;
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -954,12 +972,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = RPMERR_UNKNOWN_FILETYPE;
}
-touch:
- /* Set permissions, timestamps etc for non-hardlink entries */
- if (!rc && fp->setmeta) {
- rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
- &fp->sb, nofcaps);
- }
} else if (firstlink && rpmfiArchiveHasContent(fi)) {
/* On FA_TOUCH no hardlinks are created thus this is skipped. */
/* we skip the hard linked file containing the content */
@@ -969,47 +981,74 @@ touch:
firstlink = NULL;
}
- if (rc) {
- if (!fp->skip) {
- /* XXX only erase if temp fn w suffix is in use */
- if (fp->suffix) {
- (void) fsmRemove(fp->fpath, fp->sb.st_mode);
- }
- errno = saveerrno;
- }
- } else {
- /* Notify on success. */
+ /* Notify on success. */
+ if (rc)
+ *failedFile = xstrdup(fp->fpath);
+ else
rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
+ fp->stage = FILE_UNPACK;
+ }
+ fi = rpmfiFree(fi);
- if (!fp->skip) {
- /* Backup file if needed. Directories are handled earlier */
- if (fp->suffix)
- rc = fsmBackup(fi, fp->action);
+ if (!rc && fx < 0 && fx != RPMERR_ITER_END)
+ rc = fx;
- if (!rc)
- rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
- }
+ /* Set permissions, timestamps etc for non-hardlink entries */
+ fi = rpmfilesIter(files, RPMFI_ITER_FWD);
+ while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ struct filedata_s *fp = &fdata[fx];
+ if (!fp->skip && fp->setmeta) {
+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
+ &fp->sb, nofcaps);
}
-
if (rc)
*failedFile = xstrdup(fp->fpath);
+ fp->stage = FILE_PREP;
+ }
+ fi = rpmfiFree(fi);
- /* Run fsm file post hook for all plugins */
- rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
- fp->sb.st_mode, fp->action, rc);
+ /* If all went well, commit files to final destination */
+ fi = rpmfilesIter(files, RPMFI_ITER_FWD);
+ while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ struct filedata_s *fp = &fdata[fx];
+
+ if (!fp->skip) {
+ /* Backup file if needed. Directories are handled earlier */
+ if (!rc && fp->suffix)
+ rc = fsmBackup(fi, fp->action);
+
+ if (!rc)
+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
+
+ if (!rc)
+ fp->stage = FILE_COMMIT;
+ else
+ *failedFile = xstrdup(fp->fpath);
+ }
}
+ fi = rpmfiFree(fi);
- if (!rc && fx != RPMERR_ITER_END)
- rc = fx;
+ /* Walk backwards in case we need to erase */
+ fi = rpmfilesIter(files, RPMFI_ITER_BACK);
+ while ((fx = rpmfiNext(fi)) >= 0) {
+ struct filedata_s *fp = &fdata[fx];
+ /* Run fsm file post hook for all plugins for all processed files */
+ if (fp->stage) {
+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
+ fp->sb.st_mode, fp->action, rc);
+ }
+
+ /* On failure, erase non-committed files */
+ if (rc && fp->stage > FILE_NONE && !fp->skip) {
+ (void) fsmRemove(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 = rpmfiFree(fi);
Fclose(payload);
free(tid);
for (int i = 0; i < fc; i++)
--
2.27.0

View File

@ -0,0 +1,96 @@
From 1c23cff7296cec56379ee41077145c29d6841a12 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Feb 2021 11:25:10 +0200
Subject: [PATCH] Handle hardlink tracking with a file state pointer
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/1c23cff7296cec56379ee41077145c29d6841a12
No functional changes, just makes it a little cleaner as firstlink now
points to the actual file data instead of a index number somewhere.
---
lib/fsm.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 094f5e2bb..f86383a98 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -282,24 +282,22 @@ exit:
static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
- int * firsthardlink, FD_t *firstlinkfile)
+ struct filedata_s ** firstlink, FD_t *firstlinkfile)
{
int rc = 0;
int numHardlinks = rpmfiFNlink(fi);
if (numHardlinks > 1) {
/* Create first hardlinked file empty */
- if (*firsthardlink < 0) {
- *firsthardlink = rpmfiFX(fi);
+ if (*firstlink == NULL) {
+ *firstlink = fp;
rc = wfd_open(firstlinkfile, fp->fpath);
} else {
/* Create hard links for others */
- char *fn = rpmfilesFN(files, *firsthardlink);
- rc = link(fn, fp->fpath);
+ rc = link((*firstlink)->fpath, fp->fpath);
if (rc < 0) {
rc = RPMERR_LINK_FAILED;
}
- free(fn);
}
}
/* Write normal files or fill the last hardlinked (already
@@ -311,7 +309,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
if (!rc)
rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
wfd_close(firstlinkfile);
- *firsthardlink = -1;
+ *firstlink = NULL;
} else {
fp->setmeta = 0;
}
@@ -855,10 +853,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
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;
char *tid = NULL;
struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
+ struct filedata_s *firstlink = NULL;
if (fi == NULL) {
rc = RPMERR_BAD_MAGIC;
@@ -925,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
rc = fsmMkfile(fi, fp, files, psm, nodigest,
- &firsthardlink, &firstlinkfile);
+ &firstlink, &firstlinkfile);
}
} else if (S_ISDIR(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -962,13 +960,13 @@ touch:
rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
&fp->sb, nofcaps);
}
- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
+ } else if (firstlink && 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 */
rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
wfd_close(&firstlinkfile);
- firsthardlink = -1;
+ firstlink = NULL;
}
if (rc) {
--
2.27.0

View File

@ -0,0 +1,148 @@
From 2efdc55e15b21a80dcc414aa95e433c3adf4516c Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 11 Feb 2021 10:36:28 +0200
Subject: [PATCH] Make file open and close in fsm debuggable
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/2efdc55e15b21a80dcc414aa95e433c3adf4516c
Add debugging facilities to file open and close routines in fsm, rename
wfd_open/close to fsmOpen/Close to bring the messages in line with
our other stuff.
Slight reorganization needed for the error paths, in particular in
case of file close we haven't even been recording the close result
with can be critical when writing files. Add an error code for close
failure and return it from fsmClose(), but updating the calling code
to take this into account is out of scope in this commit.
---
lib/fsm.c | 40 ++++++++++++++++++++++++++--------------
lib/rpmarchive.h | 1 +
2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index f8038e09b..ffafa5d68 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -244,27 +244,36 @@ static int fsmSetFCaps(const char *path, const char *captxt)
return rc;
}
-static void wfd_close(FD_t *wfdp)
+static int fsmClose(FD_t *wfdp)
{
+ int rc = 0;
if (wfdp && *wfdp) {
int myerrno = errno;
static int oneshot = 0;
static int flush_io = 0;
+ int fdno = Fileno(*wfdp);
+
if (!oneshot) {
flush_io = rpmExpandNumeric("%{?_flush_io}");
oneshot = 1;
}
if (flush_io) {
- int fdno = Fileno(*wfdp);
fsync(fdno);
}
- Fclose(*wfdp);
+ if (Fclose(*wfdp))
+ rc = RPMERR_CLOSE_FAILED;
+
+ if (_fsm_debug) {
+ rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__,
+ fdno, (rc < 0 ? strerror(errno) : ""));
+ }
*wfdp = NULL;
errno = myerrno;
}
+ return rc;
}
-static int wfd_open(FD_t *wfdp, const char *dest)
+static int fsmOpen(FD_t *wfdp, const char *dest)
{
int rc = 0;
/* Create the file with 0200 permissions (write by owner). */
@@ -273,15 +282,18 @@ static int wfd_open(FD_t *wfdp, const char *dest)
*wfdp = Fopen(dest, "wx.ufdio");
umask(old_umask);
}
- if (Ferror(*wfdp)) {
+
+ if (Ferror(*wfdp))
rc = RPMERR_OPEN_FAILED;
- goto exit;
+
+ if (_fsm_debug) {
+ rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__,
+ dest, Fileno(*wfdp), (rc < 0 ? strerror(errno) : ""));
}
- return 0;
+ if (rc)
+ fsmClose(wfdp);
-exit:
- wfd_close(wfdp);
return rc;
}
@@ -294,12 +306,12 @@ static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest)
FD_t wfd = NULL;
int rc;
- rc = wfd_open(&wfd, dest);
+ rc = fsmOpen(&wfd, dest);
if (rc != 0)
goto exit;
rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm);
- wfd_close(&wfd);
+ fsmClose(&wfd);
exit:
return rc;
}
@@ -315,7 +327,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
/* Create first hardlinked file empty */
if (*firstlink == NULL) {
*firstlink = fp;
- rc = wfd_open(firstlinkfile, fp->fpath);
+ rc = fsmOpen(firstlinkfile, fp->fpath);
} else {
/* Create hard links for others */
rc = fsmLink((*firstlink)->fpath, fp->fpath);
@@ -329,7 +341,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
} else if (rpmfiArchiveHasContent(fi)) {
if (!rc)
rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
- wfd_close(firstlinkfile);
+ fsmClose(firstlinkfile);
*firstlink = NULL;
} else {
fp->setmeta = 0;
@@ -988,7 +1000,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* we skip the hard linked file containing the content */
/* write the content to the first used instead */
rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
- wfd_close(&firstlinkfile);
+ fsmClose(&firstlinkfile);
firstlink = NULL;
}
diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h
index 2484b4d71..ec6366c86 100644
--- a/lib/rpmarchive.h
+++ b/lib/rpmarchive.h
@@ -47,6 +47,7 @@ enum rpmfilesErrorCodes {
RPMERR_COPY_FAILED = -32785,
RPMERR_LSETFCON_FAILED = -32786,
RPMERR_SETCAP_FAILED = -32787,
+ RPMERR_CLOSE_FAILED = -32788,
};
#ifdef __cplusplus
--
2.27.0

View File

@ -0,0 +1,72 @@
From da79e3c3ae7da8719f0bf87a1a60e046597b8240 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 11 Feb 2022 13:28:25 +0200
Subject: [PATCH] Move file metadata setting back to unpack stage
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/da79e3c3ae7da8719f0bf87a1a60e046597b8240
Commit a82251b44ee2d2802ee8aea1b3d89f88beee4bad moved metadata setting
to a separate step because there are potential benefits to doing so, but
the current downsides are worse: as long as we operate in potentially
untrusted directories, we'd need to somehow verify the content is what we
initially laid down to avoid possible privilege escalation from non-root
owned directories.
This commit does not fix that vulnerability, only makes the window much
smaller and paves the way for the real fix(es) without introducing a
second round of directory tree validation chase to the picture.
---
lib/fsm.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index d9cfe6fa9..ae1bd3f48 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -880,7 +880,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* When touching we don't need any of this... */
if (fp->action == FA_TOUCH)
- continue;
+ goto setmeta;
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -915,6 +915,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!IS_DEV_LOG(fp->fpath))
rc = RPMERR_UNKNOWN_FILETYPE;
}
+
+setmeta:
+ if (!rc && fp->setmeta) {
+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
+ &fp->sb, nofcaps);
+ }
}
/* Notify on success. */
@@ -931,20 +937,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!rc && fx < 0 && fx != RPMERR_ITER_END)
rc = fx;
- /* Set permissions, timestamps etc for non-hardlink entries */
- fi = rpmfilesIter(files, RPMFI_ITER_FWD);
- while (!rc && (fx = rpmfiNext(fi)) >= 0) {
- struct filedata_s *fp = &fdata[fx];
- if (!fp->skip && fp->setmeta) {
- rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
- &fp->sb, nofcaps);
- }
- if (rc)
- *failedFile = xstrdup(fp->fpath);
- fp->stage = FILE_PREP;
- }
- fi = rpmfiFree(fi);
-
/* If all went well, commit files to final destination */
fi = rpmfilesIter(files, RPMFI_ITER_FWD);
while (!rc && (fx = rpmfiNext(fi)) >= 0) {
--
2.27.0

View File

@ -0,0 +1,340 @@
From 924cb31c53dcf60ff0cce650851dba354f383f15 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Feb 2021 09:47:19 +0200
Subject: [PATCH] Refactor file install and remove around a common struct
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/924cb31c53dcf60ff0cce650851dba354f383f15
Collect the common state info into a struct shared by both file install
and remove, update code accordingly. The change looks much more drastic
than it is - it's just adding fp-> prefix to a lot of places.
While we're at it, remember the state data throughout the operation.
No functional changes here, just paving way for the next steps which
will look clearer with these pre-requisites in place.
---
lib/fsm.c | 158 +++++++++++++++++++++++++++++-------------------------
1 file changed, 85 insertions(+), 73 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index c581a918a..9dba30560 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -38,6 +38,14 @@ static int strict_erasures = 0;
#define _dirPerms 0755
#define _filePerms 0644
+struct filedata_s {
+ 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
@@ -840,19 +848,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
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;
char *tid = NULL;
- const char *suffix;
- char *fpath = NULL;
+ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
if (fi == NULL) {
rc = RPMERR_BAD_MAGIC;
@@ -866,96 +871,99 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = fsmMkdirs(files, fs, plugins);
while (!rc && (fx = rpmfiNext(fi)) >= 0) {
- action = rpmfsGetAction(fs, fx);
- skip = XFA_SKIPPING(action);
- if (action != FA_TOUCH) {
- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
+ struct filedata_s *fp = &fdata[fx];
+ fp->action = rpmfsGetAction(fs, fx);
+ fp->skip = XFA_SKIPPING(fp->action);
+ if (fp->action != FA_TOUCH) {
+ fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
} else {
- suffix = NULL;
+ fp->suffix = NULL;
}
- fpath = fsmFsPath(fi, suffix);
+ fp->fpath = fsmFsPath(fi, fp->suffix);
/* Remap file perms, owner, and group. */
- rc = rpmfiStat(fi, 1, &sb);
+ rc = rpmfiStat(fi, 1, &fp->sb);
- fsmDebug(fpath, action, &sb);
+ fsmDebug(fp->fpath, fp->action, &fp->sb);
/* Exit on error. */
if (rc)
break;
/* 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 (rc) {
- skip = 1;
+ fp->skip = 1;
} else {
setFileState(fs, fx);
}
- if (!skip) {
+ if (!fp->skip) {
int setmeta = 1;
/* Directories replacing something need early backup */
- if (!suffix) {
- rc = fsmBackup(fi, action);
+ if (!fp->suffix) {
+ rc = fsmBackup(fi, fp->action);
}
/* Assume file does't exist when tmp suffix is in use */
- if (!suffix) {
- rc = fsmVerify(fpath, fi);
+ if (!fp->suffix) {
+ rc = fsmVerify(fp->fpath, fi);
} else {
rc = RPMERR_ENOENT;
}
/* See if the file was removed while our attention was elsewhere */
- if (rc == RPMERR_ENOENT && action == FA_TOUCH) {
- rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath);
- action = FA_CREATE;
- fsmDebug(fpath, action, &sb);
+ 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 (action == FA_TOUCH)
+ if (fp->action == FA_TOUCH)
goto touch;
- if (S_ISREG(sb.st_mode)) {
+ if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
- rc = fsmMkfile(fi, fpath, files, psm, nodigest,
+ rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest,
&setmeta, &firsthardlink, &firstlinkfile);
}
- } 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(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), 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(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(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);
+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
+ &fp->sb, nofcaps);
}
} else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
/* On FA_TOUCH no hardlinks are created thus this is skipped. */
@@ -967,10 +975,10 @@ touch:
}
if (rc) {
- if (!skip) {
+ if (!fp->skip) {
/* XXX only erase if temp fn w suffix is in use */
- if (suffix) {
- (void) fsmRemove(fpath, sb.st_mode);
+ if (fp->suffix) {
+ (void) fsmRemove(fp->fpath, fp->sb.st_mode);
}
errno = saveerrno;
}
@@ -978,23 +986,22 @@ touch:
/* Notify on success. */
rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
- if (!skip) {
+ if (!fp->skip) {
/* Backup file if needed. Directories are handled earlier */
- if (suffix)
- rc = fsmBackup(fi, action);
+ if (fp->suffix)
+ rc = fsmBackup(fi, fp->action);
if (!rc)
- rc = fsmCommit(&fpath, fi, action, suffix);
+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
}
}
if (rc)
- *failedFile = xstrdup(fpath);
+ *failedFile = xstrdup(fp->fpath);
/* Run fsm file post hook for all plugins */
- rpmpluginsCallFsmFilePost(plugins, fi, fpath,
- sb.st_mode, action, rc);
- fpath = _free(fpath);
+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
+ fp->sb.st_mode, fp->action, rc);
}
if (!rc && fx != RPMERR_ITER_END)
@@ -1010,7 +1017,9 @@ exit:
rpmfiFree(fi);
Fclose(payload);
free(tid);
- free(fpath);
+ for (int i = 0; i < fc; i++)
+ free(fdata[i].fpath);
+ free(fdata);
return rc;
}
@@ -1022,29 +1031,31 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK);
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));
+ fp->fpath = fsmFsPath(fi, NULL);
+ rc = fsmStat(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);
+ if (!XFA_SKIPPING(fp->action))
+ rc = fsmBackup(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(fp->fpath, fp->sb.st_mode);
/*
* Missing %ghost or %missingok entries are not errors.
@@ -1069,20 +1080,20 @@ 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"),
- 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 = xstrdup(fp->fpath);
if (rc == 0) {
/* Notify on success. */
@@ -1090,10 +1101,11 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi);
rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
}
- fpath = _free(fpath);
}
- free(fpath);
+ for (int i = 0; i < fc; i++)
+ free(fdata[i].fpath);
+ free(fdata);
rpmfiFree(fi);
return rc;
--
2.27.0

View File

@ -0,0 +1,112 @@
From 210431f18338dfa2d579ea86776cd426a72bf971 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Feb 2021 10:08:27 +0200
Subject: [PATCH] Refactor fsmMkfile() to take advantage of the new state
struct
Conflict:NA
Reference:https://github.com/rpm-software-management/rpm/commit/210431f18338dfa2d579ea86776cd426a72bf971
Move setmeta into the struct too (we'll want this later anyhow),
and now we only need to pass the struct to fsmMkfile(). One less
argument to pass around, it has way too many still.
No functional changes.
---
lib/fsm.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 9dba30560..80ca234b1 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -39,6 +39,7 @@ static int strict_erasures = 0;
#define _filePerms 0644
struct filedata_s {
+ int setmeta;
int skip;
rpmFileAction action;
const char *suffix;
@@ -279,8 +280,8 @@ exit:
return rc;
}
-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
- rpmpsm psm, int nodigest, int *setmeta,
+static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
+ rpmpsm psm, int nodigest,
int * firsthardlink, FD_t *firstlinkfile)
{
int rc = 0;
@@ -290,11 +291,11 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
/* Create first hardlinked file empty */
if (*firsthardlink < 0) {
*firsthardlink = rpmfiFX(fi);
- rc = wfd_open(firstlinkfile, dest);
+ rc = wfd_open(firstlinkfile, fp->fpath);
} else {
/* Create hard links for others */
char *fn = rpmfilesFN(files, *firsthardlink);
- rc = link(fn, dest);
+ rc = link(fn, fp->fpath);
if (rc < 0) {
rc = RPMERR_LINK_FAILED;
}
@@ -305,14 +306,14 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
existing) file with content */
if (numHardlinks<=1) {
if (!rc)
- rc = expandRegular(fi, dest, psm, nodigest);
+ rc = expandRegular(fi, fp->fpath, psm, nodigest);
} else if (rpmfiArchiveHasContent(fi)) {
if (!rc)
rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
wfd_close(firstlinkfile);
*firsthardlink = -1;
} else {
- *setmeta = 0;
+ fp->setmeta = 0;
}
return rc;
@@ -874,6 +875,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
struct filedata_s *fp = &fdata[fx];
fp->action = rpmfsGetAction(fs, fx);
fp->skip = XFA_SKIPPING(fp->action);
+ fp->setmeta = 1;
if (fp->action != FA_TOUCH) {
fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
} else {
@@ -900,8 +902,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
}
if (!fp->skip) {
- int setmeta = 1;
-
/* Directories replacing something need early backup */
if (!fp->suffix) {
rc = fsmBackup(fi, fp->action);
@@ -927,8 +927,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
- rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest,
- &setmeta, &firsthardlink, &firstlinkfile);
+ rc = fsmMkfile(fi, fp, files, psm, nodigest,
+ &firsthardlink, &firstlinkfile);
}
} else if (S_ISDIR(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -961,7 +961,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
touch:
/* Set permissions, timestamps etc for non-hardlink entries */
- if (!rc && setmeta) {
+ if (!rc && fp->setmeta) {
rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
&fp->sb, nofcaps);
}
--
2.27.0

View File

@ -0,0 +1,68 @@
From 693d828c035848585b500dfde6f4e58cfb8d4de4 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 14 Feb 2022 12:44:42 +0200
Subject: [PATCH] Return descriptor of created file from fsmMkfile()
Conflict:adapt context
Reference:https://github.com/rpm-software-management/rpm/commit/693d828c035848585b500dfde6f4e58cfb8d4de4
This will be needed for using fd-based metadata operations.
---
lib/fsm.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index b019f5711..7c4796f74 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -172,7 +172,8 @@ static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest)
static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
- struct filedata_s ** firstlink, int *firstlinkfile)
+ struct filedata_s ** firstlink, int *firstlinkfile,
+ int *fdp)
{
int rc = 0;
int fd = -1;
@@ -204,9 +205,7 @@ static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
*firstlinkfile = -1;
}
}
-
- if (fd != *firstlinkfile)
- fsmClose(&fd);
+ *fdp = fd;
return rc;
}
@@ -867,6 +866,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
fp = firstlink;
if (!fp->skip) {
+ int fd = -1;
/* Directories replacing something need early backup */
if (!fp->suffix && fp != firstlink) {
rc = fsmBackup(fi, fp->action);
@@ -910,7 +910,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (S_ISREG(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
- &firstlink, &firstlinkfile);
+ &firstlink, &firstlinkfile, &fd);
}
} else if (S_ISDIR(fp->sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
@@ -946,6 +946,9 @@ setmeta:
rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
&fp->sb, nofcaps);
}
+
+ if (fd != firstlinkfile)
+ fsmClose(&fd);
}
/* Notify on success. */
--
2.27.0

View File

@ -0,0 +1,135 @@
From 505699eb9789543a1b7bcaf8bb654d59b9d2623a Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 11 Feb 2021 14:06:29 +0200
Subject: [PATCH] Streamline + consolidate the hardlink handling logic
Conflict:delete testcode
Reference:https://github.com/rpm-software-management/rpm/commit/505699eb9789543a1b7bcaf8bb654d59b9d2623a
This is one tricksy piece of code, in particular wrt interactions with
skipped files. Streamline the logic to make it easier to follow, and
consolidate as much as possible inside fsmMkfile() so there's only
one place opening, closing and writing to files. Add bunch of tests
for partially skipped sets.
This actually also fixes a case where metadata does not get properly
set on a partially skipped hardlink file set (the --excludepath=/foo/zzzz
case would fail prior to this)
---
lib/fsm.c | 80 ++++++++++++++++++++++-----------------------------
1 files changed, 35 insertions(+), 45 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index ffafa5d68..bd2481a50 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -297,56 +297,45 @@ static int fsmOpen(FD_t *wfdp, const char *dest)
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)
-{
- FD_t wfd = NULL;
- int rc;
-
- rc = fsmOpen(&wfd, dest);
- if (rc != 0)
- goto exit;
-
- rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm);
- fsmClose(&wfd);
-exit:
- return rc;
-}
-
static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
rpmpsm psm, int nodigest,
struct filedata_s ** firstlink, FD_t *firstlinkfile)
{
int rc = 0;
- int numHardlinks = rpmfiFNlink(fi);
+ FD_t fd = NULL;
- if (numHardlinks > 1) {
- /* Create first hardlinked file empty */
- if (*firstlink == NULL) {
+ if (*firstlink == NULL) {
+ /* First encounter, open file for writing */
+ rc = fsmOpen(&fd, fp->fpath);
+ /* If it's a part of a hardlinked set, the content may come later */
+ if (fp->sb.st_nlink > 1) {
*firstlink = fp;
- rc = fsmOpen(firstlinkfile, fp->fpath);
- } else {
- /* Create hard links for others */
+ *firstlinkfile = fd;
+ }
+ } else {
+ /* Create hard links for others and avoid redundant metadata setting */
+ if (*firstlink != fp) {
rc = fsmLink((*firstlink)->fpath, fp->fpath);
+ fp->setmeta = 0;
}
+ fd = *firstlinkfile;
}
- /* Write normal files or fill the last hardlinked (already
- existing) file with content */
- if (numHardlinks<=1) {
- if (!rc)
- rc = expandRegular(fi, fp->fpath, psm, nodigest);
- } else if (rpmfiArchiveHasContent(fi)) {
+
+ /* If the file has content, unpack it */
+ if (rpmfiArchiveHasContent(fi)) {
if (!rc)
- rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
- fsmClose(firstlinkfile);
- *firstlink = NULL;
- } else {
- fp->setmeta = 0;
+ rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm);
+ /* Last file of hardlink set, ensure metadata gets set */
+ if (*firstlink) {
+ (*firstlink)->setmeta = 1;
+ *firstlink = NULL;
+ *firstlinkfile = NULL;
+ }
}
+ if (fd != *firstlinkfile)
+ fsmClose(&fd);
+
return rc;
}
@@ -994,14 +983,15 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!IS_DEV_LOG(fp->fpath))
rc = RPMERR_UNKNOWN_FILETYPE;
}
-
- } else if (firstlink && 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 */
- rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
- fsmClose(&firstlinkfile);
- firstlink = NULL;
+ } else if (firstlink && rpmfiArchiveHasContent(fi)) {
+ /*
+ * 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.
+ */
+ rc = fsmMkfile(fi, firstlink, files, psm, nodigest,
+ &firstlink, &firstlinkfile);
}
/* Notify on success. */
--
2.27.0

View File

@ -0,0 +1,66 @@
From 886c24cfc6c0fec90d8db1406a0e32c0e09e92c9 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 27 Aug 2020 10:31:07 +0300
Subject: [PATCH] Upgrade FA_TOUCH to FA_CREATE if the file went away
(RhBug:1872141)
Conflict:delete testcode
Reference:https://github.com/rpm-software-management/rpm/commit/886c24cfc6c0fec90d8db1406a0e32c0e09e92c9
When %_minimize_writes is enabled, we determine unchanged files during
fingerprinting and only update their metadata (FA_TOUCH) instead of
always recreating from scratch (FA_CREATE) during install. However
package scriptlets (and administrators) can and will do arbitrary stuff
in the meanwhile, such as rm -f their own files in %pre, hoping to
get a fresh copy of contents no matter what. Or something.
Now, if the file was determined to not need changing by rpm, this will
just fail with chown & friends trying to touch non-existent file.
One can consider this a case of package shooting itself in the foot, but
when a package update fails or succeeds depending on %_minimize_writes this
to me suggests the feature is at fault as much as the package.
Do fsmVerify() on all files to be FA_TOUCH'ed to detect files whose
type changed or were removed since fingerprinting. This still doesn't
ensure correctness if something tampers with the contents in the meanwhile,
(for that we'd need to run the file through the whole machinery again,
checksumming and all) but covers the most glaring cases.
---
lib/fsm.c | 15 +++++++++----
1 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 5fb507993..08980d49b 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -902,10 +902,6 @@ 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);
@@ -917,6 +913,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rc = RPMERR_ENOENT;
}
+ /* See if the file was removed while our attention was elsewhere */
+ if (rc == RPMERR_ENOENT && action == FA_TOUCH) {
+ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath);
+ action = FA_CREATE;
+ fsmDebug(fpath, action, &sb);
+ }
+
+ /* When touching we don't need any of this... */
+ if (action == FA_TOUCH)
+ goto touch;
+
if (S_ISREG(sb.st_mode)) {
if (rc == RPMERR_ENOENT) {
rc = fsmMkfile(fi, fpath, files, psm, nodigest,
--
2.27.0

View File

@ -1,6 +1,6 @@
Name: rpm
Version: 4.15.1
Release: 36
Release: 37
Summary: RPM Package Manager
License: GPLv2+
URL: http://www.rpm.org/
@ -93,6 +93,27 @@ Patch79: backport-0003-CVE-2021-3521.patch
Patch80: rpm-selinux-plugin-check-context-file-exist.patch
Patch81: backport-Use-root-as-default-UID_0_USER-and-UID_0_GROUP.patch
Patch82: backport-Upgrade-FA_TOUCH-to-FA_CREATE-if-the-file-went-away-.patch
Patch83: backport-Clean-up-file-unpack-iteration-logic-a-bit.patch
Patch84: backport-Refactor-file-install-and-remove-around-a-common-str.patch
Patch85: backport-Refactor-fsmMkfile-to-take-advantage-of-the-new-stat.patch
Patch86: backport-Drop-unused-filename-variable.patch
Patch87: backport-Handle-hardlink-tracking-with-a-file-state-pointer.patch
Patch88: backport-Handle-file-install-failures-more-gracefully.patch
Patch89: backport-Add-hardlink-helper-to-fsm-to-make-it-debuggable.patch
Patch90: backport-Make-file-open-and-close-in-fsm-debuggable.patch
Patch91: backport-Streamline-consolidate-the-hardlink-handling-logic.patch
Patch92: backport-Add-diagnostics-to-archive-unpacking.patch
Patch93: backport-Add-optional-callback-on-directory-changes-during-rp.patch
Patch94: backport-0001-CVE-2021-35939-CVE-2021-35937.patch
Patch95: backport-Consolidate-skipped-hardlink-with-content-case-with-.patch
Patch96: backport-Fix-sanitize-the-hardlink-metadata-setting-logic.patch
Patch97: backport-Convert-the-file-creation-steps-the-at-family-of-cal.patch
Patch98: backport-Bury-rpmio-FD-use-to-fsmUnpack.patch
Patch99: backport-Move-file-metadata-setting-back-to-unpack-stage.patch
Patch100: backport-Return-descriptor-of-created-file-from-fsmMkfile.patch
Patch101: backport-0001-CVE-2021-35938.patch
BuildRequires: gcc autoconf automake libtool make gawk popt-devel openssl-devel readline-devel libdb-devel
BuildRequires: zlib-devel libzstd-devel xz-devel bzip2-devel libarchive-devel ima-evm-utils-devel
BuildRequires: dbus-devel fakechroot elfutils-devel elfutils-libelf-devel ima-evm-utils
@ -375,6 +396,12 @@ make check || (cat tests/rpmtests.log; exit 0)
%{_mandir}/man1/gendiff.1*
%changelog
* Wed Sep 7 2022 xujing<xujing125@huawei.com> - 4.15.1-37
- Type:CVE
- ID:NA
- SUG:NA
- DESC:fix CVE-2021-35937,CVE-2021-35938,CVE-2021-35939
* Tue Dec 14 2021 renhongxun<renhongxun@huawei.com> - 4.15.1-36
- Type:bugfix
- ID:NA