Compare commits

...

No commits in common. "imports/c8s/rpm-4.14.3-15.el8" and "c8" have entirely different histories.

25 changed files with 4739 additions and 141 deletions

View File

@ -0,0 +1,107 @@
From 186e0ab025b9ad92d900697f611633a6f6162f3b 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
Internal only for now in case we need to fiddle with the API some more,
but no reason this couldn't be made public later.
---
lib/rpmfi.c | 24 ++++++++++++++++++++----
lib/rpmfi_internal.h | 17 +++++++++++++++++
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index aec8220a3..6c631fdb5 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -53,6 +53,9 @@ struct rpmfi_s {
int intervalStart; /*!< Start of iterating interval. */
int intervalEnd; /*!< End of iterating interval. */
+ rpmfiChdirCb onChdir; /*!< Callback for directory changes */
+ void *onChdirData; /*!< Caller private callback data */
+
rpmfiles files; /*!< File info set */
rpmcpio_t archive; /*!< Archive with payload */
unsigned char * found; /*!< Bit field of files found in the archive */
@@ -298,11 +301,16 @@ rpm_count_t rpmfiDC(rpmfi fi)
return (fi != NULL ? rpmfilesDC(fi->files) : 0);
}
-#ifdef NOTYET
-int rpmfiDI(rpmfi fi)
+int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data)
{
+ int rc = -1;
+ if (fi != NULL) {
+ fi->onChdir = cb;
+ fi->onChdirData = data;
+ rc = 0;
+ }
+ return rc;
}
-#endif
int rpmfiFX(rpmfi fi)
{
@@ -314,9 +322,17 @@ int rpmfiSetFX(rpmfi fi, int fx)
int i = -1;
if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {
+ int dx = fi->j;
i = fi->i;
fi->i = fx;
fi->j = rpmfilesDI(fi->files, fi->i);
+ i = fi->i;
+
+ if (fi->j != dx && fi->onChdir) {
+ int chrc = fi->onChdir(fi, fi->onChdirData);
+ if (chrc < 0)
+ i = chrc;
+ }
}
return i;
}
@@ -1682,9 +1698,9 @@ static rpmfi initIter(rpmfiles files, int itype, int link)
if (files && itype>=0 && itype<=RPMFILEITERMAX) {
fi = xcalloc(1, sizeof(*fi));
fi->i = -1;
+ fi->j = -1;
fi->files = link ? rpmfilesLink(files) : files;
fi->next = nextfuncs[itype];
- fi->i = -1;
if (itype == RPMFI_ITER_BACK) {
fi->i = rpmfilesFC(fi->files);
} else if (itype >=RPMFI_ITER_READ_ARCHIVE
diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h
index dccc6ccbe..37f1d45f5 100644
--- a/lib/rpmfi_internal.h
+++ b/lib/rpmfi_internal.h
@@ -13,6 +13,23 @@
extern "C" {
#endif
+/** \ingroup rpmfi
+ * Callback on file iterator directory changes
+ * @param fi file info
+ * @param data caller private callback data
+ * @return 0 on success, < 0 on error (to stop iteration)
+ */
+typedef int (*rpmfiChdirCb)(rpmfi fi, void *data);
+
+/** \ingroup rpmfi
+ * Set a callback for directory changes during iteration.
+ * @param fi file info
+ * @param cb callback function
+ * @param data caller private callback data
+ * @return string pool handle (weak reference)
+ */
+int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data);
+
/** \ingroup rpmfi
* Return file info set string pool handle
* @param fi file info
--
2.41.0

View File

@ -0,0 +1,30 @@
From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 13 Dec 2023 11:57:50 +0200
Subject: [PATCH] Don't warn about missing user/group on skipped files
There's no reason to complain about missing user/group for entities
we don't create at all. It's cosmetical only, but "regressed" in the
4.17 fsm robustness rewrite.
Reported in https://issues.redhat.com/browse/RHEL-18037
---
lib/fsm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 2189bd84c..a54e43bae 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -903,7 +903,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
fp->fpath = fsmFsPath(fi, fp->suffix);
/* Remap file perms, owner, and group. */
- rc = rpmfiStat(fi, 1, &fp->sb);
+ rc = rpmfiStat(fi, (fp->skip == 0), &fp->sb);
/* Hardlinks are tricky and handled elsewhere for install */
fp->setmeta = (fp->skip == 0) &&
--
2.43.0

View File

@ -0,0 +1,35 @@
From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 10 Feb 2022 10:23:22 +0200
Subject: [PATCH] Eliminate code duplication from rpmfiNext()
Now that we can, let rpmfiSetFX() take care of the details.
---
lib/rpmfi.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 689ead2c5..aec8220a3 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -856,15 +856,8 @@ int rpmfiNext(rpmfi fi)
next = fi->next(fi);
} while (next == RPMERR_ITER_SKIP);
- if (next >= 0 && next < rpmfilesFC(fi->files)) {
- fi->i = next;
- fi->j = rpmfilesDI(fi->files, fi->i);
- } else {
- fi->i = -1;
- if (next >= 0) {
- next = -1;
- }
- }
+ if (next >= 0)
+ next = rpmfiSetFX(fi, next);
}
return next;
}
--
2.41.0

View File

@ -0,0 +1,66 @@
From c140768202e271b60910644c1e4bf848a50218d3 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 27 Nov 2023 11:52:34 +0200
Subject: [PATCH] Emit full paths for file disposition diagnostics on
--fsmdebug
The full path is visible in the actual file operations later, but the
pre-flight disposition diagnostics is unreadable without the full path.
This regressed in the switch to relative paths for the *at() API family
for the symlink CVE fixes.
---
lib/fsm.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 091e90554..fcd764648 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -482,14 +482,14 @@ static void removeSBITS(int dirfd, const char *path)
}
}
-static void fsmDebug(const char *fpath, rpmFileAction action,
+static void fsmDebug(const char *dn, const char *fpath, rpmFileAction action,
const struct stat *st)
{
- rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",
+ rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s%s\n",
fileActionString(action), (int)st->st_mode,
(int)st->st_nlink, (int)st->st_uid,
(int)st->st_gid, (int)st->st_size,
- (fpath ? fpath : ""));
+ (dn ? dn : ""), (fpath ? fpath : ""));
}
static int fsmSymlink(const char *opath, int dirfd, const char *path)
@@ -910,7 +910,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
(fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
setFileState(fs, fx);
- fsmDebug(fp->fpath, fp->action, &fp->sb);
+ fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
fp->stage = FILE_PRE;
}
@@ -975,7 +975,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n",
fp->fpath);
fp->action = FA_CREATE;
- fsmDebug(fp->fpath, fp->action, &fp->sb);
+ fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
}
/* When touching we don't need any of this... */
@@ -1138,7 +1138,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb);
- fsmDebug(fp->fpath, fp->action, &fp->sb);
+ fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
/* Run fsm file pre hook for all plugins */
rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
--
2.43.0

View File

@ -0,0 +1,46 @@
From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 14 Nov 2023 11:37:48 +0200
Subject: [PATCH] Fix wrong return code on O_DIRECTORY open of invalid symlink
The dir argument to fsmOpenpath() is supposed to be a rough O_DIRECTORY
equivalent, and if the path is actually a misowned symlink it should
return ENOTDIR instead of ELOOP. Makes the resulting error messages
at least a little more comprehensible.
---
lib/fsm.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 51f439ef3..091e90554 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -304,6 +304,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
struct stat lsb, sb;
int sflags = flags | O_NOFOLLOW;
int fd = openat(dirfd, path, sflags);
+ int ffd = fd;
/*
* Only ever follow symlinks by root or target owner. Since we can't
@@ -312,7 +313,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
* it could've only been the link owner or root.
*/
if (fd < 0 && errno == ELOOP && flags != sflags) {
- int ffd = openat(dirfd, path, flags);
+ ffd = openat(dirfd, path, flags);
if (ffd >= 0) {
if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) {
if (fstat(ffd, &sb) == 0) {
@@ -327,7 +328,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
}
/* O_DIRECTORY equivalent */
- if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
+ if (dir && ((fd != ffd) || (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)))) {
errno = ENOTDIR;
fsmClose(&fd);
}
--
2.43.0

View File

@ -1,89 +0,0 @@
From 13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4 Mon Sep 17 00:00:00 2001
Message-Id: <13b0ebee7cdb1e4d200b3c40d0ec9440f198a1d4.1554886141.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 10 Apr 2019 11:24:44 +0300
Subject: [PATCH] Monkey-patch .decode() method to our strings as a temporary
compat crutch
As a temporary crutch to support faster deployment of the sane
string behavior on python3, monkey-patch a decode method into all
strings we return. This seems to be enough to fix practically all
API users who have already adapted to the long-standing broken API
on Python 3. API users compatible with both Python 2 and 3 never needed
this anyway. Issue a warning with pointer to the relevant bug when the
fake decode() method is used to alert users to the issue.
This is certainly an evil thing to do and will be removed as soon as
the critical users have been fixed to work with the new, corrected
behavior.
---
python/rpm/__init__.py | 3 +++
python/rpmmodule.c | 1 +
python/rpmsystem-py.h | 22 ++++++++++++++++++++--
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/python/rpm/__init__.py b/python/rpm/__init__.py
index 54728bbd4..6d69eda7b 100644
--- a/python/rpm/__init__.py
+++ b/python/rpm/__init__.py
@@ -61,6 +61,9 @@ except ImportError:
# backwards compatibility + give the same class both ways
ts = TransactionSet
+def _fakedecode(self, encoding='utf-8', errors='strict'):
+ warnings.warn("decode() called on unicode string, see https://bugzilla.redhat.com/show_bug.cgi?id=1693751", UnicodeWarning, stacklevel=2)
+ return self
def headerLoad(*args, **kwds):
"""DEPRECATED! Use rpm.hdr() instead."""
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
index 05032edc7..2a76cfbd0 100644
--- a/python/rpmmodule.c
+++ b/python/rpmmodule.c
@@ -28,6 +28,7 @@
*/
PyObject * pyrpmError;
+PyObject * fakedecode = NULL;
static PyObject * archScore(PyObject * self, PyObject * arg)
{
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
index 25938464a..803da0fc1 100644
--- a/python/rpmsystem-py.h
+++ b/python/rpmsystem-py.h
@@ -19,12 +19,29 @@
#define PyInt_AsSsize_t PyLong_AsSsize_t
#endif
+PyObject * fakedecode;
+
static inline PyObject * utf8FromString(const char *s)
{
/* In Python 3, we return all strings as surrogate-escaped utf-8 */
#if PY_MAJOR_VERSION >= 3
- if (s != NULL)
- return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape");
+ if (s != NULL) {
+ PyObject *o = PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape");
+ /* fish the fake decode function from python side if not done yet */
+ if (fakedecode == NULL) {
+ PyObject *n = PyUnicode_FromString("rpm");
+ PyObject *m = PyImport_Import(n);
+ PyObject *md = PyModule_GetDict(m);
+ fakedecode = PyDict_GetItemString(md, "_fakedecode");
+ Py_DECREF(m);
+ Py_DECREF(n);
+ }
+ if (fakedecode && o) {
+ /* monkey-patch it into the string object as "decode" */
+ PyDict_SetItemString(Py_TYPE(o)->tp_dict, "decode", fakedecode);
+ }
+ return o;
+ }
#else
if (s != NULL)
return PyBytes_FromString(s);
--
2.20.1

View File

@ -0,0 +1,153 @@
From ac7b0dbd5a18d2c57a942ca14ac856b8047425ff Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 15 Feb 2022 10:43:13 +0200
Subject: [PATCH] Pass file descriptor to file prepare plugin hook, use when
possible
Sadly the thing that allegedly makes things better mostly just makes
things more complicated as symlinks can't be opened, so we'll now have
to deal with both cases in plugins too. To make matters worse, most
APIs out there support either an fd or a path, but very few support
the *at() style dirfd + basename approach so plugins are stuck with
absolute paths for now.
This is of course a plugin API/ABI change too.
---
lib/rpmplugin.h | 2 +-
lib/rpmplugins.c | 4 ++--
lib/rpmplugins.h | 3 ++-
plugins/ima.c | 9 +++++++--
plugins/selinux.c | 13 ++++++++-----
5 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
index fd81aec8d..fab4b3e83 100644
--- a/lib/rpmplugin.h
+++ b/lib/rpmplugin.h
@@ -57,7 +57,7 @@ typedef rpmRC (*plugin_fsm_file_post_func)(rpmPlugin plugin, rpmfi fi,
const char* path, mode_t file_mode,
rpmFsmOp op, int res);
typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
- const char* path,
+ int fd, const char* path,
const char *dest,
mode_t file_mode, rpmFsmOp op);
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
index 65e684e84..923084b78 100644
--- a/lib/rpmplugins.c
+++ b/lib/rpmplugins.c
@@ -384,7 +384,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
}
rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
- const char *path, const char *dest,
+ int fd, const char *path, const char *dest,
mode_t file_mode, rpmFsmOp op)
{
plugin_fsm_file_prepare_func hookFunc;
@@ -394,7 +394,7 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
for (i = 0; i < plugins->count; i++) {
rpmPlugin plugin = plugins->plugins[i];
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);
- if (hookFunc && hookFunc(plugin, fi, path, dest, file_mode, op) == RPMRC_FAIL) {
+ if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {
rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_prepare failed\n", plugin->name);
rc = RPMRC_FAIL;
}
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
index 39762c376..ddf5d7048 100644
--- a/lib/rpmplugins.h
+++ b/lib/rpmplugins.h
@@ -156,6 +156,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
* permissions etc, but before committing file to destination path.
* @param plugins plugins structure
* @param fi file info iterator (or NULL)
+ * @param fd file descriptor (or -1 if not available)
* @param path file object current path
* @param dest file object destination path
* @param mode file object mode
@@ -164,7 +165,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
*/
RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
- const char *path, const char *dest,
+ int fd, const char *path, const char *dest,
mode_t mode, rpmFsmOp op);
#ifdef __cplusplus
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
index 7ac44f0d0..1ff50c30f 100644
--- a/plugins/fapolicyd.c
+++ b/plugins/fapolicyd.c
@@ -145,7 +145,8 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
}
static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
- const char *path, const char *dest,
+ int fd, const char *path,
+ const char *dest,
mode_t file_mode, rpmFsmOp op)
{
/* not ready */
--- a/plugins/ima.c 2020-04-28 14:50:11.835399269 +0200
+++ b/plugins/ima.c 2023-12-13 11:19:58.835948660 +0100
@@ -39,7 +39,7 @@
return (memcmp(fsig, &zero_hdr, sizeof(zero_hdr)) == 0);
}
-static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,
const char *path,
const char *dest,
mode_t file_mode, rpmFsmOp op)
@@ -63,8 +63,14 @@
fsig = rpmfiFSignature(fi, &len);
if (fsig && (check_zero_hdr(fsig, len) == 0)) {
- if (lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0) < 0) {
- rpmlog(RPMLOG_ERR,
+ int xx;
+ if (fd >= 0)
+ xx = fsetxattr(fd, XATTR_NAME_IMA, fsig, len, 0);
+ else
+ xx = lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0);
+ if (xx < 0) {
+ int is_err = errno != EOPNOTSUPP;
+ rpmlog(is_err?RPMLOG_ERR:RPMLOG_DEBUG,
"ima: could not apply signature on '%s': %s\n",
path, strerror(errno));
rc = RPMRC_FAIL;
--- a/plugins/selinux.c 2023-12-13 11:21:54.935009141 +0100
+++ b/plugins/selinux.c 2023-12-13 11:22:23.172510285 +0100
@@ -149,7 +149,7 @@
return rc;
}
-static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,
const char *path, const char *dest,
mode_t file_mode, rpmFsmOp op)
{
@@ -159,14 +159,17 @@
if (sehandle && !XFA_SKIPPING(action)) {
security_context_t scon = NULL;
if (selabel_lookup_raw(sehandle, &scon, dest, file_mode) == 0) {
- int conrc = lsetfilecon(path, scon);
+ int conrc;
+ if (fd >= 0)
+ conrc = fsetfilecon(fd, scon);
+ else
+ conrc = lsetfilecon(path, scon);
if (conrc == 0 || (conrc < 0 && errno == EOPNOTSUPP))
rc = RPMRC_OK;
- rpmlog((rc != RPMRC_OK) ? RPMLOG_ERR : RPMLOG_DEBUG,
- "lsetfilecon: (%s, %s) %s\n",
- path, scon, (conrc < 0 ? strerror(errno) : ""));
+ rpmlog((rc != RPMRC_OK) ? RPMLOG_ERR : RPMLOG_DEBUG, "lsetfilecon: (%d %s, %s) %s\n",
+ fd, path, scon, (conrc < 0 ? strerror(errno) : ""));
freecon(scon);
} else {

View File

@ -0,0 +1,32 @@
From f1503ab6e898430b80017c0f8347860f3a74d5bb Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Mon, 11 Dec 2023 15:50:15 +0100
Subject: [PATCH] Print full path if file removal fails
For normal debug output the basename of the files are sufficient as when
debugging is enabled the directories are also printed. But here the
warning is given without a debug flag so we need the full context right
there.
---
lib/fsm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index fcd764648..2189bd84c 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -1174,9 +1174,9 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
if (rc) {
int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
- rpmlog(lvl, _("%s %s: remove failed: %s\n"),
+ rpmlog(lvl, _("%s %s%s: remove failed: %s\n"),
S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"),
- fp->fpath, strerror(errno));
+ rpmfiDN(fi), fp->fpath, strerror(errno));
}
}
--
2.43.0

View File

@ -0,0 +1,90 @@
From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 15 Feb 2022 11:34:37 +0200
Subject: [PATCH] Swap over to dirfd+basename based operation within the fsm
Within fsm this is just a matter of adjusting error messages to include
the directory... if it only wasn't for the plugins requiring absolute
paths for outside users. For the plugins, we need to assemble absolute
paths as needed, both in ensureDir() and plugin file slots.
---
lib/rpmplugins.c | 20 +++++++++++++++++---
2 files changed, 36 insertions(+), 14 deletions(-)
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
index 703368c0d..f06fd7895 100644
--- a/lib/rpmplugins.c
+++ b/lib/rpmplugins.c
@@ -350,21 +350,31 @@ rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int ty
return rc;
}
+static char *abspath(rpmfi fi, const char *path)
+{
+ if (*path == '/')
+ return xstrdup(path);
+ else
+ return rstrscat(NULL, rpmfiDN(fi), path, NULL);
+}
+
rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
mode_t file_mode, rpmFsmOp op)
{
plugin_fsm_file_pre_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
+ char *apath = abspath(fi, path);
for (i = 0; i < plugins->count; i++) {
rpmPlugin plugin = plugins->plugins[i];
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {
+ if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) {
rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
rc = RPMRC_FAIL;
}
}
+ free(apath);
return rc;
}
@@ -375,14 +385,16 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
plugin_fsm_file_post_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
+ char *apath = abspath(fi, path);
for (i = 0; i < plugins->count; i++) {
rpmPlugin plugin = plugins->plugins[i];
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_post);
- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, res) == RPMRC_FAIL) {
+ if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op, res) == RPMRC_FAIL) {
rpmlog(RPMLOG_WARNING, "Plugin %s: hook fsm_file_post failed\n", plugin->name);
}
}
+ free(apath);
return rc;
}
@@ -394,15 +406,17 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
plugin_fsm_file_prepare_func hookFunc;
int i;
rpmRC rc = RPMRC_OK;
+ char *apath = abspath(fi, path);
for (i = 0; i < plugins->count; i++) {
rpmPlugin plugin = plugins->plugins[i];
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);
- if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {
+ if (hookFunc && hookFunc(plugin, fi, fd, apath, dest, file_mode, op) == RPMRC_FAIL) {
rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_prepare failed\n", plugin->name);
rc = RPMRC_FAIL;
}
}
+ free(apath);
return rc;
}
--
2.41.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
From acbf558c486ee3518aca74045504f05872da4a58 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Tue, 26 Sep 2023 13:14:44 +0200
Subject: [PATCH] brp-python-bytecompile compatibility with newer pythons
---
scripts/brp-python-bytecompile | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile
index 4a9b49e..472bf10 100644
--- a/scripts/brp-python-bytecompile
+++ b/scripts/brp-python-bytecompile
@@ -58,7 +58,7 @@ EOF
# and below /usr/lib/python3.1/, we're targeting /usr/bin/python3.1
shopt -s nullglob
-for python_libdir in `find "$RPM_BUILD_ROOT" -type d|grep -E "/usr/lib(64)?/python[0-9]\.[0-9]$"`;
+for python_libdir in `find "$RPM_BUILD_ROOT" -type d|grep -E "/usr/lib(64)?/python[0-9]\.[0-9]+$"`;
do
python_binary=/usr/bin/$(basename $python_libdir)
if [ "$python_binary" = "/usr/bin/python3.6" ]; then
@@ -97,17 +97,17 @@ fi
# Figure out if there are files to be bytecompiled with the default_python at all
# this prevents unnecessary default_python invocation
-find "$RPM_BUILD_ROOT" -type f -name "*.py" | grep -Ev "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" || exit 0
+find "$RPM_BUILD_ROOT" -type f -name "*.py" | grep -Ev "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" || exit 0
# Generate normal (.pyc) byte-compiled files.
-python_bytecompile "" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"
+python_bytecompile "" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
# One or more of the files had a syntax error
exit 1
fi
# Generate optimized (.pyo) byte-compiled files.
-python_bytecompile "-O" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"
+python_bytecompile "-O" $default_python "/bin/|/sbin/|/usr/lib(64)?/python[0-9]\.[0-9]+|/usr/share/doc" "$RPM_BUILD_ROOT" "$depth" "/"
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
# One or more of the files had a syntax error
exit 1
--
2.41.0

View File

@ -0,0 +1,197 @@
From 013cd4ba63c35fa75feeccde0022d56e68bc5845 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Mon, 16 Aug 2021 18:21:02 +0200
Subject: [PATCH] Add support for RPMDBI_BASENAMES on file queries
There are legitimate reasons (such as rhbz#1940895 or the included test)
for wanting the former behavior where all file states were considered in
file queries prior to commit 9ad57bda4a82b9847826daa766b4421d877bb3d9,
so celebrate the tenth anniversary of that commit by adding a CLI switch
(a new package selector --path), as contemplated back then.
Update the man page for --file to reflect it's current behavior and make
--path that more obvious.
Resolves: rhbz#1940895
Combined with:
d1aebda01033bc8ba0d748b49f6fad9a5c0caa3f
f62b6d27cd741406a52a7e9c5b1d6f581dbd3af8
Backported for 4.14.3.
---
doc/rpm.8 | 9 ++++++--
lib/poptQV.c | 6 +++++-
lib/query.c | 7 +++++--
lib/rpmcli.h | 1 +
tests/rpmquery.at | 52 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/doc/rpm.8 b/doc/rpm.8
index 15a3db25f..74604c8ec 100644
--- a/doc/rpm.8
+++ b/doc/rpm.8
@@ -57,7 +57,7 @@ rpm \- RPM Package Manager
.PP
[\fB\fIPACKAGE_NAME\fB\fR]
- [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR]
+ [\fB-a,--all [\fISELECTOR\fR]\fR] [\fB-f,--file \fIFILE\fB\fR] [\fB--path \fIPATH\fB\fR]
[\fB-g,--group \fIGROUP\fB\fR] {\fB-p,--package \fIPACKAGE_FILE\fB\fR]
[\fB--hdrid \fISHA1\fB\fR] [\fB--pkgid \fIMD5\fB\fR] [\fB--tid \fITID\fB\fR]
[\fB--querybynumber \fIHDRNUM\fB\fR] [\fB--triggeredby \fIPACKAGE_NAME\fB\fR]
@@ -555,7 +555,7 @@ starts with "b".
List duplicated packages.
.TP
\fB-f, --file \fIFILE\fB\fR
-Query package owning \fIFILE\fR.
+Query package owning installed \fIFILE\fR.
.TP
\fB--filecaps\fR
List file names with POSIX1.e capabilities.
@@ -598,6 +598,11 @@ that will be expanded to paths that are substituted in place of
the package manifest as additional \fIPACKAGE_FILE\fR
arguments to the query.
.TP
+\fB--path \fIPATH\fB\fR
+Query package(s) owning \fIPATH\fR, whether the file is installed or not.
+Multiple packages may own a \fIPATH\fR, but the file is only owned by the
+package installed last.
+.TP
\fB--pkgid \fIMD5\fB\fR
Query package that contains a given package identifier, i.e. the
\fIMD5\fR digest of the combined header and
diff --git a/lib/poptQV.c b/lib/poptQV.c
index 9021d7b3c..f752d8b82 100644
--- a/lib/poptQV.c
+++ b/lib/poptQV.c
@@ -27,6 +27,7 @@ struct rpmQVKArguments_s rpmQVKArgs;
#define POPT_WHATENHANCES -1014
#define POPT_WHATOBSOLETES -1015
#define POPT_WHATCONFLICTS -1016
+#define POPT_QUERYBYPATH -1017
/* ========== Query/Verify/Signature source args */
static void rpmQVSourceArgCallback( poptContext con,
@@ -58,6 +59,7 @@ static void rpmQVSourceArgCallback( poptContext con,
case POPT_WHATSUPPLEMENTS: qva->qva_source |= RPMQV_WHATSUPPLEMENTS; break;
case POPT_WHATENHANCES: qva->qva_source |= RPMQV_WHATENHANCES; break;
case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY; break;
+ case POPT_QUERYBYPATH: qva->qva_source |= RPMQV_PATH_ALL; break;
case POPT_QUERYBYPKGID: qva->qva_source |= RPMQV_PKGID; break;
case POPT_QUERYBYHDRID: qva->qva_source |= RPMQV_HDRID; break;
case POPT_QUERYBYTID: qva->qva_source |= RPMQV_TID; break;
@@ -80,7 +82,9 @@ struct poptOption rpmQVSourcePoptTable[] = {
{ "checksig", 'K', POPT_ARGFLAG_DOC_HIDDEN, NULL, 'K',
N_("rpm checksig mode"), NULL },
{ "file", 'f', 0, 0, 'f',
- N_("query/verify package(s) owning file"), "FILE" },
+ N_("query/verify package(s) owning installed file"), "FILE" },
+ { "path", '\0', 0, 0, POPT_QUERYBYPATH,
+ N_("query/verify package(s) owning path, installed or not"), "PATH" },
{ "group", 'g', 0, 0, 'g',
N_("query/verify package(s) in group"), "GROUP" },
{ "package", 'p', 0, 0, 'p',
diff --git a/lib/query.c b/lib/query.c
index 26cdecf10..e6ea1fa2d 100644
--- a/lib/query.c
+++ b/lib/query.c
@@ -440,6 +440,7 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar
}
/* fallthrough on absolute and relative paths */
case RPMQV_PATH:
+ case RPMQV_PATH_ALL:
{ char * fn;
for (s = arg; *s != '\0'; s++)
@@ -458,8 +459,10 @@ static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * ar
fn = xstrdup(arg);
(void) rpmCleanPath(fn);
- /* XXX Add a switch to enable former BASENAMES behavior? */
- mi = rpmtsInitIterator(ts, RPMDBI_INSTFILENAMES, fn, 0);
+ rpmDbiTagVal tag = RPMDBI_INSTFILENAMES;
+ if (qva->qva_source == RPMQV_PATH_ALL)
+ tag = RPMDBI_BASENAMES;
+ mi = rpmtsInitIterator(ts, tag, fn, 0);
if (mi == NULL)
mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0);
diff --git a/lib/rpmcli.h b/lib/rpmcli.h
index 99af2585a..c0d07d137 100644
--- a/lib/rpmcli.h
+++ b/lib/rpmcli.h
@@ -102,6 +102,7 @@ enum rpmQVSources_e {
RPMQV_SPECBUILTRPMS, /*!< ... from pkgs which would be built from spec */
RPMQV_WHATOBSOLETES, /*!< ... from obsoletes db search. */
RPMQV_WHATCONFLICTS, /*!< ... from conflicts db search. */
+ RPMQV_PATH_ALL, /*!< ... from file path db search (all states). */
};
typedef rpmFlags rpmQVSources;
diff --git a/tests/rpmquery.at b/tests/rpmquery.at
index 36c62339a..ad580f664 100644
--- a/tests/rpmquery.at
+++ b/tests/rpmquery.at
@@ -194,6 +194,58 @@ runroot rpm \
AT_CLEANUP
+# ------------------------------
+# query a package by a file
+AT_SETUP([rpm -qf])
+AT_KEYWORDS([query])
+AT_CHECK([
+RPMDB_INIT
+runroot rpm \
+ --nodeps \
+ -i /data/RPMS/hello-1.0-1.i386.rpm
+runroot rpm \
+ -qf /usr/local/bin/hello
+],
+[0],
+[hello-1.0-1.i386
+],
+[])
+AT_CLEANUP
+
+AT_SETUP([rpm -qf on non-installed file])
+AT_KEYWORDS([query])
+AT_CHECK([
+RPMDB_INIT
+runroot rpm \
+ --nodeps \
+ --excludedocs \
+ -i /data/RPMS/hello-1.0-1.i386.rpm
+runroot rpm \
+ -qf /usr/share/doc/hello-1.0/FAQ
+],
+[1],
+[],
+[error: file /usr/share/doc/hello-1.0/FAQ: No such file or directory
+])
+AT_CLEANUP
+
+AT_SETUP([rpm -q --path on non-installed file])
+AT_KEYWORDS([query])
+AT_CHECK([
+RPMDB_INIT
+runroot rpm \
+ --nodeps \
+ --excludedocs \
+ -i /data/RPMS/hello-1.0-1.i386.rpm
+runroot rpm \
+ -q --path /usr/share/doc/hello-1.0/FAQ
+],
+[0],
+[hello-1.0-1.i386
+],
+[])
+AT_CLEANUP
+
# ------------------------------
AT_SETUP([integer array query])
AT_KEYWORDS([query])
--
2.35.1

View File

@ -0,0 +1,798 @@
From 34790c335fe6e5e1099c9320d7b3134398104120 Mon Sep 17 00:00:00 2001
Message-Id: <34790c335fe6e5e1099c9320d7b3134398104120.1624429665.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 23 Jun 2021 08:24:44 +0300
Subject: [PATCH] Add read-only support for sqlite
Based on latest upstream sqlite backend version, chainsaw write support
out and adjust for the infra differences (which there are more than a
few) and add an error message instead.
---
configure.ac | 23 ++
lib/Makefile.am | 6 +
lib/backend/dbi.c | 14 +
lib/backend/dbi.h | 5 +
lib/backend/sqlite.c | 659 +++++++++++++++++++++++++++++++++++++++++++
macros.in | 1 +
6 files changed, 708 insertions(+)
create mode 100644 lib/backend/sqlite.c
diff --git a/configure.ac b/configure.ac
index 3fcb3ff20..e04aced68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -589,6 +589,29 @@ AS_IF([test "$enable_ndb" = yes],[
])
AM_CONDITIONAL([NDB], [test "$enable_ndb" = yes])
+# Check for SQLITE support
+AC_ARG_ENABLE([sqlite],
+ [AS_HELP_STRING([--enable-sqlite=@<:@yes/no/auto@:>@)],
+ [build with sqlite rpm database format support (default=yes)])],
+ [enable_sqlite="$enableval"],
+ [enable_sqlite=yes])
+
+AS_IF([test "x$enable_sqlite" != "xno"], [
+ PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.22.0], [have_sqlite=yes], [have_sqlite=no])
+ AS_IF([test "$enable_sqlite" = "yes"], [
+ if test "$have_sqlite" = "no"; then
+ AC_MSG_ERROR([--enable-sqlite specified, but not available])
+ fi
+ ])
+])
+
+if test "x$have_sqlite" = "xyes"; then
+ AC_DEFINE([WITH_SQLITE], [1], [Define if SQLITE is available])
+ SQLITE_REQUIRES=sqlite
+ AC_SUBST(SQLITE_REQUIRES)
+fi
+AM_CONDITIONAL([SQLITE], [test "x$have_sqlite" = "xyes"])
+
#=================
# Check for LMDB support
AC_ARG_ENABLE([lmdb],
diff --git a/lib/Makefile.am b/lib/Makefile.am
index baf3238ee..8a9fe77bd 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -76,6 +76,12 @@ librpm_la_SOURCES += \
backend/ndb/rpmxdb.h
endif
+if SQLITE
+AM_CPPFLAGS += $(SQLITE_CFLAGS)
+librpm_la_LIBADD += $(SQLITE_LIBS)
+librpm_la_SOURCES += backend/sqlite.c
+endif
+
if LMDB
AM_CPPFLAGS += $(LMDB_CFLAGS)
librpm_la_LIBADD += $(LMDB_LIBS)
diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c
index e99a5f2b2..dc3587f58 100644
--- a/lib/backend/dbi.c
+++ b/lib/backend/dbi.c
@@ -48,6 +48,11 @@ dbDetectBackend(rpmdb rdb)
if (!strcmp(db_backend, "ndb")) {
rdb->db_ops = &ndb_dbops;
} else
+#endif
+#ifdef WITH_SQLITE
+ if (!strcmp(db_backend, "sqlite")) {
+ rdb->db_ops = &sqlite_dbops;
+ } else
#endif
{
rdb->db_ops = &db3_dbops;
@@ -75,6 +80,15 @@ dbDetectBackend(rpmdb rdb)
free(path);
#endif
+#ifdef WITH_SQLITE
+ path = rstrscat(NULL, dbhome, "/rpmdb.sqlite", NULL);
+ if (access(path, F_OK) == 0 && rdb->db_ops != &sqlite_dbops) {
+ rdb->db_ops = &sqlite_dbops;
+ rpmlog(RPMLOG_WARNING, _("Found SQLITE rpmdb.sqlite database while attempting %s backend: using sqlite backend.\n"), db_backend);
+ }
+ free(path);
+#endif
+
path = rstrscat(NULL, dbhome, "/Packages", NULL);
if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) {
rdb->db_ops = &db3_dbops;
diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h
index 02f49c8fd..ff2b4f974 100644
--- a/lib/backend/dbi.h
+++ b/lib/backend/dbi.h
@@ -275,6 +275,11 @@ RPM_GNUC_INTERNAL
extern struct rpmdbOps_s lmdb_dbops;
#endif
+#if defined(WITH_SQLITE)
+RPM_GNUC_INTERNAL
+extern struct rpmdbOps_s sqlite_dbops;
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c
new file mode 100644
index 000000000..3caeba5f0
--- /dev/null
+++ b/lib/backend/sqlite.c
@@ -0,0 +1,659 @@
+#include "system.h"
+
+#include <sqlite3.h>
+#include <fcntl.h>
+
+#include <rpm/rpmlog.h>
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmmacro.h>
+#include "lib/rpmdb_internal.h"
+
+#include "debug.h"
+
+static const int sleep_ms = 50;
+
+struct dbiCursor_s {
+ sqlite3 *sdb;
+ sqlite3_stmt *stmt;
+ const char *fmt;
+ int flags;
+ rpmTagVal tag;
+ int ctype;
+ struct dbiCursor_s *subc;
+
+ const void *key;
+ unsigned int keylen;
+};
+
+static int sqlexec(sqlite3 *sdb, const char *fmt, ...);
+
+static void rpm_match3(sqlite3_context *sctx, int argc, sqlite3_value **argv)
+{
+ int match = 0;
+ if (argc == 3) {
+ int b1len = sqlite3_value_bytes(argv[0]);
+ int b2len = sqlite3_value_bytes(argv[1]);
+ int n = sqlite3_value_int(argv[2]);
+ if (b1len >= n && b2len >= n) {
+ const char *b1 = sqlite3_value_blob(argv[0]);
+ const char *b2 = sqlite3_value_blob(argv[1]);
+ match = (memcmp(b1, b2, n) == 0);
+ }
+ }
+ sqlite3_result_int(sctx, match);
+}
+
+static void errCb(void *data, int err, const char *msg)
+{
+ rpmdb rdb = data;
+ rpmlog(RPMLOG_WARNING, "%s: %s: %s\n",
+ rdb->db_descr, sqlite3_errstr(err), msg);
+}
+
+static int dbiCursorReset(dbiCursor dbc)
+{
+ if (dbc->stmt) {
+ sqlite3_reset(dbc->stmt);
+ sqlite3_clear_bindings(dbc->stmt);
+ }
+ return 0;
+}
+
+static int dbiCursorResult(dbiCursor dbc)
+{
+ int rc = sqlite3_errcode(dbc->sdb);
+ int err = (rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW);
+ if (err) {
+ rpmlog(RPMLOG_ERR, "%s: %d: %s\n", sqlite3_sql(dbc->stmt),
+ sqlite3_errcode(dbc->sdb), sqlite3_errmsg(dbc->sdb));
+ }
+ return err ? RPMRC_FAIL : RPMRC_OK;
+}
+
+static int dbiCursorPrep(dbiCursor dbc, const char *fmt, ...)
+{
+ if (dbc->stmt == NULL) {
+ char *cmd = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ cmd = sqlite3_vmprintf(fmt, ap);
+ va_end(ap);
+
+ sqlite3_prepare_v2(dbc->sdb, cmd, -1, &dbc->stmt, NULL);
+ sqlite3_free(cmd);
+ } else {
+ dbiCursorReset(dbc);
+ }
+
+ return dbiCursorResult(dbc);
+}
+
+static int dbiCursorBindPkg(dbiCursor dbc, unsigned int hnum,
+ void *blob, unsigned int bloblen)
+{
+ int rc = 0;
+
+ if (hnum)
+ rc = sqlite3_bind_int(dbc->stmt, 1, hnum);
+ else
+ rc = sqlite3_bind_null(dbc->stmt, 1);
+
+ if (blob) {
+ if (!rc)
+ rc = sqlite3_bind_blob(dbc->stmt, 2, blob, bloblen, NULL);
+ }
+ return dbiCursorResult(dbc);
+}
+
+static int dbiCursorBindIdx(dbiCursor dbc, const void *key, int keylen,
+ dbiIndexItem rec)
+{
+ int rc;
+ if (dbc->ctype == SQLITE_TEXT) {
+ rc = sqlite3_bind_text(dbc->stmt, 1, key, keylen, NULL);
+ } else {
+ rc = sqlite3_bind_blob(dbc->stmt, 1, key, keylen, NULL);
+ }
+
+ if (rec) {
+ if (!rc)
+ rc = sqlite3_bind_int(dbc->stmt, 2, rec->hdrNum);
+ if (!rc)
+ rc = sqlite3_bind_int(dbc->stmt, 3, rec->tagNum);
+ }
+
+ return dbiCursorResult(dbc);
+}
+
+static int sqlite_init(rpmdb rdb, const char * dbhome)
+{
+ int rc = 0;
+ char *dbfile = NULL;
+
+ if (rdb->db_dbenv == NULL) {
+ dbfile = rpmGenPath(dbhome, "rpmdb.sqlite", NULL);
+ sqlite3 *sdb = NULL;
+ int xx, flags = 0;
+ int retry_open = 1;
+
+ free(rdb->db_descr);
+ rdb->db_descr = xstrdup("sqlite");
+
+ if ((rdb->db_mode & O_ACCMODE) == O_RDONLY)
+ flags |= SQLITE_OPEN_READONLY;
+ else {
+ rpmlog(RPMLOG_ERR,
+ _("unable to open sqlite database %s for writing, sqlite support is read-only\n"), dbfile);
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ while (retry_open--) {
+ xx = sqlite3_open_v2(dbfile, &sdb, flags, NULL);
+ /* Attempt to create if missing, discarding OPEN_READONLY (!) */
+ if (xx == SQLITE_CANTOPEN && (flags & SQLITE_OPEN_READONLY)) {
+ /* Sqlite allocates resources even on failure to open (!) */
+ sqlite3_close(sdb);
+ flags &= ~SQLITE_OPEN_READONLY;
+ flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+ retry_open++;
+ }
+ }
+
+ if (xx != SQLITE_OK) {
+ rpmlog(RPMLOG_ERR, _("Unable to open sqlite database %s: %s\n"),
+ dbfile, sqlite3_errstr(xx));
+ rc = 1;
+ goto exit;
+ }
+
+ sqlite3_create_function(sdb, "match", 3,
+ (SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ NULL, rpm_match3, NULL, NULL);
+
+ sqlite3_busy_timeout(sdb, sleep_ms);
+ sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb);
+
+ sqlexec(sdb, "PRAGMA secure_delete = OFF");
+ sqlexec(sdb, "PRAGMA case_sensitive_like = ON");
+
+ if (sqlite3_db_readonly(sdb, NULL) == 0) {
+ if (sqlexec(sdb, "PRAGMA journal_mode = WAL") == 0) {
+ int one = 1;
+ /* Annoying but necessary to support non-privileged readers */
+ sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL, &one);
+
+ if (!rpmExpandNumeric("%{?_flush_io}"))
+ sqlexec(sdb, "PRAGMA wal_autocheckpoint = 0");
+ }
+ }
+
+ rdb->db_dbenv = sdb;
+ }
+ rdb->db_opens++;
+
+exit:
+ free(dbfile);
+ return rc;
+}
+
+static int sqlite_fini(rpmdb rdb)
+{
+ int rc = 0;
+ if (rdb) {
+ sqlite3 *sdb = rdb->db_dbenv;
+ if (rdb->db_opens > 1) {
+ rdb->db_opens--;
+ } else {
+ if (sqlite3_db_readonly(sdb, NULL) == 0) {
+ sqlexec(sdb, "PRAGMA optimize");
+ sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE");
+ }
+ rdb->db_dbenv = NULL;
+ int xx = sqlite3_close(sdb);
+ rc = (xx != SQLITE_OK);
+ }
+ }
+
+ return rc;
+}
+
+static int sqlexec(sqlite3 *sdb, const char *fmt, ...)
+{
+ int rc = 0;
+ char *cmd = NULL;
+ char *err = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ cmd = sqlite3_vmprintf(fmt, ap);
+ va_end(ap);
+
+ /* sqlite3_exec() doesn't seeem to honor sqlite3_busy_timeout() */
+ while ((rc = sqlite3_exec(sdb, cmd, NULL, NULL, &err)) == SQLITE_BUSY) {
+ usleep(sleep_ms);
+ }
+
+ if (rc)
+ rpmlog(RPMLOG_ERR, "sqlite failure: %s: %s\n", cmd, err);
+ else
+ rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc);
+
+ sqlite3_free(cmd);
+
+ return rc ? RPMRC_FAIL : RPMRC_OK;
+}
+
+static int dbiExists(dbiIndex dbi)
+{
+ const char *col = (dbi->dbi_type == DBI_PRIMARY) ? "hnum" : "key";
+ const char *tbl = dbi->dbi_file;
+ int rc = sqlite3_table_column_metadata(dbi->dbi_db, NULL, tbl, col,
+ NULL, NULL, NULL, NULL, NULL);
+ return (rc == 0);
+}
+
+static int init_table(dbiIndex dbi, rpmTagVal tag)
+{
+ int rc = 0;
+
+ if (dbiExists(dbi))
+ return 0;
+
+ if (dbi->dbi_type == DBI_PRIMARY) {
+ rc = sqlexec(dbi->dbi_db,
+ "CREATE TABLE IF NOT EXISTS '%q' ("
+ "hnum INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "blob BLOB NOT NULL"
+ ")",
+ dbi->dbi_file);
+ } else {
+ const char *keytype = (rpmTagGetClass(tag) == RPM_STRING_CLASS) ?
+ "TEXT" : "BLOB";
+ rc = sqlexec(dbi->dbi_db,
+ "CREATE TABLE IF NOT EXISTS '%q' ("
+ "key '%q' NOT NULL, "
+ "hnum INTEGER NOT NULL, "
+ "idx INTEGER NOT NULL, "
+ "FOREIGN KEY (hnum) REFERENCES 'Packages'(hnum)"
+ ")",
+ dbi->dbi_file, keytype);
+ }
+ if (!rc)
+ dbi->dbi_flags |= DBI_CREATED;
+
+ return rc;
+}
+
+static int create_index(sqlite3 *sdb, const char *table, const char *col)
+{
+ return sqlexec(sdb,
+ "CREATE INDEX IF NOT EXISTS '%s_%s_idx' ON '%q'(%s ASC)",
+ table, col, table, col);
+}
+
+static int init_index(dbiIndex dbi, rpmTagVal tag)
+{
+ int rc = 0;
+
+ /* Can't create on readonly database, but things will still work */
+ if (sqlite3_db_readonly(dbi->dbi_db, NULL) == 1)
+ return 0;
+
+ if (dbi->dbi_type == DBI_SECONDARY) {
+ int string = (rpmTagGetClass(tag) == RPM_STRING_CLASS);
+ int array = (rpmTagGetReturnType(tag) == RPM_ARRAY_RETURN_TYPE);
+ if (!rc && string)
+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "key");
+ if (!rc && array)
+ rc = create_index(dbi->dbi_db, dbi->dbi_file, "hnum");
+ }
+ return rc;
+}
+
+static int sqlite_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
+{
+ int rc = sqlite_init(rdb, rpmdbHome(rdb));
+
+ if (!rc) {
+ dbiIndex dbi = dbiNew(rdb, rpmtag);
+ dbi->dbi_db = rdb->db_dbenv;
+
+ rc = init_table(dbi, rpmtag);
+
+ if (!rc && !(rdb->db_flags & RPMDB_FLAG_REBUILD))
+ rc = init_index(dbi, rpmtag);
+
+ if (!rc && dbip)
+ *dbip = dbi;
+ else
+ dbiFree(dbi);
+ }
+
+ return rc;
+}
+
+static int sqlite_Close(dbiIndex dbi, unsigned int flags)
+{
+ rpmdb rdb = dbi->dbi_rpmdb;
+ int rc = 0;
+ if (rdb->db_flags & RPMDB_FLAG_REBUILD)
+ rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file));
+ sqlite_fini(dbi->dbi_rpmdb);
+ dbiFree(dbi);
+ return rc;
+}
+
+static int sqlite_Verify(dbiIndex dbi, unsigned int flags)
+{
+ int errors = -1;
+ int key_errors = -1;
+ sqlite3_stmt *s = NULL;
+ const char *cmd = "PRAGMA integrity_check";
+
+ if (dbi->dbi_type == DBI_SECONDARY)
+ return RPMRC_OK;
+
+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
+ errors = 0;
+ while (sqlite3_step(s) == SQLITE_ROW) {
+ const char *txt = (const char *)sqlite3_column_text(s, 0);
+ if (!rstreq(txt, "ok")) {
+ errors++;
+ rpmlog(RPMLOG_ERR, "verify: %s\n", txt);
+ }
+ }
+ sqlite3_finalize(s);
+ } else {
+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
+ }
+
+ /* No point checking higher-level errors if low-level errors exist */
+ if (errors)
+ goto exit;
+
+ cmd = "PRAGMA foreign_key_check";
+ if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
+ key_errors = 0;
+ while (sqlite3_step(s) == SQLITE_ROW) {
+ key_errors++;
+ rpmlog(RPMLOG_ERR, "verify key: %s[%lld]\n",
+ sqlite3_column_text(s, 0),
+ sqlite3_column_int64(s, 1));
+ }
+ sqlite3_finalize(s);
+ } else {
+ rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
+ }
+
+exit:
+
+ return (errors == 0 && key_errors == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
+
+static void sqlite_SetFSync(rpmdb rdb, int enable)
+{
+ if (rdb->db_dbenv) {
+ sqlexec(rdb->db_dbenv,
+ "PRAGMA synchronous = %s", enable ? "FULL" : "OFF");
+ }
+}
+
+static int sqlite_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
+{
+ int rc = 0;
+
+ switch (ctrl) {
+ case DB_CTRL_LOCK_RW:
+ rc = sqlexec(rdb->db_dbenv, "SAVEPOINT 'rwlock'");
+ break;
+ case DB_CTRL_UNLOCK_RW:
+ rc = sqlexec(rdb->db_dbenv, "RELEASE 'rwlock'");
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static dbiCursor sqlite_CursorInit(dbiIndex dbi, unsigned int flags)
+{
+ dbiCursor dbc = xcalloc(1, sizeof(*dbc));
+ dbc->sdb = dbi->dbi_db;
+ dbc->flags = flags;
+ dbc->tag = rpmTagGetValue(dbi->dbi_file);
+ if (rpmTagGetClass(dbc->tag) == RPM_STRING_CLASS) {
+ dbc->ctype = SQLITE_TEXT;
+ } else {
+ dbc->ctype = SQLITE_BLOB;
+ }
+ if (dbc->flags & DBC_WRITE)
+ sqlexec(dbc->sdb, "SAVEPOINT '%s'", dbi->dbi_file);
+ return dbc;
+}
+
+static dbiCursor sqlite_CursorFree(dbiIndex dbi, dbiCursor dbc)
+{
+ if (dbc) {
+ sqlite3_finalize(dbc->stmt);
+ if (dbc->subc)
+ dbiCursorFree(dbi, dbc->subc);
+ if (dbc->flags & DBC_WRITE)
+ sqlexec(dbc->sdb, "RELEASE '%s'", dbi->dbi_file);
+ free(dbc);
+ }
+ return NULL;
+}
+
+static rpmRC sqlite_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
+{
+ return RPMRC_FAIL;
+}
+
+static rpmRC sqlite_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
+{
+ return RPMRC_FAIL;
+}
+
+static rpmRC sqlite_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
+{
+ return RPMRC_FAIL;
+}
+
+static rpmRC sqlite_stepPkg(dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc = sqlite3_step(dbc->stmt);
+
+ if (rc == SQLITE_ROW) {
+ if (hdrLen)
+ *hdrLen = sqlite3_column_bytes(dbc->stmt, 1);
+ if (hdrBlob)
+ *hdrBlob = (void *) sqlite3_column_blob(dbc->stmt, 1);
+ }
+ return rc;
+}
+
+static rpmRC sqlite_pkgdbByKey(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q' WHERE hnum=?",
+ dbi->dbi_file);
+
+ if (!rc)
+ rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0);
+
+ if (!rc)
+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
+
+ return dbiCursorResult(dbc);
+}
+
+static rpmRC sqlite_pkgdbIter(dbiIndex dbi, dbiCursor dbc,
+ unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc = RPMRC_OK;
+ if (dbc->stmt == NULL) {
+ rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q'", dbi->dbi_file);
+ }
+
+ if (!rc)
+ rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
+
+ if (rc == SQLITE_DONE) {
+ rc = RPMRC_NOTFOUND;
+ } else {
+ rc = dbiCursorResult(dbc);
+ }
+
+ return rc;
+}
+
+static rpmRC sqlite_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
+{
+ int rc;
+
+ if (hdrNum) {
+ rc = sqlite_pkgdbByKey(dbi, dbc, hdrNum, hdrBlob, hdrLen);
+ } else {
+ rc = sqlite_pkgdbIter(dbi, dbc, hdrBlob, hdrLen);
+ }
+
+ return rc;
+}
+
+static unsigned int sqlite_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
+{
+ return sqlite3_column_int(dbc->stmt, 0);
+}
+
+static rpmRC sqlite_idxdbByKey(dbiIndex dbi, dbiCursor dbc,
+ const char *keyp, size_t keylen, int searchType,
+ dbiIndexSet *set)
+{
+ int rc = RPMRC_NOTFOUND;
+
+ if (searchType == DBC_PREFIX_SEARCH) {
+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' "
+ "WHERE MATCH(key,'%q',%d) "
+ "ORDER BY key",
+ dbi->dbi_file, keyp, keylen);
+ } else {
+ rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' WHERE key=?",
+ dbi->dbi_file);
+ if (!rc)
+ rc = dbiCursorBindIdx(dbc, keyp, keylen, NULL);
+ }
+
+
+ if (!rc) {
+ while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {
+ unsigned int hnum = sqlite3_column_int(dbc->stmt, 0);
+ unsigned int tnum = sqlite3_column_int(dbc->stmt, 1);
+
+ if (*set == NULL)
+ *set = dbiIndexSetNew(5);
+ dbiIndexSetAppendOne(*set, hnum, tnum, 0);
+ }
+ }
+
+ if (rc == SQLITE_DONE) {
+ rc = (*set) ? RPMRC_OK : RPMRC_NOTFOUND;
+ } else {
+ rc = dbiCursorResult(dbc);
+ }
+
+ return rc;
+}
+
+static rpmRC sqlite_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set)
+{
+ int rc = RPMRC_OK;
+
+ if (dbc->stmt == NULL) {
+ rc = dbiCursorPrep(dbc, "SELECT DISTINCT key FROM '%q' ORDER BY key",
+ dbi->dbi_file);
+ if (set)
+ dbc->subc = dbiCursorInit(dbi, 0);
+ }
+
+ if (!rc)
+ rc = sqlite3_step(dbc->stmt);
+
+ if (rc == SQLITE_ROW) {
+ if (dbc->ctype == SQLITE_TEXT) {
+ dbc->key = sqlite3_column_text(dbc->stmt, 0);
+ } else {
+ dbc->key = sqlite3_column_blob(dbc->stmt, 0);
+ }
+ dbc->keylen = sqlite3_column_bytes(dbc->stmt, 0);
+ if (dbc->subc) {
+ rc = sqlite_idxdbByKey(dbi, dbc->subc, dbc->key, dbc->keylen,
+ DBC_NORMAL_SEARCH, set);
+ } else {
+ rc = RPMRC_OK;
+ }
+ } else if (rc == SQLITE_DONE) {
+ rc = RPMRC_NOTFOUND;
+ } else {
+ rc = dbiCursorResult(dbc);
+ }
+
+ return rc;
+}
+
+static rpmRC sqlite_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType)
+{
+ int rc;
+ if (keyp) {
+ rc = sqlite_idxdbByKey(dbi, dbc, keyp, keylen, searchType, set);
+ } else {
+ rc = sqlite_idxdbIter(dbi, dbc, set);
+ }
+
+ return rc;
+}
+
+static rpmRC sqlite_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return RPMRC_FAIL;
+}
+
+static rpmRC sqlite_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
+{
+ return RPMRC_FAIL;
+}
+
+static const void * sqlite_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
+{
+ const void *key = NULL;
+ if (dbc) {
+ key = dbc->key;
+ if (key && keylen)
+ *keylen = dbc->keylen;
+ }
+ return key;
+}
+
+struct rpmdbOps_s sqlite_dbops = {
+ .open = sqlite_Open,
+ .close = sqlite_Close,
+ .verify = sqlite_Verify,
+ .setFSync = sqlite_SetFSync,
+ .ctrl = sqlite_Ctrl,
+
+ .cursorInit = sqlite_CursorInit,
+ .cursorFree = sqlite_CursorFree,
+
+ .pkgdbPut = sqlite_pkgdbPut,
+ .pkgdbDel = sqlite_pkgdbDel,
+ .pkgdbGet = sqlite_pkgdbGet,
+ .pkgdbKey = sqlite_pkgdbKey,
+ .pkgdbNew = sqlite_pkgdbNew,
+
+ .idxdbGet = sqlite_idxdbGet,
+ .idxdbPut = sqlite_idxdbPut,
+ .idxdbDel = sqlite_idxdbDel,
+ .idxdbKey = sqlite_idxdbKey
+};
+
diff --git a/macros.in b/macros.in
index a6069ee4d..9ad3d60ef 100644
--- a/macros.in
+++ b/macros.in
@@ -620,6 +620,7 @@ package or when debugging this package.\
# bdb Berkeley DB
# lmdb Lightning Memory-mapped Database
# ndb new data base format
+# sqlite Sqlite database (read-only in this version!)
#
%_db_backend bdb
--
2.31.1

View File

@ -0,0 +1,167 @@
From 534fd1f0c84b12ba6080a46e07c57ef913c77cba Mon Sep 17 00:00:00 2001
From: Radovan Sroka <rsroka@redhat.com>
Date: Thu, 25 Aug 2022 15:38:01 +0200
Subject: [PATCH] fapolicyd: Make write() nonblocking
- switch to read only and non blocking mode for pipe
- add 1 minute loop to wait for pipe to reappear
Sometimes during the system update/upgrade fapolicyd
get restarted e.g. when systemd gets updated.
That can lead to the situation where fapolicyd pipe
has been removed and created again.
In such cases rpm-plugin-fapolicyd gets stuck on
write() to the pipe which does not exist anymore.
After switching to non blocking file descriptor
we can try to reopen the pipe if there is an error
from write(). Assuming that a new pipe should appear
when fapolicyd daemon starts again.
If not then after 1 minute of waiting we expect
fapolicyd daemon to be not active and we let the
transaction continue.
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
---
plugins/fapolicyd.c | 74 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 65 insertions(+), 9 deletions(-)
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
index 1ff50c30f..6c6322941 100644
--- a/plugins/fapolicyd.c
+++ b/plugins/fapolicyd.c
@@ -27,7 +27,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
int fd = -1;
struct stat s;
- fd = open(state->fifo_path, O_RDWR);
+ fd = open(state->fifo_path, O_WRONLY|O_NONBLOCK);
if (fd == -1) {
rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
goto bad;
@@ -55,15 +55,26 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
}
state->fd = fd;
+
/* considering success */
return RPMRC_OK;
bad:
if (fd >= 0)
close(fd);
+
+ state->fd = -1;
return RPMRC_FAIL;
}
+static void close_fifo(struct fapolicyd_data* state)
+{
+ if (state->fd > 0)
+ (void) close(state->fd);
+
+ state->fd = -1;
+}
+
static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
{
ssize_t len = strlen(str);
@@ -86,6 +97,54 @@ static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
return RPMRC_FAIL;
}
+static void try_to_write_to_fifo(struct fapolicyd_data* state, const char * str)
+{
+ int reload = 0;
+ int printed = 0;
+
+ /* 1min/60s */
+ const int timeout = 60;
+
+ /* wait up to X seconds */
+ for (int i = 0; i < timeout; i++) {
+
+ if (reload) {
+ if (!printed) {
+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: waiting for the service connection to resume, it can take up to %d seconds\n", timeout);
+ printed = 1;
+ }
+
+ (void) close_fifo(state);
+ (void) open_fifo(state);
+ }
+
+ if (state->fd >= 0) {
+ if (write_fifo(state, str) == RPMRC_OK) {
+
+ /* write was successful after few reopens */
+ if (reload)
+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has resumed\n");
+
+ break;
+ }
+ }
+
+ /* failed write or reopen */
+ reload = 1;
+ sleep(1);
+
+ /* the last iteration */
+ /* consider failure */
+ if (i == timeout-1) {
+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has not resumed\n");
+ rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: continuing without the service\n");
+ }
+
+ }
+
+}
+
+
static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
{
if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
@@ -102,10 +161,7 @@ static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
static void fapolicyd_cleanup(rpmPlugin plugin)
{
- if (fapolicyd_state.fd > 0)
- (void) close(fapolicyd_state.fd);
-
- fapolicyd_state.fd = -1;
+ (void) close_fifo(&fapolicyd_state);
}
static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
@@ -116,9 +172,9 @@ static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
/* we are ready */
if (fapolicyd_state.fd > 0) {
/* send a signal that transaction is over */
- (void) write_fifo(&fapolicyd_state, "1\n");
+ (void) try_to_write_to_fifo(&fapolicyd_state, "1\n");
/* flush cache */
- (void) write_fifo(&fapolicyd_state, "2\n");
+ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
}
end:
@@ -133,7 +189,7 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
if (fapolicyd_state.changed_files > 0) {
/* send signal to flush cache */
- (void) write_fifo(&fapolicyd_state, "2\n");
+ (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
/* optimize flushing */
/* flush only when there was an actual change */
@@ -176,7 +232,7 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
char * sha = rpmfiFDigestHex(fi, NULL);
snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
- (void) write_fifo(&fapolicyd_state, buffer);
+ (void) try_to_write_to_fifo(&fapolicyd_state, buffer);
free(sha);
--
2.37.3

View File

@ -0,0 +1,184 @@
From f17aa638649fb8de730fecdbc906dc869b626ba5 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 16 Nov 2021 11:49:18 +0200
Subject: [PATCH 1/2] Fix spurious %transfiletriggerpostun execution
(RhBug:2023311)
If a package has multiple %transfiletriggerpostun triggers, any one
of them matching would cause all of them to run, due to disconnect
in the intel gathering stage: we'd gather all the headers with matching
files into a lump, and then add any postun triggers found in them,
but this loses the triggering file information and causes all postuns
to run.
The triggers need to be added while looping over the file matches,
like runFileTriggers() does. Doing so actually simplifies the code.
These should really be unified to use the same code, but leaving
that exercise to another rainy day.
---
lib/rpmtriggers.c | 64 +++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 33 deletions(-)
diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
index 0827af0c2..dc457f7cc 100644
--- a/lib/rpmtriggers.c
+++ b/lib/rpmtriggers.c
@@ -97,19 +97,37 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs)
}
}
+static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter)
+{
+ int tix = 0;
+ rpmds ds;
+ rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
+
+ while ((ds = rpmdsFilterTi(triggers, tix))) {
+ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) {
+ struct rpmtd_s priorities;
+
+ if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
+ &priorities, HEADERGET_MINMEM)) {
+ rpmtdSetIndex(&priorities, tix);
+ rpmtriggersAdd(ts->trigs2run, headerGetInstance(trigH),
+ tix, *rpmtdGetUint32(&priorities));
+ }
+ }
+ rpmdsFree(ds);
+ tix++;
+ }
+ rpmdsFree(triggers);
+}
+
void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
{
- rpmdbMatchIterator mi;
rpmdbIndexIterator ii;
- Header trigH;
const void *key;
size_t keylen;
rpmfiles files;
- rpmds rpmdsTriggers;
- rpmds rpmdsTrigger;
ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME);
- mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES);
files = rpmteFiles(te);
/* Iterate over file triggers in rpmdb */
@@ -121,39 +139,19 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
rpmfi fi = rpmfilesFindPrefix(files, pfx);
while (rpmfiNext(fi) >= 0) {
if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
- /* If yes then store it */
- rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii),
- rpmdbIndexIteratorNumPkgs(ii));
- break;
+ unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii);
+ const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii);
+ /* Save any matching postun triggers */
+ for (int i = 0; i < npkg; i++) {
+ Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]);
+ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN);
+ headerFree(h);
+ }
}
}
rpmfiFree(fi);
}
rpmdbIndexIteratorFree(ii);
-
- if (rpmdbGetIteratorCount(mi)) {
- /* Filter triggers and save only trans postun triggers into ts */
- while ((trigH = rpmdbNextIterator(mi)) != NULL) {
- int tix = 0;
- rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
- while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) {
- if ((rpmdsNext(rpmdsTrigger) >= 0) &&
- (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) {
- struct rpmtd_s priorities;
-
- headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
- &priorities, HEADERGET_MINMEM);
- rpmtdSetIndex(&priorities, tix);
- rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi),
- tix, *rpmtdGetUint32(&priorities));
- }
- rpmdsFree(rpmdsTrigger);
- tix++;
- }
- rpmdsFree(rpmdsTriggers);
- }
- }
- rpmdbFreeIterator(mi);
rpmfilesFree(files);
}
--
2.35.1
From e617e7c550d3523998707c55f96b37ede2c48c78 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 2 Feb 2022 13:46:23 +0200
Subject: [PATCH 2/2] Really fix spurious %transfiletriggerpostun execution
(RhBug:2023311)
Commit b3d672a5523dfec033160e5cc866432a0e808649 got the base reasoning
in the ballpark but the code all wrong, introducing a severe performance
regression without actually fixing what it claimed to.
The missing incredient is actually comparing the current prefix with the
triggers in matched package (trying to describe this makes my head
spin): a package may have multiple triggers on multiple prefixes and
we need to make sure we only execute triggers of this type, from this
prefix.
This stuff really needs more and better testcases.
Fixes: b3d672a5523dfec033160e5cc866432a0e808649
---
lib/rpmtriggers.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
index dc457f7cc..c652981be 100644
--- a/lib/rpmtriggers.c
+++ b/lib/rpmtriggers.c
@@ -97,14 +97,16 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs)
}
}
-static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter)
+static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter,
+ const char *prefix)
{
int tix = 0;
rpmds ds;
rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
while ((ds = rpmdsFilterTi(triggers, tix))) {
- if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) {
+ if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter) &&
+ strcmp(prefix, rpmdsN(ds)) == 0) {
struct rpmtd_s priorities;
if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
@@ -141,12 +143,13 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii);
const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii);
- /* Save any matching postun triggers */
+ /* Save any postun triggers matching this prefix */
for (int i = 0; i < npkg; i++) {
Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]);
- addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN);
+ addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN, pfx);
headerFree(h);
}
+ break;
}
}
rpmfiFree(fi);
--
2.35.1

View File

@ -0,0 +1,327 @@
commit c7d7c5acd0c14d0450016887cba1d86483086794
Author: Michal Domonkos <mdomonko@redhat.com>
Date: Mon Jun 21 10:05:10 2021 +0200
Add quoting to literal curly brackets
These curly brackets are already treated as literals by the shell, so
let's make that explicit for clarity, and silence a ShellCheck warning
at the same time.
More info: https://github.com/koalaman/shellcheck/wiki/SC1083
Found by ShellCheck.
diff -up rpm-4.16.1.3/scripts/check-rpaths-worker.orig rpm-4.16.1.3/scripts/check-rpaths-worker
--- rpm-4.16.1.3/scripts/check-rpaths-worker.orig 2021-06-29 15:34:31.671003589 +0200
+++ rpm-4.16.1.3/scripts/check-rpaths-worker 2021-06-29 15:34:51.993414093 +0200
@@ -120,13 +120,13 @@ for i; do
(/lib64/*|/usr/lib64/*|/usr/X11R6/lib64/*|/usr/local/lib64/*)
badness=0;;
- (\$ORIGIN|\${ORIGINX}|\$ORIGIN/*|\${ORIGINX}/*)
+ (\$ORIGIN|\$\{ORIGINX\}|\$ORIGIN/*|\$\{ORIGINX\}/*)
test $allow_ORIGIN -eq 0 && badness=8 || {
badness=0
new_allow_ORIGIN=1
}
;;
- (/*\$PLATFORM*|/*\${PLATFORM}*|/*\$LIB*|/*\${LIB}*)
+ (/*\$PLATFORM*|/*\$\{PLATFORM\}*|/*\$LIB*|/*\$\{LIB\}*)
badness=0;;
(/lib|/usr/lib|/usr/X11R6/lib)
From d8dc4fd37b1d90cd97de7fcf484d449ec132c9b3 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Wed, 9 Jun 2021 21:31:40 +0200
Subject: [PATCH 1/7] Fix memory leak in sqlexec()
Callers are supposed to free the error strings themselves:
https://www.sqlite.org/capi3ref.html#sqlite3_exec
Found by Coverity.
---
lib/backend/sqlite.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c
index 7c2de45aa..dbefeb163 100644
--- a/lib/backend/sqlite.c
+++ b/lib/backend/sqlite.c
@@ -233,6 +233,7 @@ static int sqlexec(sqlite3 *sdb, const char *fmt, ...)
rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc);
sqlite3_free(cmd);
+ sqlite3_free(err);
return rc ? RPMRC_FAIL : RPMRC_OK;
}
--
2.31.1
From 5baf73feb4951cc3b3f553a4b18d3b3599cbf87c Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Fri, 25 Jun 2021 11:21:46 +0200
Subject: [PATCH 2/7] Always free the arg list passed to rpmGlob()
Even though the actual implementation of rpmGlob() does not allocate the
passed arg list (av) if the return code (rc) is non-zero or arg count
(ac) is 0, it's the responsibility of the caller (rpmInstall() here) to
free that memory, so make sure we do that irrespectively of the above
conditions.
Found by Coverity.
---
lib/rpminstall.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/rpminstall.c b/lib/rpminstall.c
index 724126e94..302ec0ba1 100644
--- a/lib/rpminstall.c
+++ b/lib/rpminstall.c
@@ -461,6 +461,7 @@ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv)
rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
}
eiu->numFailed++;
+ argvFree(av);
continue;
}
--
2.31.1
From 3c8b01b67ec907afaaffe71691fa41b878578527 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Mon, 14 Jun 2021 10:21:25 +0200
Subject: [PATCH 3/7] Fix resource leak in Fts_children()
This function is not used anywhere within our codebase (and neither is
it part of the public API) so it's basically a no-op... Still, rather
than yanking it completely, let's just silence the Coverity error here.
Found by Coverity.
---
misc/fts.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/misc/fts.c b/misc/fts.c
index d3ebb2946..caf27495d 100644
--- a/misc/fts.c
+++ b/misc/fts.c
@@ -585,8 +585,10 @@ Fts_children(FTS * sp, int instr)
if ((fd = __open(".", O_RDONLY, 0)) < 0)
return (NULL);
sp->fts_child = fts_build(sp, instr);
- if (__fchdir(fd))
+ if (__fchdir(fd)) {
+ (void)__close(fd);
return (NULL);
+ }
(void)__close(fd);
return (sp->fts_child);
}
--
2.31.1
From 39b7bf8579e0522cf16347b3a7e332d3b6d742c6 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Mon, 14 Jun 2021 12:34:23 +0200
Subject: [PATCH 4/7] Fix memory leak in fts_build()
Turns out this leak is already fixed in glibc's current version of fts.c
(where our copy originates from), so let's just backport that.
Original commit in glibc:
https://sourceware.org/git/?p=glibc.git;\
a=commit;h=db67c2c98b89a5723af44df54f38b779de8d4a65
Found by Coverity.
---
misc/fts.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/misc/fts.c b/misc/fts.c
index caf27495d..f7fce0eaa 100644
--- a/misc/fts.c
+++ b/misc/fts.c
@@ -855,6 +855,7 @@ mem1: saved_errno = errno;
fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
+ fts_lfree(head);
return (NULL);
}
@@ -862,6 +863,7 @@ mem1: saved_errno = errno;
if (!nitems) {
if (type == BREAD)
cur->fts_info = FTS_DP;
+ fts_lfree(head);
return (NULL);
}
--
2.31.1
From 9c093c4f092dd6bd1e0c8d2b852a72b74db076c2 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Tue, 15 Jun 2021 13:34:21 +0200
Subject: [PATCH 5/7] Fix memory leak in decodePkts()
Found by Coverity.
---
rpmio/rpmpgp.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index c59185dce..ee5c81e24 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -1371,9 +1371,13 @@ static pgpArmor decodePkts(uint8_t *b, uint8_t **pkt, size_t *pktlen)
crc = pgpCRC(dec, declen);
if (crcpkt != crc) {
ec = PGPARMOR_ERR_CRC_CHECK;
+ _free(dec);
goto exit;
}
- if (pkt) *pkt = dec;
+ if (pkt)
+ *pkt = dec;
+ else
+ _free(dec);
if (pktlen) *pktlen = declen;
ec = PGPARMOR_PUBKEY; /* XXX ASCII Pubkeys only, please. */
goto exit;
--
2.31.1
From 590b2fc06252567eb7d57197dc361a8b459d62a3 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Mon, 21 Jun 2021 17:51:14 +0200
Subject: [PATCH 6/7] Fix memory leak with multiple %lang-s in one line
We permit two equivalent forms of specifying a list of languages per
file:
%lang(xx,yy,zz) /path/to/file
%lang(xx) %lang(yy) %lang(zz) /path/to/file
The leak was when parsing the second form.
Found by Coverity.
---
build/files.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/build/files.c b/build/files.c
index f8153ad2b..0c8859f6c 100644
--- a/build/files.c
+++ b/build/files.c
@@ -777,6 +777,8 @@ static rpmRC parseForLang(char * buf, FileEntry cur)
if (*pe == ',') pe++; /* skip , if present */
}
+
+ q = _free(q);
}
rc = RPMRC_OK;
--
2.31.1
From b7a1e996326ee29a163d67ceb1e6127fdc251c14 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Fri, 25 Jun 2021 15:15:08 +0200
Subject: [PATCH 7/7] Fix memory leaks in Lua rex extension
This covers the following usage:
expr = rex.newPOSIX(<regex>)
expr:match(<string>) # A leak occurred here
expr:gmatch(<string>, <func>) # A leak occurred here
Found by Coverity.
---
luaext/lrexlib.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/luaext/lrexlib.c b/luaext/lrexlib.c
index 09c5a6454..0f29b6371 100644
--- a/luaext/lrexlib.c
+++ b/luaext/lrexlib.c
@@ -80,6 +80,7 @@ static void rex_push_matches(lua_State *L, const char *text, regmatch_t *match,
static int rex_match(lua_State *L)
{
+ int rc = 0;
int res;
#ifdef REG_BASIC
size_t len;
@@ -109,9 +110,10 @@ static int rex_match(lua_State *L)
lua_pushstring(L, "n");
lua_pushnumber(L, ncapt);
lua_rawset(L, -3);
- return 3;
- } else
- return 0;
+ rc = 3;
+ }
+ free(match);
+ return rc;
}
static int rex_gmatch(lua_State *L)
@@ -158,6 +160,7 @@ static int rex_gmatch(lua_State *L)
break;
}
lua_pushnumber(L, nmatch);
+ free(match);
return 1;
}
--
2.31.1
commit 9747a6af016a3458d54fe060777c95e3900b5fa4
Author: Demi Marie Obenour <athena@invisiblethingslab.com>
Date: Tue Mar 2 12:47:29 2021 -0500
Fix a tiny memory leak
Found by fuzzing rpmReadPackageFile() with libfuzzer under ASAN.
diff --git a/lib/headerutil.c b/lib/headerutil.c
index 22e36c74d..fab210ff2 100644
--- a/lib/headerutil.c
+++ b/lib/headerutil.c
@@ -333,8 +333,10 @@ static void providePackageNVR(Header h)
rpmds hds, nvrds;
/* Generate provides for this package name-version-release. */
- if (!(name && pEVR))
+ if (!(name && pEVR)) {
+ free(pEVR);
return;
+ }
/*
* Rpm prior to 3.0.3 does not have versioned provides.
commit cb2ae4bdf2f60876fdc68e3f84938e9c37182fab
Author: Igor Gnatenko <i.gnatenko.brain@gmail.com>
Date: Tue Feb 6 14:50:27 2018 +0100
lua: fix memory leak in Pexec()
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
diff --git a/luaext/lposix.c b/luaext/lposix.c
index 5d7ad3c87..2730bcff7 100644
--- a/luaext/lposix.c
+++ b/luaext/lposix.c
@@ -348,6 +348,7 @@ static int Pexec(lua_State *L) /** exec(path,[args]) */
for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
argv[i] = NULL;
execvp(path,argv);
+ free(argv);
return pusherror(L, path);
}

View File

@ -0,0 +1,38 @@
From 77007d68782b66f2d00d7b200516731246876dca Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 27 May 2021 13:58:58 +0300
Subject: [PATCH] Macroize find-debuginfo script location
Makes it easier to handle varying paths, mainly in preparation for the
next step.
Backported for 4.14.3.
---
macros.in | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/macros.in b/macros.in
index a6069ee4d..be28a3b28 100644
--- a/macros.in
+++ b/macros.in
@@ -82,6 +82,8 @@
%__remsh %{__rsh}
%__strip @__STRIP@
+%__find_debuginfo %{_rpmconfigdir}/find-debuginfo.sh
+
# XXX avoid failures if tools are not installed when rpm is built.
%__libtoolize libtoolize
%__aclocal aclocal
@@ -177,7 +179,7 @@
# the script. See the script for details.
#
%__debug_install_post \
- %{_rpmconfigdir}/find-debuginfo.sh \\\
+ %{__find_debuginfo} \\\
%{?_smp_mflags} \\\
%{?_missing_build_ids_terminate_build:--strict-build-id} \\\
%{?_no_recompute_build_ids:-n} \\\
--
2.33.1

View File

@ -1,48 +0,0 @@
commit cfdb8300f6e3aed0abc41406a3c4737eb1192067
Author: Michal Domonkos <mdomonko@redhat.com>
Date: Sun Jul 11 18:08:26 2021 +0200
Don't brp-strip .ko files
Otherwise SecureBoot signatures may be stripped too.
We used to exclude shared libraries from this strip as they were
supposed to be covered by another brp script (brp-strip-shared), however
it turned out the latter was never really used, so we removed the
exclusion in commit 0ab151ab138fd4fb6d3176fd0270d9cc6f4623f3.
As it turns out, that was a little too ambitious, since we may now
inadvertently strip SecureBoot signatures from kernel modules too,
provided that they're made during the build, prior to the invocation of
brp-strip.
Note that this regression currently does *not* affect the following two
cases on Fedora/RHEL systems with redhat-rpm-config installed:
- in-tree kernel modules; these are built from kernel.spec which
already contains a hack ensuring that module signing only happens
*after* any stripping (see %__modsign_install_post in kernel.spec)
- out-of-tree kernel modules built with debuginfo enabled; this is
because brp-strip is only called when %debug_package is set to
%{nil}
Any other combinations may be affected, depending on the macros and
.spec files used, so let's fix this by effectively "reverting" said
commit for .ko files only.
Fixes: rhbz#1967291
Backported into 4.14.3
diff -up rpm-4.14.3/scripts/brp-strip.orig rpm-4.14.3/scripts/brp-strip
--- rpm-4.14.3/scripts/brp-strip.orig 2021-07-12 17:21:04.446396789 +0200
+++ rpm-4.14.3/scripts/brp-strip 2021-07-12 17:21:20.673633783 +0200
@@ -12,7 +12,7 @@ Darwin*) exit 0 ;;
esac
# Strip ELF binaries
-for f in `find "$RPM_BUILD_ROOT" -type f -exec file {} \; | \
+for f in `find "$RPM_BUILD_ROOT" -type f \! -name "*.ko" -exec file {} \; | \
grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
sed -n -e 's/^\(.*\):[ ]*ELF.*, not stripped.*/\1/p'`; do
$STRIP -g "$f" || :

View File

@ -0,0 +1,29 @@
From fe274b8f965582fdf97e6c46f90b9e7c124b0b8b Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Fri, 16 Dec 2022 15:50:12 +0100
Subject: [PATCH] rpm2archive: Don't print usage on no arguments
given as we want to default to reading from stdin and writing to stdout in
that case.
---
rpm2archive.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/rpm2archive.c b/rpm2archive.c
index 09da8d16b..53f047f58 100644
--- a/rpm2archive.c
+++ b/rpm2archive.c
@@ -241,10 +241,6 @@ int main(int argc, const char *argv[])
exit(EXIT_FAILURE);
}
}
- if (argc < 2 || poptGetNextOpt(optCon) == 0) {
- poptPrintUsage(optCon, stderr, 0);
- exit(EXIT_FAILURE);
- }
rpmts ts = rpmtsCreate();
rpmVSFlags vsflags = 0;
--
2.38.1

View File

@ -0,0 +1,138 @@
From d8a169164cf40fc1cf6448792c1fa991f19bb375 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Thu, 22 Apr 2021 14:50:34 +0200
Subject: [PATCH] Add --nocompression option to rpm2archive
Also use popt for the command line handling. As we are using librpm
anyway there is no reason to keep the dependencies low (as with
rpm2cpio).
Resolves: #1530
---
doc/rpm2archive.8 | 16 ++++++++++---
rpm2archive.c | 60 ++++++++++++++++++++++++++++++++++-------------
2 files changed, 57 insertions(+), 19 deletions(-)
diff --git a/rpm2archive.c b/rpm2archive.c
index d96db006ea..cb39c7a712 100644
--- a/rpm2archive.c
+++ b/rpm2archive.c
@@ -10,6 +10,8 @@
#include <rpm/rpmts.h>
+#include <popt.h>
+
#include <archive.h>
#include <archive_entry.h>
#include <unistd.h>
@@ -18,6 +20,16 @@
#define BUFSIZE (128*1024)
+int compress = 1;
+
+static struct poptOption optionsTable[] = {
+ { "nocompression", 'n', POPT_ARG_VAL, &compress, 0,
+ N_("create uncompressed tar file"),
+ NULL },
+ POPT_AUTOHELP
+ POPT_TABLEEND
+};
+
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi)
{
archive_entry_clear(entry);
@@ -60,7 +72,7 @@ static void write_file_content(struct archive * a, char * buf, rpmfi fi)
}
}
-static int process_package(rpmts ts, char * filename)
+static int process_package(rpmts ts, const char * filename)
{
FD_t fdi;
FD_t gzdi;
@@ -119,9 +131,11 @@ static int process_package(rpmts ts, char * filename)
/* create archive */
a = archive_write_new();
- if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) {
- fprintf(stderr, "Error: Could not create gzip output filter\n");
- exit(EXIT_FAILURE);
+ if (compress) {
+ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) {
+ fprintf(stderr, "%s\n", archive_error_string(a));
+ exit(EXIT_FAILURE);
+ }
}
if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) {
fprintf(stderr, "Error: Format pax restricted is not supported\n");
@@ -142,7 +156,12 @@ static int process_package(rpmts ts, char * filename)
}
archive_write_open_fd(a, STDOUT_FILENO);
} else {
- char * outname = rstrscat(NULL, filename, ".tgz", NULL);
+ char * outname = rstrscat(NULL, filename, NULL);
+ if (compress) {
+ outname = rstrscat(&outname, ".tgz", NULL);
+ } else {
+ outname = rstrscat(&outname, ".tar", NULL);
+ }
if (archive_write_open_filename(a, outname) != ARCHIVE_OK) {
fprintf(stderr, "Error: Can't open output file: %s\n", outname);
exit(EXIT_FAILURE);
@@ -203,21 +222,22 @@ static int process_package(rpmts ts, char * filename)
return rc;
}
-int main(int argc, char *argv[])
+int main(int argc, const char *argv[])
{
- int rc = 0, i;
+ int rc = 0;
+ poptContext optCon;
+ const char *fn;
xsetprogname(argv[0]); /* Portability call -- see system.h */
rpmReadConfigFiles(NULL, NULL);
- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) {
- fprintf(stderr, "Usage: %s [file.rpm ...]\n", argv[0]);
+ optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
+ poptSetOtherOptionHelp(optCon, "[OPTIONS]* <FILES>");
+ if (argc < 2 || poptGetNextOpt(optCon) == 0) {
+ poptPrintUsage(optCon, stderr, 0);
exit(EXIT_FAILURE);
}
- if (argc == 1)
- argv[argc++] = "-"; /* abuse NULL pointer at the end of argv */
-
rpmts ts = rpmtsCreate();
rpmVSFlags vsflags = 0;
@@ -227,13 +247,21 @@ int main(int argc, char *argv[])
vsflags |= RPMVSF_NOHDRCHK;
(void) rpmtsSetVSFlags(ts, vsflags);
- for (i = 1; i < argc; i++) {
+ /* if no file name is given use stdin/stdout */
+ if (!poptPeekArg(optCon)) {
+ rc = process_package(ts, "-");
+ if (rc != 0)
+ goto exit;
+ }
- rc = process_package(ts, argv[i]);
+ while ((fn = poptGetArg(optCon)) != NULL) {
+ rc = process_package(ts, fn);
if (rc != 0)
- return rc;
+ goto exit;
}
+ exit:
+ poptFreeContext(optCon);
(void) rpmtsFree(ts);
return rc;
}

View File

@ -0,0 +1,36 @@
From 8f416b275a365426b07c75adfc017e0b18a85450 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Fri, 16 Dec 2022 15:45:20 +0100
Subject: [PATCH] rpm2archive: Properly parse popt options
and issue an error message for unknown options. Before unknown options
could mess up the argument parsing leading to reading and writing from
stdin/stdout.
Thanks to Eva Mrakova and the Red Hat QE team for spotting this!
---
rpm2archive.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/rpm2archive.c b/rpm2archive.c
index de1a17d2b..09da8d16b 100644
--- a/rpm2archive.c
+++ b/rpm2archive.c
@@ -233,6 +233,14 @@ int main(int argc, const char *argv[])
optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]* <FILES>");
+ while ((rc = poptGetNextOpt(optCon)) != -1) {
+ if (rc < 0) {
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ poptStrerror(rc));
+ exit(EXIT_FAILURE);
+ }
+ }
if (argc < 2 || poptGetNextOpt(optCon) == 0) {
poptPrintUsage(optCon, stderr, 0);
exit(EXIT_FAILURE);
--
2.38.1

View File

@ -0,0 +1,40 @@
From 2e61e5846f8301f85da9d30281538ea736d96fd0 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Tue, 7 Dec 2021 08:08:37 +0100
Subject: [PATCH] Skip recorded symlinks in --setperms (RhBug:1900662)
If a package contains a symlink in the buildroot which is declared as a
ghost or config file but is a regular file or directory on the system
where it's installed, a --setperms call will reset its permissions to
those of a symlink (777 on Linux), which almost certainly is not the
correct thing to do.
To fix that, just skip files that were recorded as symlinks.
This is a special case of a general issue in --setperms; since file
permission semantics may change depending on the file type, to stay on
the safe side, any (ghost or config) file whose type changes after
installation should probably be skipped. However, symlinks are the most
prominent case here, so let's just focus on that now and avoid adding
too much cleverness to a popt alias (this got us into trouble not too
long ago, see commits 38c2f6e and 0d83637). We may revisit this in the
eventual C implementation.
---
rpmpopt.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/rpmpopt.in b/rpmpopt.in
index 67fcabfb1..e130a5d05 100644
--- a/rpmpopt.in
+++ b/rpmpopt.in
@@ -44,6 +44,7 @@ rpm alias --scripts --qf '\
--POPTdesc=$"list install/erase scriptlets from package(s)"
rpm alias --setperms -q --qf '[\[ -L %{FILENAMES:shescape} \] || \
+ \[ -n %{FILELINKTOS:shescape} \] || \
( \[ $((%{FILEFLAGS} & 2#1001000)) != 0 \] && \[ ! -e %{FILENAMES:shescape} \] ) || \
chmod %7{FILEMODES:octal} %{FILENAMES:shescape}\n]' \
--pipe "grep -v \(none\) | grep '^. -L ' | sed 's/chmod .../chmod /' | sh" \
--
2.35.1

View File

@ -0,0 +1,401 @@
From 82c53e4b7f720012a391d8f6e5da9ee3c4f22bed Mon Sep 17 00:00:00 2001
From: Demi Marie Obenour <demi@invisiblethingslab.com>
Date: Thu, 6 May 2021 18:34:45 -0400
Subject: [PATCH] Validate and require subkey binding signatures on PGP public
keys
All subkeys must be followed by a binding signature by the primary key
as per the OpenPGP RFC, enforce the presence and validity in the parser.
The implementation is as kludgey as they come to work around our
simple-minded parser structure without touching API, to maximise
backportability. Store all the raw packets internally as we decode them
to be able to access previous elements at will, needed to validate ordering
and access the actual data. Add testcases for manipulated keys whose
import previously would succeed.
Combined with:
5ff86764b17f31535cb247543a90dd739076ec38
b5e8bc74b2b05aa557f663fe227b94d2bc64fbd8
9f03f42e2614a68f589f9db8fe76287146522c0c
b6dffb6dc5ffa2ddc389743f0507876cab341315 (mem-leak fix)
ae3d2d234ae47ff85229d3fce97a266fa1aa5a61 (use-after-free fix)
Fixes CVE-2021-3521.
---
rpmio/rpmpgp.c | 122 +++++++++++++++---
sign/rpmgensig.c | 2 +-
tests/Makefile.am | 3 +
tests/data/keys/CVE-2021-3521-badbind.asc | 25 ++++
.../data/keys/CVE-2021-3521-nosubsig-last.asc | 25 ++++
tests/data/keys/CVE-2021-3521-nosubsig.asc | 37 ++++++
tests/rpmsigdig.at | 28 ++++
7 files changed, 224 insertions(+), 18 deletions(-)
create mode 100644 tests/data/keys/CVE-2021-3521-badbind.asc
create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig-last.asc
create mode 100644 tests/data/keys/CVE-2021-3521-nosubsig.asc
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index 46cd0f31a..bd4992ec7 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -511,7 +511,7 @@ pgpDigAlg pgpDigAlgFree(pgpDigAlg alg)
return NULL;
}
-static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype,
+static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo,
const uint8_t *p, const uint8_t *h, size_t hlen,
pgpDigParams sigp)
{
@@ -524,10 +524,8 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype,
int mpil = pgpMpiLen(p);
if (p + mpil > pend)
break;
- if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) {
- if (sigalg->setmpi(sigalg, i, p))
- break;
- }
+ if (sigalg->setmpi(sigalg, i, p))
+ break;
p += mpil;
}
@@ -600,7 +598,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
}
p = ((uint8_t *)v) + sizeof(*v);
- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp);
+ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp);
} break;
case 4:
{ pgpPktSigV4 v = (pgpPktSigV4)h;
@@ -658,7 +656,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
if (p > (h + hlen))
return 1;
- rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp);
+ rc = pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp);
} break;
default:
rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version);
@@ -999,36 +997,127 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
return algo;
}
+static pgpDigParams pgpDigParamsNew(uint8_t tag)
+{
+ pgpDigParams digp = xcalloc(1, sizeof(*digp));
+ digp->tag = tag;
+ return digp;
+}
+
+static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag)
+{
+ int rc = -1;
+ if (pkt->tag == exptag) {
+ uint8_t head[] = {
+ 0x99,
+ (pkt->blen >> 8),
+ (pkt->blen ),
+ };
+
+ rpmDigestUpdate(hash, head, 3);
+ rpmDigestUpdate(hash, pkt->body, pkt->blen);
+ rc = 0;
+ }
+ return rc;
+}
+
+static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig,
+ const struct pgpPkt *all, int i)
+{
+ int rc = -1;
+ DIGEST_CTX hash = NULL;
+
+ switch (selfsig->sigtype) {
+ case PGPSIGTYPE_SUBKEY_BINDING:
+ hash = rpmDigestInit(selfsig->hash_algo, 0);
+ if (hash) {
+ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY);
+ if (!rc)
+ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY);
+ }
+ break;
+ default:
+ /* ignore types we can't handle */
+ rc = 0;
+ break;
+ }
+
+ if (hash && rc == 0)
+ rc = pgpVerifySignature(key, selfsig, hash);
+
+ rpmDigestFinal(hash, NULL, NULL, 0);
+
+ return rc;
+}
+
int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
pgpDigParams * ret)
{
const uint8_t *p = pkts;
const uint8_t *pend = pkts + pktlen;
pgpDigParams digp = NULL;
- struct pgpPkt pkt;
+ pgpDigParams selfsig = NULL;
+ int i = 0;
+ int alloced = 16; /* plenty for normal cases */
+ struct pgpPkt *all = xmalloc(alloced * sizeof(*all));
int rc = -1; /* assume failure */
+ int expect = 0;
+ int prevtag = 0;
while (p < pend) {
- if (decodePkt(p, (pend - p), &pkt))
+ struct pgpPkt *pkt = &all[i];
+ if (decodePkt(p, (pend - p), pkt))
break;
if (digp == NULL) {
- if (pkttype && pkt.tag != pkttype) {
+ if (pkttype && pkt->tag != pkttype) {
break;
} else {
- digp = xcalloc(1, sizeof(*digp));
- digp->tag = pkt.tag;
+ digp = pgpDigParamsNew(pkt->tag);
}
}
- if (pgpPrtPkt(&pkt, digp))
+ if (expect) {
+ if (pkt->tag != expect)
+ break;
+ selfsig = pgpDigParamsNew(pkt->tag);
+ }
+
+ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp))
break;
- p += (pkt.body - pkt.head) + pkt.blen;
+ if (selfsig) {
+ /* subkeys must be followed by binding signature */
+ int xx = 1; /* assume failure */
+
+ if (!(prevtag == PGPTAG_PUBLIC_SUBKEY &&
+ selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING))
+ xx = pgpVerifySelf(digp, selfsig, all, i);
+
+ selfsig = pgpDigParamsFree(selfsig);
+ if (xx)
+ break;
+ expect = 0;
+ }
+
+ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY)
+ expect = PGPTAG_SIGNATURE;
+ prevtag = pkt->tag;
+
+ i++;
+ p += (pkt->body - pkt->head) + pkt->blen;
+ if (pkttype == PGPTAG_SIGNATURE)
+ break;
+
+ if (alloced <= i) {
+ alloced *= 2;
+ all = xrealloc(all, alloced * sizeof(*all));
+ }
}
- rc = (digp && (p == pend)) ? 0 : -1;
+ rc = (digp && (p == pend) && expect == 0) ? 0 : -1;
+ free(all);
if (ret && rc == 0) {
*ret = digp;
} else {
@@ -1063,8 +1152,7 @@ int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen,
digps = xrealloc(digps, alloced * sizeof(*digps));
}
- digps[count] = xcalloc(1, sizeof(**digps));
- digps[count]->tag = PGPTAG_PUBLIC_SUBKEY;
+ digps[count] = pgpDigParamsNew(PGPTAG_PUBLIC_SUBKEY);
/* Copy UID from main key to subkey */
digps[count]->userid = xstrdup(mainkey->userid);
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 771d01098..b33fe996c 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -409,7 +409,7 @@ static int haveSignature(rpmtd sigtd, Header h)
pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2);
if (pgpDigParamsCmp(sig1, sig2) == 0)
rc = 1;
- pgpDigParamsFree(sig2);
+ sig2 = pgpDigParamsFree(sig2);
}
pgpDigParamsFree(sig1);
rpmtdFreeData(&oldtd);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5f5207e56..309347262 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -87,6 +87,9 @@ EXTRA_DIST += data/SPECS/hello-config-buildid.spec
EXTRA_DIST += data/SPECS/hello-cd.spec
EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub
EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret
+EXTRA_DIST += data/keys/CVE-2021-3521-badbind.asc
+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig.asc
+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig-last.asc
EXTRA_DIST += data/macros.testfile
# testsuite voodoo
diff --git a/tests/data/keys/CVE-2021-3521-badbind.asc b/tests/data/keys/CVE-2021-3521-badbind.asc
new file mode 100644
index 000000000..aea00f9d7
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-badbind.asc
@@ -0,0 +1,25 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE=
+=WCfs
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/data/keys/CVE-2021-3521-nosubsig-last.asc b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc
new file mode 100644
index 000000000..aea00f9d7
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc
@@ -0,0 +1,25 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE=
+=WCfs
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/data/keys/CVE-2021-3521-nosubsig.asc b/tests/data/keys/CVE-2021-3521-nosubsig.asc
new file mode 100644
index 000000000..3a2e7417f
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-nosubsig.asc
@@ -0,0 +1,37 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAG5AQ0EWOY5GAEIAKT68NmshdC4
+VcRhOhlXBvZq23NtskkKoPvW+ZlMuxbRDG48pGBtxhjOngriVUGceEWsXww5Q7En
+uRBYglkxkW34ENym0Ji6tsPYfhbbG+dZWKIL4vMIzPOIwlPrXrm558vgkdMM/ELZ
+8WIz3KtzvYubKUk2Qz+96lPXbwnlC/SBFRpBseJC5LoOb/5ZGdR/HeLz1JXiacHF
+v9Nr3cZWqg5yJbDNZKfASdZgC85v3kkvhTtzknl//5wqdAMexbuwiIh2xyxbO+B/
+qqzZFrVmu3sV2Tj5lLZ/9p1qAuEM7ULbixd/ld8yTmYvQ4bBlKv2bmzXtVfF+ymB
+Tm6BzyQEl/MAEQEAAYkBHwQYAQgACQUCWOY5GAIbDAAKCRBDRFkeGWTF/PANB/9j
+mifmj6z/EPe0PJFhrpISt9PjiUQCt0IPtiL5zKAkWjHePIzyi+0kCTBF6DDLFxos
+3vN4bWnVKT1kBhZAQlPqpJTg+m74JUYeDGCdNx9SK7oRllATqyu+5rncgxjWVPnQ
+zu/HRPlWJwcVFYEVXYL8xzfantwQTqefjmcRmBRdA2XJITK+hGWwAmrqAWx+q5xX
+Pa8wkNMxVzNS2rUKO9SoVuJ/wlUvfoShkJ/VJ5HDp3qzUqncADfdGN35TDzscngQ
+gHvnMwVBfYfSCABV1hNByoZcc/kxkrWMmsd/EnIyLd1Q1baKqc3cEDuC6E6/o4yJ
+E4XX4jtDmdZPreZALsiB
+=rRop
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at
index 09fcdd525..a74f400ae 100644
--- a/tests/rpmsigdig.at
+++ b/tests/rpmsigdig.at
@@ -212,6 +212,34 @@ UNW2iqnN3BA7guhOv6OMiROF1+I7Q5nWT63mQC7IgQ==
[])
AT_CLEANUP
+AT_SETUP([rpmkeys --import invalid keys])
+AT_KEYWORDS([rpmkeys import])
+RPMDB_INIT
+
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-badbind.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-badbind.asc: key 1 import failed.]
+)
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-nosubsig.asc: key 1 import failed.]
+)
+
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig-last.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-nosubsig-last.asc: key 1 import failed.]
+)
+AT_CLEANUP
+
# ------------------------------
# Test pre-built package verification
AT_SETUP([rpmkeys -K <signed> 1])
--
2.34.1

View File

@ -0,0 +1,51 @@
From f1634250587479d664b34b6de1a6546b2c2b9de5 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Mon, 18 Jan 2021 15:02:34 +0100
Subject: [PATCH] rpm2archive: Add more error handling
Cleanly error out if file can't be written instead of segfaulting
Resolves: #1091
---
rpm2archive.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/rpm2archive.c b/rpm2archive.c
index 646f1663d..15c5da016 100644
--- a/rpm2archive.c
+++ b/rpm2archive.c
@@ -119,9 +119,14 @@ static int process_package(rpmts ts, char * filename)
/* create archive */
a = archive_write_new();
- archive_write_add_filter_gzip(a);
- archive_write_set_format_pax_restricted(a);
-
+ if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) {
+ fprintf(stderr, "Error: Could not create gzip output filter\n");
+ exit(EXIT_FAILURE);
+ }
+ if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) {
+ fprintf(stderr, "Error: Format pax restricted is not supported\n");
+ exit(EXIT_FAILURE);
+ }
if (!strcmp(filename, "-")) {
if (isatty(STDOUT_FILENO)) {
fprintf(stderr, "Error: refusing to output archive data to a terminal.\n");
@@ -130,9 +135,11 @@ static int process_package(rpmts ts, char * filename)
archive_write_open_fd(a, STDOUT_FILENO);
} else {
char * outname = rstrscat(NULL, filename, ".tgz", NULL);
- archive_write_open_filename(a, outname);
+ if (archive_write_open_filename(a, outname) != ARCHIVE_OK) {
+ fprintf(stderr, "Error: Can't open output file: %s\n", outname);
+ exit(EXIT_FAILURE);
+ }
_free(outname);
- // XXX error handling
}
entry = archive_entry_new();
--
2.38.1

View File

@ -18,6 +18,8 @@
%bcond_without zstd
# build with lmdb support?
%bcond_with lmdb
# build with readonly sqlite support?
%bcond_without sqlite
%if 0%{?rhel} > 7
# Disable python2 build by default
@ -30,7 +32,7 @@
%global rpmver 4.14.3
#global snapver rc2
%global rel 15
%global rel 31
%global srcver %{version}%{?snapver:-%{snapver}}
%global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x}
@ -104,14 +106,33 @@ Patch151: 0001-Unblock-signals-in-forked-scriptlets.patch
Patch152: rpm-4.14.3-fix-ambiguous-diagnostics-on-file-triggers.patch
Patch153: rpm-4.14.3-ELF-files-strip-when-debuginfo-disabled.patch
Patch154: rpm-4.14.3-more-careful-sig-hdr-copy.patch
Patch155: rpm-4.14.3-preserve-kmod-secure-boot-signature.patch
Patch156: rpm-4.14.3-hdrblobInit-add-bounds-check.patch
Patch157: rpm-4.14.3-add-read-only-support-for-sqlite.patch
Patch158: rpm-4.14.3-imp-covscan-fixes.patch
Patch159: rpm-4.14.3-add-path-query-option.patch
Patch160: rpm-4.14.3-macroize-find-debuginfo-script-location.patch
Patch161: rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch
Patch162: rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch
Patch163: rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch
Patch164: rpm-4.14.3-fapolicyd-make-write-nonblocking.patch
Patch165: rpm-4.16.1.3-rpm2archive-error-handling.patch
Patch166: rpm-4.14.3-rpm2archive-nocompression.patch
Patch167: rpm-4.14.3-rpm2archive-parse-popt-options.patch
Patch168: rpm-4.14.3-rpm2archive-Don-t-print-usage.patch
# Backport fsm to fix CVEs
Patch169: 0001-Eliminate-code-duplication-from-rpmfiNext.patch
Patch170: 0001-Add-optional-callback-on-directory-changes-during-rp.patch
Patch171: 0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch
Patch172: 0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch
Patch173: 0001-Use-file-state-machine-from-rpm-4.19.patch
Patch174: 0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch
Patch175: 0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch
Patch176: 0001-Print-full-path-if-file-removal-fails.patch
Patch177: 0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch
# Python 3 string API sanity
Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch
Patch501: 0001-Return-NULL-string-as-None-from-utf8FromString.patch
# Temporary compat crutch, not upstream
Patch502: 0001-Monkey-patch-.decode-method-to-our-strings-as-a-temp.patch
# Make test-suite work with Python 3
Patch503: 0001-Honor-PYTHON-from-configure-when-running-tests.patch
Patch504: 0002-Use-Python-3-compatible-exception-syntax-in-tests.patch
@ -139,6 +160,8 @@ Patch1000: disable-python-extra.patch
Patch1001: compile-with-Platform-Python-binary-where-relevant.patch
# make unversioned %%__python an error unless explicitly overridden
Patch1002: rpm-4.14.2-unversioned-python.patch
# Make brp-python-bytecompile compatible with Python 3.10+
Patch1003: brp-python-bytecompile-compatibility-with-newer-pyth.patch
# Partially GPL/LGPL dual-licensed and some bits with BSD
# SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD
@ -179,6 +202,9 @@ BuildRequires: lua-devel >= 5.1
BuildRequires: libcap-devel
BuildRequires: libacl-devel
BuildRequires: audit-libs-devel
%if %{with sqlite}
BuildRequires: sqlite-devel
%endif
%if %{with xz}
BuildRequires: xz-devel >= 4.999.8
%endif
@ -461,6 +487,7 @@ done;
%{?with_libimaevm: --with-imaevm} \
%{?with_zstd: --enable-zstd} \
%{?with_lmdb: --enable-lmdb} \
%{?with_sqlite: --enable-sqlite} \
--with-fapolicyd \
--enable-python \
--with-crypto=openssl \
@ -684,6 +711,49 @@ make check || cat tests/rpmtests.log
%doc doc/librpm/html/*
%changelog
* Tue Dec 12 2023 Florian Festi <ffesti@redhat.com> - 4.14.3-31
- Backport file handling code from rpm-4.19 to fix CVE-2021-35937,
CVE-2021-35938 and CVE-2021-35939
* Tue Sep 26 2023 Lumír Balhar <lbalhar@redhat.com> - 4.14.3-27
- Make brp-python-bytecompile script compatible with Python 3.10+
Resolves: RHEL-6423
* Mon Dec 19 2022 Florian Festi <ffesti@redhat.com> - 4.14.3-26
- Add --nocompression to rpm2archive (#2129345)
* Tue Sep 13 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-24
- Make write() nonblocking in fapolicyd plugin (#2110787)
* Tue Apr 05 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-23
- Fix minor ABI regression in rpmcli.h (#1940895)
* Tue Feb 15 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-22
- Fix spurious %transfiletriggerpostun execution (#2023693)
- Skip recorded symlinks in --setperms (#1900662)
* Mon Jan 10 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-21
- Address covscan issues in binding sigs validation patch (#1958480)
* Thu Dec 09 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-20
- Add --path query option (#1940895)
- Macroize find-debuginfo script location (#2019540)
- Validate and require subkey binding sigs on PGP pubkeys (#1958480)
- Fixes CVE-2021-3521
* Wed Oct 06 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-19
- Unbreak in-tree kmod strip by reverting brp-strip fix (#1967291)
* Thu Aug 26 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-18
- Address important covscan issues (#1996665), vol. 2
* Mon Aug 23 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-17
- Address important covscan issues (#1996665)
* Thu Aug 19 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-16
- Add support for read-only sqlite rpmdb (#1938928)
- Drop compat .decode() method from returned Py3 strings (#1840142)
* Thu Jul 15 2021 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-15
- Add out-of-bounds checks to hdrblobInit() (#1929445)
- Fixes CVE-2021-20266