import rpm-4.14.3-31.el8

i8c-beta changed/i8c-beta/rpm-4.14.3-31.el8
MSVSphere Packaging Team 9 months ago
commit f35ca8f4b6

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/rpm-4.14.3.tar.bz2

@ -0,0 +1 @@
3f8c3ef08f93eaeef12008055a43f6872306f8a2 SOURCES/rpm-4.14.3.tar.bz2

@ -0,0 +1,93 @@
From 1da9e839bb573b9187403983f5a69853ab364306 Mon Sep 17 00:00:00 2001
From: Pavlina Moravcova Varekova <pmoravco@redhat.com>
Date: Sun, 17 Mar 2019 06:47:26 +0100
Subject: [PATCH] Add flag to use strip -g instead of full strip on DSOs
(RhBug:1663264)
The find-debuginfo.sh flag -g had exactly this meaning. But from
version rpm-4.13.0-alpha flag -g changes its behavior. It affects
both libraries and executables.
For some packages the original behavior was preferred. That is why
the new find-debuginfo.sh flag --g-libs is created.
Options -g and --g-libs are mutually exclusive.
Adjusted for rpm-4.14.2 in RHEL
--- rpm-4.14.2/scripts/find-debuginfo.sh.orig 2019-04-24 15:14:29.351010878 +0200
+++ rpm-4.14.2/scripts/find-debuginfo.sh 2019-04-24 15:19:42.296240705 +0200
@@ -4,6 +4,7 @@
#
# Usage: find-debuginfo.sh [--strict-build-id] [-g] [-r] [-m] [-i] [-n]
# [--keep-section SECTION] [--remove-section SECTION]
+# [--g-libs]
# [-j N] [--jobs N]
# [-o debugfiles.list]
# [-S debugsourcefiles.list]
@@ -16,6 +17,8 @@
# [builddir]
#
# The -g flag says to use strip -g instead of full strip on DSOs or EXEs.
+# The --g-libs flag says to use strip -g instead of full strip ONLY on DSOs.
+# Options -g and --g-libs are mutually exclusive.
# The -r flag says to use eu-strip --reloc-debug-sections.
# Use --keep-section SECTION or --remove-section SECTION to explicitly
# keep a (non-allocated) section in the main executable or explicitly
@@ -68,6 +71,9 @@
# With -g arg, pass it to strip on libraries or executables.
strip_g=false
+# With --g-libs arg, pass it to strip on libraries.
+strip_glibs=false
+
# with -r arg, pass --reloc-debug-sections to eu-strip.
strip_r=false
@@ -135,6 +141,9 @@
unique_debug_src_base=$2
shift
;;
+ --g-libs)
+ strip_glibs=true
+ ;;
-g)
strip_g=true
;;
@@ -204,6 +213,11 @@
exit 2
fi
+if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then
+ echo >&2 "*** ERROR: -g and --g-libs cannot be used together"
+ exit 2
+fi
+
i=0
while ((i < nout)); do
outs[$i]="$BUILDDIR/${outs[$i]}"
@@ -237,6 +251,9 @@
application/x-executable*) g=-g ;;
application/x-pie-executable*) g=-g ;;
esac
+ $strip_glibs && case "$(file -bi "$2")" in
+ application/x-sharedlib*) g=-g ;;
+ esac
eu-strip --remove-comment $r $g ${keep_remove_args} -f "$1" "$2" || exit
chmod 444 "$1" || exit
}
@@ -430,8 +430,12 @@
# libraries. Other executable ELF files (like kernel modules) don't need it.
if [ "$include_minidebug" = "true" -a "$strip_g" = "false" ]; then
skip_mini=true
+ if [ "$strip_glibs" = "false" ]; then
+ case "$(file -bi "$f")" in
+ application/x-sharedlib*) skip_mini=false ;;
+ esac
+ fi
case "$(file -bi "$f")" in
- application/x-sharedlib*) skip_mini=false ;;
application/x-executable*) skip_mini=false ;;
application/x-pie-executable*) skip_mini=false ;;
esac

@ -0,0 +1,44 @@
From f00bb5be9caa62220c6aeaf3f7264840d5c089e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Tue, 5 Feb 2019 18:15:47 +0100
Subject: [PATCH] Add limits to autopatch macro
Limits allow to apply only range of patches with given parameters.
Useful if something needs to be done between patch sets. Allows applying
of patches with different -pX parameter in one spec file.
Resolves: #626
Co-authored-by: Florian Festi <ffesti@redhat.com>
---
macros.in | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/macros.in b/macros.in
index 7b5b63020..912ad5997 100644
--- a/macros.in
+++ b/macros.in
@@ -1265,11 +1265,19 @@ else\
end}
# Automatically apply all patches
-%autopatch(vp:)\
+# -m<min> Apply patches with number >= min only
+# -M<max> Apply patches with number <= max only
+%autopatch(vp:m:M:)\
%{lua:\
local options = rpm.expand("%{!-v:-q} %{-p:-p%{-p*}} ")\
+local low_limit = tonumber(rpm.expand("%{-m:%{-m*}}"))\
+local high_limit = tonumber(rpm.expand("%{-M:%{-M*}}"))\
for i, p in ipairs(patches) do\
- print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n"))\
+ local inum = patch_nums[i]\
+ if ((not low_limit or inum>=low_limit) and (not high_limit or inum<=high_limit)) \
+ then\
+ print(rpm.expand("%apply_patch -m %{basename:"..p.."} "..options..p.." "..i.."\\n")) \
+ end\
end}
# One macro to (optionally) do it all.
--
2.26.2

@ -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

@ -0,0 +1,32 @@
From 38c03ddb18e86c84d89af695f72442d8365eb64e Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Tue, 21 Jul 2020 10:45:20 +0200
Subject: [PATCH] Always close libelf handle (#1313)
Otherwise executables that are not proper elf files are leaking libelf
handles. This results in file being left open (mmap'ed) and fails the
build on NFS as those files can't be deleted properly there.
Resolves: rhbz#1840728
See also: https://bugzilla.redhat.com/show_bug.cgi?id=1840728
---
build/files.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build/files.c b/build/files.c
index f675306f7..62489c07c 100644
--- a/build/files.c
+++ b/build/files.c
@@ -1935,8 +1935,8 @@ static int generateBuildIDs(FileList fl, ARGV_t *files)
if (terminate)
rc = 1;
}
- elf_end (elf);
}
+ elf_end (elf);
close (fd);
}
}
--
2.26.2

@ -0,0 +1,37 @@
From c4f285cff8f830447857e52848ecf909cedb192a Mon Sep 17 00:00:00 2001
Message-Id: <c4f285cff8f830447857e52848ecf909cedb192a.1543566970.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 6 Nov 2018 12:22:55 +0200
Subject: [PATCH] Document --noverify in the man page (RhBug:1646458)
Should've been in commit 765e2c72ae8be369ada41d4747b8999519a0e327
---
doc/rpm.8 | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/doc/rpm.8 b/doc/rpm.8
index 5ab61b2ac..31c51d821 100644
--- a/doc/rpm.8
+++ b/doc/rpm.8
@@ -104,7 +104,7 @@ Scripts and triggers:
[\fB--ignoresize\fR] [\fB--ignorearch\fR] [\fB--ignoreos\fR]
[\fB--includedocs\fR] [\fB--justdb\fR]
[\fB--nodeps\fR] [\fB--nodigest\fR] [\fB--noplugins\fR]
- [\fB--nocaps\fR] [\fB--noorder\fR]
+ [\fB--nocaps\fR] [\fB--noorder\fR] [\fB--noverify\fR]
[\fB--nosignature\fR] [\fB--noscripts\fR] [\fB--notriggers\fR]
[\fB--oldpackage\fR] [\fB--percent\fR] [\fB--prefix \fINEWPATH\fB\fR]
[\fB--relocate \fIOLDPATH\fB=\fINEWPATH\fB\fR]
@@ -315,6 +315,9 @@ Don't set file capabilities.
Don't reorder the packages for an install. The list of
packages would normally be reordered to satisfy dependencies.
.TP
+\fB--noverify\fR
+Don't perform verify package files prior to installation.
+.TP
\fB--noplugins\fR
Do not load and execute plugins.
.TP
--
2.19.2

@ -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

@ -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

@ -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

@ -0,0 +1,152 @@
From 13f70e3710b2df49a923cc6450ff4a8f86e65666 Mon Sep 17 00:00:00 2001
Message-Id: <13f70e3710b2df49a923cc6450ff4a8f86e65666.1555050140.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 20 Mar 2019 12:38:00 +0200
Subject: [PATCH] Fix FA_TOUCH on files with suid/sgid bits and/or capabilities
FA_TOUCH used to set suffix to "" instead of NULL which causes fsmCommit()
to rename the file onto itself, which is a bit dumb but mostly harmless
with regular permission. On suid/sgid/capabilities we strip any extra
privileges on rename to make sure hardlinks are neutered, and because
rename occurs after other permissions etc setting, on FA_TOUCH those
extra privileges are stripped and much brokenness will follow.
A more minimal fix would be a strategically placed strcmp(), but NULL
is what the rest of the fsm expects for no suffix and differentiating
between empty and NULL suffix is too subtle for its own good as
witnessed here. So now, NULL suffix is no suffix again and the rest
of the code will do the right thing except where related to creation,
and creation is what FA_TOUCH wont do so lets just explicitly skip it
and restore the original code otherwise. The goto is ugly but reindenting
gets even uglier, shrug. Add a test-case to go with it.
This has been broken since its introduction in commit
79ca74e15e15c1d91a9a31a9ee90abc91736f390 so all current 4.14.x versions
are affected.
---
lib/fsm.c | 17 ++++++++++----
tests/data/SPECS/replacetest.spec | 2 +-
tests/rpmverify.at | 38 ++++++++++++++++++++++++++++++-
3 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 8eb2c185c..432bcbd90 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -898,12 +898,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
action = rpmfsGetAction(fs, rpmfiFX(fi));
skip = XFA_SKIPPING(action);
- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
if (action != FA_TOUCH) {
- fpath = fsmFsPath(fi, suffix);
+ suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
} else {
- fpath = fsmFsPath(fi, "");
+ suffix = NULL;
}
+ fpath = fsmFsPath(fi, suffix);
/* Remap file perms, owner, and group. */
rc = rpmfiStat(fi, 1, &sb);
@@ -926,6 +926,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!skip) {
int setmeta = 1;
+ /* When touching we don't need any of this... */
+ if (action == FA_TOUCH)
+ goto touch;
+
/* Directories replacing something need early backup */
if (!suffix) {
rc = fsmBackup(fi, action);
@@ -934,7 +938,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!suffix) {
rc = fsmVerify(fpath, fi);
} else {
- rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT;
+ rc = RPMERR_ENOENT;
}
if (S_ISREG(sb.st_mode)) {
@@ -970,11 +974,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (!IS_DEV_LOG(fpath))
rc = RPMERR_UNKNOWN_FILETYPE;
}
+
+touch:
/* Set permissions, timestamps etc for non-hardlink entries */
if (!rc && setmeta) {
rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps);
}
} else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
+ /* On FA_TOUCH no hardlinks are created thus this is skipped. */
/* we skip the hard linked file containing the content */
/* write the content to the first used instead */
char *fn = rpmfilesFN(files, firsthardlink);
@@ -987,7 +994,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
if (rc) {
if (!skip) {
/* XXX only erase if temp fn w suffix is in use */
- if (suffix && (action != FA_TOUCH)) {
+ if (suffix) {
(void) fsmRemove(fpath, sb.st_mode);
}
errno = saveerrno;
diff --git a/tests/data/SPECS/replacetest.spec b/tests/data/SPECS/replacetest.spec
index 54974567b..d5a1729d3 100644
--- a/tests/data/SPECS/replacetest.spec
+++ b/tests/data/SPECS/replacetest.spec
@@ -46,4 +46,4 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,%{user},%{grp},-)
-/opt/*
+%{?fileattr} /opt/*
diff --git a/tests/rpmverify.at b/tests/rpmverify.at
index 52ee2abfb..f7dd57531 100644
--- a/tests/rpmverify.at
+++ b/tests/rpmverify.at
@@ -575,3 +575,39 @@
],
[])
AT_CLEANUP
+
+AT_SETUP([Upgraded verification with min_writes 5 (suid files)])
+AT_KEYWORDS([upgrade verify min_writes])
+AT_CHECK([
+RPMDB_CLEAR
+RPMDB_INIT
+tf="${RPMTEST}"/opt/foo
+rm -rf "${tf}" "${tf}".rpm*
+rm -rf "${TOPDIR}"
+
+for v in "1.0" "2.0"; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver $v" \
+ --define "filetype file" \
+ --define "filedata foo" \
+ --define "fileattr %attr(2755,-,-)" \
+ /data/SPECS/replacetest.spec
+done
+
+runroot rpm -U /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm
+runroot rpm -Va --nouser --nogroup replacetest
+runroot rpm -U \
+ --define "_minimize_writes 1" \
+ /build/RPMS/noarch/replacetest-2.0-1.noarch.rpm
+runroot rpm -Va --nouser --nogroup replacetest
+chmod 777 "${tf}"
+runroot rpm -U \
+ --oldpackage \
+ --define "_minimize_writes 1" \
+ /build/RPMS/noarch/replacetest-1.0-1.noarch.rpm
+runroot rpm -Va --nouser --nogroup replacetest
+],
+[0],
+[],
+[])
+AT_CLEANUP
--
2.20.1

@ -0,0 +1,41 @@
From 1fd84fa0cfa6e493d1c15edfb7d9f0bb05e4f920 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Thu, 2 May 2019 17:17:56 +0200
Subject: [PATCH] Fix brp-strip-static-archive parallelism
The change made in fc2c986 can break for large values of %_smp_build_ncpus as
this many processes are able to overflow the following pipe.
Thanks to Denys Vlasenko for testing this.
This change solves this problem by running a whole processing pileline for each
parallel (file) process. This has also the benefit of running at least some
stip commands in parallel.
The -n param fro xargs was increased to 32 to further reduce the over head of
spawing the helpers as they are now needed for each run of the file command.
---
scripts/brp-strip-static-archive | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive
index 4dc449061..13d9a098b 100755
--- a/scripts/brp-strip-static-archive
+++ b/scripts/brp-strip-static-archive
@@ -13,10 +13,6 @@ Darwin*) exit 0 ;;
esac
# Strip static libraries.
-for f in `find "$RPM_BUILD_ROOT" -type f | \
- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
- xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \
- grep 'current ar archive' | \
- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do
- $STRIP -g "$f"
-done
+find "$RPM_BUILD_ROOT" -type f | \
+ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
+ xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0
--
2.21.0

@ -0,0 +1,102 @@
From 60066aba510b3ff4a7db092021aae71948e3f8be Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 4 Jun 2020 11:18:01 +0300
Subject: [PATCH] Fix python ts.addErase() not raising exception on not-found
packages
The code would only raise an exception if TransactionSetCore.addErase()
returned an error, but the catch is that with many kinds of argument
types we'd silently skip the whole addition because no headers were found.
This looks to be a regression introduced some eleven years ago in
commit 9b20c706a4f93266450fae2f94007343b2e8fd9e.
As a special case, a match iterator argument will not raise an exception
if it doesn't actually match anything.
Fixes: #1214
---
python/rpm/transaction.py | 26 +++++++++++++++-----------
tests/rpmpython.at | 22 ++++++++++++++++++++++
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/python/rpm/transaction.py b/python/rpm/transaction.py
index 7c4a551d3..3c9ddb207 100644
--- a/python/rpm/transaction.py
+++ b/python/rpm/transaction.py
@@ -91,14 +91,22 @@ class TransactionSet(TransactionSetCore):
def addErase(self, item):
hdrs = []
- if isinstance(item, rpm.hdr):
- hdrs = [item]
- elif isinstance(item, rpm.mi):
+ # match iterators are passed on as-is
+ if isinstance(item, rpm.mi):
hdrs = item
- elif isinstance(item, int):
- hdrs = self.dbMatch(rpm.RPMDBI_PACKAGES, item)
- elif isinstance(item, _string_types):
- hdrs = self.dbMatch(rpm.RPMDBI_LABEL, item)
+ elif isinstance(item, rpm.hdr):
+ hdrs.append(item)
+ elif isinstance(item, (int, _string_types)):
+ if isinstance(item, int):
+ dbi = rpm.RPMDBI_PACKAGES
+ else:
+ dbi = rpm.RPMDBI_LABEL
+
+ for h in self.dbMatch(dbi, item):
+ hdrs.append(h)
+
+ if not hdrs:
+ raise rpm.error("package not installed")
else:
raise TypeError("invalid type %s" % type(item))
@@ -106,10 +114,6 @@ class TransactionSet(TransactionSetCore):
if not TransactionSetCore.addErase(self, h):
raise rpm.error("package not installed")
- # garbage collection should take care but just in case...
- if isinstance(hdrs, rpm.mi):
- del hdrs
-
def run(self, callback, data):
rc = TransactionSetCore.run(self, callback, data, self._probFilter)
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
index 3a7c251f1..de39c8417 100644
--- a/tests/rpmpython.at
+++ b/tests/rpmpython.at
@@ -201,6 +201,28 @@ for e in ts:
[foo-1.0-1.noarch]
)
+RPMPY_TEST([add erasure to transaction],[
+ts = rpm.ts()
+for i in ['foo', 1234]:
+ myprint('addErase %s' % i)
+ try:
+ ts.addErase(i)
+ except rpm.error as err:
+ myprint(err)
+myprint('addErase mi')
+mi = ts.dbMatch('name', 'foo')
+try:
+ ts.addErase(mi)
+except rpm.error as err:
+ myprint(err)
+],
+[addErase foo
+package not installed
+addErase 1234
+package not installed
+addErase mi]
+)
+
RPMPY_TEST([add bogus package to transaction 1],[
ts = rpm.ts()
h = rpm.hdr()
--
2.26.2

@ -0,0 +1,50 @@
From ed6c5573c09611ff9522ed290ef9d1ba717d8019 Mon Sep 17 00:00:00 2001
Message-Id: <ed6c5573c09611ff9522ed290ef9d1ba717d8019.1574331915.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 21 Nov 2019 12:22:45 +0200
Subject: [PATCH] Fix resource leaks on zstd open error paths
If zstd stream initialization fails, the opened fd and the stream
itself are leaked. Handle error exit in a central label.
---
rpmio/rpmio.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c
index 243942411..10ba20cd6 100644
--- a/rpmio/rpmio.c
+++ b/rpmio/rpmio.c
@@ -1128,13 +1128,13 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode)
if ((flags & O_ACCMODE) == O_RDONLY) { /* decompressing */
if ((_stream = (void *) ZSTD_createDStream()) == NULL
|| ZSTD_isError(ZSTD_initDStream(_stream))) {
- return NULL;
+ goto err;
}
nb = ZSTD_DStreamInSize();
} else { /* compressing */
if ((_stream = (void *) ZSTD_createCStream()) == NULL
|| ZSTD_isError(ZSTD_initCStream(_stream, level))) {
- return NULL;
+ goto err;
}
nb = ZSTD_CStreamOutSize();
}
@@ -1149,6 +1149,14 @@ static rpmzstd rpmzstdNew(int fdno, const char *fmode)
zstd->b = xmalloc(nb);
return zstd;
+
+err:
+ fclose(fp);
+ if ((flags & O_ACCMODE) == O_RDONLY)
+ ZSTD_freeDStream(_stream);
+ else
+ ZSTD_freeCStream(_stream);
+ return NULL;
}
static FD_t zstdFdopen(FD_t fd, int fdno, const char * fmode)
--
2.23.0

@ -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

@ -0,0 +1,53 @@
From 6b6c4d881dc6fc99f949dac4aaf9a513542f9956 Mon Sep 17 00:00:00 2001
Message-Id: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 3 Oct 2018 15:22:55 +0300
Subject: [PATCH 1/5] Honor PYTHON from configure when running tests
Pass PYTHON from configure down through all the nutty layers of make
to allow running test-suite with Python 3. In theory that is.
(cherry picked from commit dcd5ab67c40b543f22b07df8c1028c34b94a7929)
---
tests/Makefile.am | 1 +
tests/atlocal.in | 3 ++-
tests/local.at | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index eaf817cc2..21ca216a8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -117,6 +117,7 @@ atlocal: atlocal.in Makefile
-e "s,[@]usrlibdir[@],$(libdir)," \
-e "s,[@]execprefix[@],$(exec_prefix)," \
-e "s,[@]RPMCONFIGDIR[@],$(rpmconfigdir)," \
+ -e "s,[@]PYTHON[@],$(PYTHON)," \
< $(srcdir)/atlocal.in > atlocal
DISTCLEANFILES = atlocal
EXTRA_DIST += atlocal.in
diff --git a/tests/atlocal.in b/tests/atlocal.in
index d7d837f45..3b1474b56 100644
--- rpm-4.14.3/tests/atlocal.in.orig 2020-04-28 14:19:26.866602968 +0200
+++ rpm-4.14.3/tests/atlocal.in 2020-04-28 14:21:07.977910054 +0200
@@ -3,7 +3,8 @@
PATH="${abs_builddir}/testing@rpmbindir@:${abs_builddir}/testing@usrbindir@:$PATH"
export PATH
-PYLIBDIR=`python2 -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))"`
+PYTHON=@PYTHON@
+PYLIBDIR=$(${PYTHON} -c "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib(1,0,'@execprefix@'))")
PYTHONPATH="${abs_builddir}/testing${PYLIBDIR}"
export PYTHONPATH
--- rpm-4.14.3/tests/local.at.orig 2020-04-28 14:28:33.106664317 +0200
+++ rpm-4.14.3/tests/local.at 2020-04-28 14:29:02.064038653 +0200
@@ -18,7 +18,7 @@
sys.stdout.write('%s\n' % msg)
$1
EOF
-python2 test.py
+${PYTHON} test.py test.py
]])
m4_define([RPMPY_CHECK],[

@ -0,0 +1,656 @@
From 84920f898315d09a57a3f1067433eaeb7de5e830 Mon Sep 17 00:00:00 2001
Message-Id: <84920f898315d09a57a3f1067433eaeb7de5e830.1554884444.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 22 Feb 2019 19:44:16 +0200
Subject: [PATCH] In Python 3, return all our string data as surrogate-escaped
utf-8 strings
In the almost ten years of rpm sort of supporting Python 3 bindings, quite
obviously nobody has actually tried to use them. There's a major mismatch
between what the header API outputs (bytes) and what all the other APIs
accept (strings), resulting in hysterical TypeErrors all over the place,
including but not limited to labelCompare() (RhBug:1631292). Also a huge
number of other places have been returning strings and silently assuming
utf-8 through use of Py_BuildValue("s", ...), which will just irrevocably
fail when non-utf8 data is encountered.
The politically Python 3-correct solution would be declaring all our data
as bytes with unspecified encoding - that's exactly what it historically is.
However doing so would by definition break every single rpm script people
have developed on Python 2. And when 99% of the rpm content in the world
actually is utf-8 encoded even if it doesn't say so (and in recent times
packages even advertise themselves as utf-8 encoded), the bytes-only route
seems a wee bit too draconian, even to this grumpy old fella.
Instead, route all our string returns through a single helper macro
which on Python 2 just does what we always did, but in Python 3 converts
the data to surrogate-escaped utf-8 strings. This makes stuff "just work"
out of the box pretty much everywhere even with Python 3 (including
our own test-suite!), while still allowing to handle the non-utf8 case.
Handling the non-utf8 case is a bit more uglier but still possible,
which is exactly how you want corner-cases to be. There might be some
uses for retrieving raw byte data from the header, but worrying about
such an API is a case for some other rainy day, for now we mostly only
care that stuff works again.
Also add test-cases for mixed data source labelCompare() and
non-utf8 insert to + retrieve from header.
---
python/header-py.c | 2 +-
python/rpmds-py.c | 8 ++++----
python/rpmfd-py.c | 6 +++---
python/rpmfi-py.c | 24 ++++++++++++------------
python/rpmfiles-py.c | 26 +++++++++++++-------------
python/rpmkeyring-py.c | 2 +-
python/rpmmacro-py.c | 2 +-
python/rpmmodule.c | 2 +-
python/rpmps-py.c | 8 ++++----
python/rpmstrpool-py.c | 2 +-
python/rpmsystem-py.h | 7 +++++++
python/rpmtd-py.c | 2 +-
python/rpmte-py.c | 16 ++++++++--------
python/rpmts-py.c | 11 ++++++-----
python/spec-py.c | 8 ++++----
tests/local.at | 1 +
tests/rpmpython.at | 34 ++++++++++++++++++++++++++++++++++
17 files changed, 102 insertions(+), 59 deletions(-)
diff --git a/python/header-py.c b/python/header-py.c
index c9d54e869..93c241cb7 100644
--- a/python/header-py.c
+++ b/python/header-py.c
@@ -231,7 +231,7 @@ static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds)
return NULL;
}
- result = Py_BuildValue("s", r);
+ result = utf8FromString(r);
free(r);
return result;
diff --git a/python/rpmds-py.c b/python/rpmds-py.c
index 39b26628e..ecc9af9d5 100644
--- a/python/rpmds-py.c
+++ b/python/rpmds-py.c
@@ -31,19 +31,19 @@ rpmds_Ix(rpmdsObject * s)
static PyObject *
rpmds_DNEVR(rpmdsObject * s)
{
- return Py_BuildValue("s", rpmdsDNEVR(s->ds));
+ return utf8FromString(rpmdsDNEVR(s->ds));
}
static PyObject *
rpmds_N(rpmdsObject * s)
{
- return Py_BuildValue("s", rpmdsN(s->ds));
+ return utf8FromString(rpmdsN(s->ds));
}
static PyObject *
rpmds_EVR(rpmdsObject * s)
{
- return Py_BuildValue("s", rpmdsEVR(s->ds));
+ return utf8FromString(rpmdsEVR(s->ds));
}
static PyObject *
@@ -261,7 +261,7 @@ rpmds_subscript(rpmdsObject * s, PyObject * key)
ix = (int) PyInt_AsLong(key);
rpmdsSetIx(s->ds, ix);
- return Py_BuildValue("s", rpmdsDNEVR(s->ds));
+ return utf8FromString(rpmdsDNEVR(s->ds));
}
static PyMappingMethods rpmds_as_mapping = {
diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c
index 85fb0cd24..4b05cce5f 100644
--- a/python/rpmfd-py.c
+++ b/python/rpmfd-py.c
@@ -327,17 +327,17 @@ static PyObject *rpmfd_get_closed(rpmfdObject *s)
static PyObject *rpmfd_get_name(rpmfdObject *s)
{
/* XXX: rpm returns non-paths with [mumble], python files use <mumble> */
- return Py_BuildValue("s", Fdescr(s->fd));
+ return utf8FromString(Fdescr(s->fd));
}
static PyObject *rpmfd_get_mode(rpmfdObject *s)
{
- return Py_BuildValue("s", s->mode);
+ return utf8FromString(s->mode);
}
static PyObject *rpmfd_get_flags(rpmfdObject *s)
{
- return Py_BuildValue("s", s->flags);
+ return utf8FromString(s->flags);
}
static PyGetSetDef rpmfd_getseters[] = {
diff --git a/python/rpmfi-py.c b/python/rpmfi-py.c
index 8d2f926d0..db405c231 100644
--- a/python/rpmfi-py.c
+++ b/python/rpmfi-py.c
@@ -41,19 +41,19 @@ rpmfi_DX(rpmfiObject * s, PyObject * unused)
static PyObject *
rpmfi_BN(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiBN(s->fi));
+ return utf8FromString(rpmfiBN(s->fi));
}
static PyObject *
rpmfi_DN(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiDN(s->fi));
+ return utf8FromString(rpmfiDN(s->fi));
}
static PyObject *
rpmfi_FN(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiFN(s->fi));
+ return utf8FromString(rpmfiFN(s->fi));
}
static PyObject *
@@ -98,7 +98,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused)
{
char *digest = rpmfiFDigestHex(s->fi, NULL);
if (digest) {
- PyObject *dig = Py_BuildValue("s", digest);
+ PyObject *dig = utf8FromString(digest);
free(digest);
return dig;
} else {
@@ -109,7 +109,7 @@ rpmfi_Digest(rpmfiObject * s, PyObject * unused)
static PyObject *
rpmfi_FLink(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiFLink(s->fi));
+ return utf8FromString(rpmfiFLink(s->fi));
}
static PyObject *
@@ -133,13 +133,13 @@ rpmfi_FMtime(rpmfiObject * s, PyObject * unused)
static PyObject *
rpmfi_FUser(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiFUser(s->fi));
+ return utf8FromString(rpmfiFUser(s->fi));
}
static PyObject *
rpmfi_FGroup(rpmfiObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmfiFGroup(s->fi));
+ return utf8FromString(rpmfiFGroup(s->fi));
}
static PyObject *
@@ -155,7 +155,7 @@ rpmfi_FClass(rpmfiObject * s, PyObject * unused)
if ((FClass = rpmfiFClass(s->fi)) == NULL)
FClass = "";
- return Py_BuildValue("s", FClass);
+ return utf8FromString(FClass);
}
static PyObject *
@@ -208,7 +208,7 @@ rpmfi_iternext(rpmfiObject * s)
Py_INCREF(Py_None);
PyTuple_SET_ITEM(result, 0, Py_None);
} else
- PyTuple_SET_ITEM(result, 0, Py_BuildValue("s", FN));
+ PyTuple_SET_ITEM(result, 0, utf8FromString(FN));
PyTuple_SET_ITEM(result, 1, PyLong_FromLongLong(FSize));
PyTuple_SET_ITEM(result, 2, PyInt_FromLong(FMode));
PyTuple_SET_ITEM(result, 3, PyInt_FromLong(FMtime));
@@ -222,12 +222,12 @@ rpmfi_iternext(rpmfiObject * s)
Py_INCREF(Py_None);
PyTuple_SET_ITEM(result, 10, Py_None);
} else
- PyTuple_SET_ITEM(result, 10, Py_BuildValue("s", FUser));
+ PyTuple_SET_ITEM(result, 10, utf8FromString(FUser));
if (FGroup == NULL) {
Py_INCREF(Py_None);
PyTuple_SET_ITEM(result, 11, Py_None);
} else
- PyTuple_SET_ITEM(result, 11, Py_BuildValue("s", FGroup));
+ PyTuple_SET_ITEM(result, 11, utf8FromString(FGroup));
PyTuple_SET_ITEM(result, 12, rpmfi_Digest(s, NULL));
} else
@@ -313,7 +313,7 @@ rpmfi_subscript(rpmfiObject * s, PyObject * key)
ix = (int) PyInt_AsLong(key);
rpmfiSetFX(s->fi, ix);
- return Py_BuildValue("s", rpmfiFN(s->fi));
+ return utf8FromString(rpmfiFN(s->fi));
}
static PyMappingMethods rpmfi_as_mapping = {
diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c
index bc07dbeaf..557246cae 100644
--- a/python/rpmfiles-py.c
+++ b/python/rpmfiles-py.c
@@ -41,37 +41,37 @@ static PyObject *rpmfile_dx(rpmfileObject *s)
static PyObject *rpmfile_name(rpmfileObject *s)
{
char * fn = rpmfilesFN(s->files, s->ix);
- PyObject *o = Py_BuildValue("s", fn);
+ PyObject *o = utf8FromString(fn);
free(fn);
return o;
}
static PyObject *rpmfile_basename(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesBN(s->files, s->ix));
+ return utf8FromString(rpmfilesBN(s->files, s->ix));
}
static PyObject *rpmfile_dirname(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix)));
+ return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix)));
}
static PyObject *rpmfile_orig_name(rpmfileObject *s)
{
char * fn = rpmfilesOFN(s->files, s->ix);
- PyObject *o = Py_BuildValue("s", fn);
+ PyObject *o = utf8FromString(fn);
free(fn);
return o;
}
static PyObject *rpmfile_orig_basename(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesOBN(s->files, s->ix));
+ return utf8FromString(rpmfilesOBN(s->files, s->ix));
}
static PyObject *rpmfile_orig_dirname(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix)));
+ return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix)));
}
static PyObject *rpmfile_mode(rpmfileObject *s)
{
@@ -105,17 +105,17 @@ static PyObject *rpmfile_nlink(rpmfileObject *s)
static PyObject *rpmfile_linkto(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFLink(s->files, s->ix));
+ return utf8FromString(rpmfilesFLink(s->files, s->ix));
}
static PyObject *rpmfile_user(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFUser(s->files, s->ix));
+ return utf8FromString(rpmfilesFUser(s->files, s->ix));
}
static PyObject *rpmfile_group(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFGroup(s->files, s->ix));
+ return utf8FromString(rpmfilesFGroup(s->files, s->ix));
}
static PyObject *rpmfile_fflags(rpmfileObject *s)
@@ -145,7 +145,7 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
NULL, &diglen);
if (digest) {
char * hex = pgpHexStr(digest, diglen);
- PyObject *o = Py_BuildValue("s", hex);
+ PyObject *o = utf8FromString(hex);
free(hex);
return o;
}
@@ -154,17 +154,17 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
static PyObject *rpmfile_class(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFClass(s->files, s->ix));
+ return utf8FromString(rpmfilesFClass(s->files, s->ix));
}
static PyObject *rpmfile_caps(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFCaps(s->files, s->ix));
+ return utf8FromString(rpmfilesFCaps(s->files, s->ix));
}
static PyObject *rpmfile_langs(rpmfileObject *s)
{
- return Py_BuildValue("s", rpmfilesFLangs(s->files, s->ix));
+ return utf8FromString(rpmfilesFLangs(s->files, s->ix));
}
static PyObject *rpmfile_links(rpmfileObject *s)
diff --git a/python/rpmkeyring-py.c b/python/rpmkeyring-py.c
index d5f131e42..8968e0513 100644
--- a/python/rpmkeyring-py.c
+++ b/python/rpmkeyring-py.c
@@ -38,7 +38,7 @@ static PyObject *rpmPubkey_new(PyTypeObject *subtype,
static PyObject * rpmPubkey_Base64(rpmPubkeyObject *s)
{
char *b64 = rpmPubkeyBase64(s->pubkey);
- PyObject *res = Py_BuildValue("s", b64);
+ PyObject *res = utf8FromString(b64);
free(b64);
return res;
}
diff --git a/python/rpmmacro-py.c b/python/rpmmacro-py.c
index 3cb1a51f5..d8a365547 100644
--- a/python/rpmmacro-py.c
+++ b/python/rpmmacro-py.c
@@ -52,7 +52,7 @@ rpmmacro_ExpandMacro(PyObject * self, PyObject * args, PyObject * kwds)
if (rpmExpandMacros(NULL, macro, &str, 0) < 0)
PyErr_SetString(pyrpmError, "error expanding macro");
else
- res = Py_BuildValue("s", str);
+ res = utf8FromString(str);
free(str);
}
return res;
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
index 3faad23c7..05032edc7 100644
--- a/python/rpmmodule.c
+++ b/python/rpmmodule.c
@@ -237,7 +237,7 @@ static void addRpmTags(PyObject *module)
PyModule_AddIntConstant(module, tagname, tagval);
pyval = PyInt_FromLong(tagval);
- pyname = Py_BuildValue("s", shortname);
+ pyname = utf8FromString(shortname);
PyDict_SetItem(dict, pyval, pyname);
Py_DECREF(pyval);
Py_DECREF(pyname);
diff --git a/python/rpmps-py.c b/python/rpmps-py.c
index bdc899a60..902b2ae63 100644
--- a/python/rpmps-py.c
+++ b/python/rpmps-py.c
@@ -18,12 +18,12 @@ static PyObject *rpmprob_get_type(rpmProblemObject *s, void *closure)
static PyObject *rpmprob_get_pkgnevr(rpmProblemObject *s, void *closure)
{
- return Py_BuildValue("s", rpmProblemGetPkgNEVR(s->prob));
+ return utf8FromString(rpmProblemGetPkgNEVR(s->prob));
}
static PyObject *rpmprob_get_altnevr(rpmProblemObject *s, void *closure)
{
- return Py_BuildValue("s", rpmProblemGetAltNEVR(s->prob));
+ return utf8FromString(rpmProblemGetAltNEVR(s->prob));
}
static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure)
@@ -38,7 +38,7 @@ static PyObject *rpmprob_get_key(rpmProblemObject *s, void *closure)
static PyObject *rpmprob_get_str(rpmProblemObject *s, void *closure)
{
- return Py_BuildValue("s", rpmProblemGetStr(s->prob));
+ return utf8FromString(rpmProblemGetStr(s->prob));
}
static PyObject *rpmprob_get_num(rpmProblemObject *s, void *closure)
@@ -59,7 +59,7 @@ static PyGetSetDef rpmprob_getseters[] = {
static PyObject *rpmprob_str(rpmProblemObject *s)
{
char *str = rpmProblemString(s->prob);
- PyObject *res = Py_BuildValue("s", str);
+ PyObject *res = utf8FromString(str);
free(str);
return res;
}
diff --git a/python/rpmstrpool-py.c b/python/rpmstrpool-py.c
index 356bd1de5..a56e2b540 100644
--- a/python/rpmstrpool-py.c
+++ b/python/rpmstrpool-py.c
@@ -44,7 +44,7 @@ static PyObject *strpool_id2str(rpmstrPoolObject *s, PyObject *item)
const char *str = rpmstrPoolStr(s->pool, id);
if (str)
- ret = PyBytes_FromString(str);
+ ret = utf8FromString(str);
else
PyErr_SetObject(PyExc_KeyError, item);
}
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
index 955d60cd3..87c750571 100644
--- a/python/rpmsystem-py.h
+++ b/python/rpmsystem-py.h
@@ -19,4 +19,11 @@
#define PyInt_AsSsize_t PyLong_AsSsize_t
#endif
+/* In Python 3, we return all strings as surrogate-escaped utf-8 */
+#if PY_MAJOR_VERSION >= 3
+#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape")
+#else
+#define utf8FromString(_s) PyBytes_FromString(_s)
+#endif
+
#endif /* H_SYSTEM_PYTHON */
diff --git a/python/rpmtd-py.c b/python/rpmtd-py.c
index 247c7502a..23ca10517 100644
--- a/python/rpmtd-py.c
+++ b/python/rpmtd-py.c
@@ -17,7 +17,7 @@ PyObject * rpmtd_ItemAsPyobj(rpmtd td, rpmTagClass tclass)
switch (tclass) {
case RPM_STRING_CLASS:
- res = PyBytes_FromString(rpmtdGetString(td));
+ res = utf8FromString(rpmtdGetString(td));
break;
case RPM_NUMERIC_CLASS:
res = PyLong_FromLongLong(rpmtdGetNumber(td));
diff --git a/python/rpmte-py.c b/python/rpmte-py.c
index 99ff2f496..2b3745754 100644
--- a/python/rpmte-py.c
+++ b/python/rpmte-py.c
@@ -54,49 +54,49 @@ rpmte_TEType(rpmteObject * s, PyObject * unused)
static PyObject *
rpmte_N(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteN(s->te));
+ return utf8FromString(rpmteN(s->te));
}
static PyObject *
rpmte_E(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteE(s->te));
+ return utf8FromString(rpmteE(s->te));
}
static PyObject *
rpmte_V(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteV(s->te));
+ return utf8FromString(rpmteV(s->te));
}
static PyObject *
rpmte_R(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteR(s->te));
+ return utf8FromString(rpmteR(s->te));
}
static PyObject *
rpmte_A(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteA(s->te));
+ return utf8FromString(rpmteA(s->te));
}
static PyObject *
rpmte_O(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteO(s->te));
+ return utf8FromString(rpmteO(s->te));
}
static PyObject *
rpmte_NEVR(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteNEVR(s->te));
+ return utf8FromString(rpmteNEVR(s->te));
}
static PyObject *
rpmte_NEVRA(rpmteObject * s, PyObject * unused)
{
- return Py_BuildValue("s", rpmteNEVRA(s->te));
+ return utf8FromString(rpmteNEVRA(s->te));
}
static PyObject *
diff --git a/python/rpmts-py.c b/python/rpmts-py.c
index 1ddfc9a1e..96e3bb28e 100644
--- a/python/rpmts-py.c
+++ b/python/rpmts-py.c
@@ -230,8 +230,9 @@ rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
PyEval_RestoreThread(cbInfo->_save);
- args = Py_BuildValue("(Oissi)", cbInfo->tso,
- rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
+ args = Py_BuildValue("(OiNNi)", cbInfo->tso,
+ rpmdsTagN(ds), utf8FromString(rpmdsN(ds)),
+ utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds));
result = PyEval_CallObject(cbInfo->cb, args);
Py_DECREF(args);
@@ -409,7 +410,7 @@ rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
rpmrc = headerCheck(s->ts, uh, uc, &msg);
Py_END_ALLOW_THREADS;
- return Py_BuildValue("(is)", rpmrc, msg);
+ return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg));
}
static PyObject *
@@ -500,7 +501,7 @@ rpmtsCallback(const void * hd, const rpmCallbackType what,
/* Synthesize a python object for callback (if necessary). */
if (pkgObj == NULL) {
if (h) {
- pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
+ pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME));
} else {
pkgObj = Py_None;
Py_INCREF(pkgObj);
@@ -845,7 +846,7 @@ static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
{
- return Py_BuildValue("s", rpmtsRootDir(s->ts));
+ return utf8FromString(rpmtsRootDir(s->ts));
}
static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
diff --git a/python/spec-py.c b/python/spec-py.c
index 4efdbf4bf..70b796531 100644
--- a/python/spec-py.c
+++ b/python/spec-py.c
@@ -57,7 +57,7 @@ static PyObject *pkgGetSection(rpmSpecPkg pkg, int section)
{
char *sect = rpmSpecPkgGetSection(pkg, section);
if (sect != NULL) {
- PyObject *ps = PyBytes_FromString(sect);
+ PyObject *ps = utf8FromString(sect);
free(sect);
if (ps != NULL)
return ps;
@@ -158,7 +158,7 @@ static PyObject * getSection(rpmSpec spec, int section)
{
const char *sect = rpmSpecGetSection(spec, section);
if (sect) {
- return Py_BuildValue("s", sect);
+ return utf8FromString(sect);
}
Py_RETURN_NONE;
}
@@ -208,8 +208,8 @@ static PyObject * spec_get_sources(specObject *s, void *closure)
rpmSpecSrcIter iter = rpmSpecSrcIterInit(s->spec);
while ((source = rpmSpecSrcIterNext(iter)) != NULL) {
- PyObject *srcUrl = Py_BuildValue("(sii)",
- rpmSpecSrcFilename(source, 1),
+ PyObject *srcUrl = Py_BuildValue("(Nii)",
+ utf8FromString(rpmSpecSrcFilename(source, 1)),
rpmSpecSrcNum(source),
rpmSpecSrcFlags(source));
if (!srcUrl) {
diff --git a/tests/local.at b/tests/local.at
index 02ead66c9..42eef1c75 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -10,6 +10,7 @@ rm -rf "${abs_builddir}"/testing`rpm --eval '%_dbpath'`/*
m4_define([RPMPY_RUN],[[
cat << EOF > test.py
+# coding=utf-8
import rpm, sys
dbpath=rpm.expandMacro('%_dbpath')
rpm.addMacro('_dbpath', '${abs_builddir}/testing%s' % dbpath)
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
index ff77f868c..58f3e84a6 100644
--- a/tests/rpmpython.at
+++ b/tests/rpmpython.at
@@ -106,6 +106,25 @@ None
'rpm.hdr' object has no attribute '__foo__']
)
+RPMPY_TEST([non-utf8 data in header],[
+str = u'älämölö'
+enc = 'iso-8859-1'
+b = str.encode(enc)
+h = rpm.hdr()
+h['group'] = b
+d = h['group']
+try:
+ # python 3
+ t = bytes(d, 'utf-8', 'surrogateescape')
+except TypeError:
+ # python 2
+ t = bytes(d)
+res = t.decode(enc)
+myprint(str == res)
+],
+[True]
+)
+
RPMPY_TEST([invalid header data],[
h1 = rpm.hdr()
h1['basenames'] = ['bing', 'bang', 'bong']
@@ -125,6 +144,21 @@ for h in [h1, h2]:
/opt/bing,/opt/bang,/flopt/bong]
)
+RPMPY_TEST([labelCompare],[
+v = '1.0'
+r = '1'
+e = 3
+h = rpm.hdr()
+h['name'] = 'testpkg'
+h['version'] = v
+h['release'] = r
+h['epoch'] = e
+myprint(rpm.labelCompare((str(h['epoch']), h['version'], h['release']),
+ (str(e), v, r)))
+],
+[0]
+)
+
RPMPY_TEST([vfyflags API],[
ts = rpm.ts()
dlv = ts.getVfyFlags()
--
2.20.1

@ -0,0 +1,63 @@
From 9ad4b813483f8cf6c641f56387248b33b6dfc570 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 20 Feb 2019 15:28:30 +0200
Subject: [PATCH] Introduce patch_nums and source_nums Lua variables in spec
context
The pre-existing patches and sources variables only contains patch and
source filenames, but for some purposes we need access to the associated
patch/source number too. We could use the number as the table key, but
that would make the table unsorted. That we could handle in our own
macros, but would break compatibility for anybody doing custom stuff
with these. So it seems best to just add parallel arrays sharing the
same array indexes so that both values are as easily accessible,
depending on the need.
Inspired by Pascal "Pixel" Rigaux's similar patch in Mageia, which differs
in that the number-arrays are indexed by the filename and is unordered.
Compared to patches/sources this seemed against principle of least
surprise, and is slightly more cumbersome int the case we want the number
directly, such as in PR #626. The variable names differ so there
is no incompatibility to that downstream patch introduced.
---
build/parsePreamble.c | 9 +++++++++
build/spec.c | 3 ++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/build/parsePreamble.c b/build/parsePreamble.c
index 812c41f9f..9520bac4b 100644
--- a/build/parsePreamble.c
+++ b/build/parsePreamble.c
@@ -322,6 +322,15 @@ static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag
rpmluaSetVar(lua, var);
rpmluavFree(var);
rpmluaPop(lua);
+
+ what = (flag & RPMBUILD_ISPATCH) ? "patch_nums" : "source_nums";
+ rpmluaPushTable(lua, what);
+ var = rpmluavNew();
+ rpmluavSetListMode(var, 1);
+ rpmluavSetValueNum(var, p->num);
+ rpmluaSetVar(lua, var);
+ rpmluavFree(var);
+ rpmluaPop(lua);
}
#endif
free(body);
diff --git a/build/spec.c b/build/spec.c
index 80eaca611..55095c6ce 100644
--- a/build/spec.c
+++ b/build/spec.c
@@ -305,7 +305,8 @@ rpmSpec newSpec(void)
#ifdef WITH_LUA
/* make sure patches and sources tables always exist */
rpmlua lua = NULL; /* global state */
- const char * luavars[] = { "patches", "sources", NULL, };
+ const char * luavars[] = { "patches", "sources",
+ "patch_nums", "source_nums", NULL, };
for (const char **vp = luavars; vp && *vp; vp++) {
rpmluaDelVar(lua, *vp);
rpmluaPushTable(lua, *vp);
--
2.26.2

@ -0,0 +1,41 @@
From e811c7ec0b4d2685b63b61803e3952466b1a4ac6 Mon Sep 17 00:00:00 2001
Message-Id: <e811c7ec0b4d2685b63b61803e3952466b1a4ac6.1574335619.git.pmatilai@redhat.com>
From: marxin <mliska@suse.cz>
Date: Wed, 28 Nov 2018 10:52:01 +0100
Subject: [PATCH] Isolate %_smp_build_ncpus and use it for %_smp_mflags.
Refactor _smp_build_ncpus and use it in %_smp_mflags. Note that now
having a single CPU, %_smp_mflags is expanded to '-j1'.
XXX: hand-edited to remove double quotes as per upstream commit
9b6fdc65ef0507fff04a69c88e085a7a26711839 which isn't applicable
directly due to other changes
---
platform.in | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/platform.in b/platform.in
index 3eb67b55b..2dd951f87 100644
--- a/platform.in
+++ b/platform.in
@@ -50,11 +50,14 @@
# Maximum number of CPU's to use when building, 0 for unlimited.
#%_smp_ncpus_max 0
-%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
+
+%_smp_build_ncpus %([ -z "$RPM_BUILD_NCPUS" ] \\\
&& RPM_BUILD_NCPUS="`/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\
ncpus_max=%{?_smp_ncpus_max}; \\\
if [ -n "$ncpus_max" ] && [ "$ncpus_max" -gt 0 ] && [ "$RPM_BUILD_NCPUS" -gt "$ncpus_max" ]; then RPM_BUILD_NCPUS="$ncpus_max"; fi; \\\
- if [ "$RPM_BUILD_NCPUS" -gt 1 ]; then echo "-j$RPM_BUILD_NCPUS"; fi)
+ echo "$RPM_BUILD_NCPUS";)
+
+%_smp_mflags -j%{_smp_build_ncpus}
#==============================================================================
# ---- Build policy macros.
--
2.23.0

@ -0,0 +1,31 @@
From f23af97c4135013d3134a17c881014fb6e9589c8 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Tue, 30 Apr 2019 17:12:35 +0200
Subject: [PATCH] Make check-buildroot check the build files in parallel
Thanks to Denys Vlasenko for pointing this out in rhbz#1704353
---
scripts/check-buildroot | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/check-buildroot b/scripts/check-buildroot
index 0cfb34f39..f91dc767b 100755
--- a/scripts/check-buildroot
+++ b/scripts/check-buildroot
@@ -24,11 +24,12 @@ fi
tmp=$(mktemp ${TMPDIR:-/tmp}/cbr.XXXXXX)
trap "rm -f $tmp" EXIT
+NCPUS=${RPM_BUILD_NCPUS:-1}
find "$RPM_BUILD_ROOT" \! \( \
-name '*.pyo' -o -name '*.pyc' -o -name '*.elc' -o -name '.packlist' \
\) -type f -print0 | \
- LANG=C xargs -0r grep -F "$RPM_BUILD_ROOT" >$tmp
+ LANG=C xargs -0r -P$NCPUS -n16 grep -F "$RPM_BUILD_ROOT" >>$tmp
test -s "$tmp" && {
cat "$tmp"
--
2.21.0

@ -0,0 +1,28 @@
From 57b4f21634429ccd29d47cf93ec0841f70b68404 Mon Sep 17 00:00:00 2001
Message-Id: <57b4f21634429ccd29d47cf93ec0841f70b68404.1545311826.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 18 Sep 2018 11:02:36 +0300
Subject: [PATCH] Mark elements with associated problems as failed
An element with a problem can not possibly succeed so mark these failures
early. Doesn't make much of a difference as problems will prevent the
transaction from starting in the first place but it makes sense anyway.
---
lib/rpmte.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/rpmte.c b/lib/rpmte.c
index 4bdeeaf68..c5d614f67 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -703,6 +703,7 @@ static void appendProblem(rpmte te, rpmProblemType type,
if (te->probs == NULL)
te->probs = rpmpsCreate();
rpmpsAppendProblem(te->probs, p);
+ rpmteMarkFailed(te);
}
rpmProblemFree(p);
}
--
2.19.2

@ -0,0 +1,76 @@
From 362c4401979f896de1e69a3e18d33954953912cc Mon Sep 17 00:00:00 2001
Message-Id: <362c4401979f896de1e69a3e18d33954953912cc.1554983588.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 11 Dec 2018 13:21:47 +0200
Subject: [PATCH] Only read through payload on verify if actually needed
If none of our verify items ranges over the payload, then why bother?
To do this, add an internal rpmvs API to get it's range, and use
that to decide whether trip over the payload is needed or not.
In addition, the payload digest tag needs to be grabbed outside of the
condition to avoid depending on other values. The details including
RPMVSF_NEEDPAYLOAD will be handled internally to rpmvs which makes it
actually nicer code-wise too.
---
lib/rpmchecksig.c | 8 ++++----
lib/rpmvs.c | 12 ++++++++++++
lib/rpmvs.h | 3 +++
3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c
index 1ba72a45e..810f7153d 100644
--- a/lib/rpmchecksig.c
+++ b/lib/rpmchecksig.c
@@ -187,11 +187,11 @@ rpmRC rpmpkgRead(struct rpmvs_s *vs, FD_t fd,
/* Finalize header range */
rpmvsFiniRange(vs, RPMSIG_HEADER);
- /* Unless disabled, read the payload, generating digest(s) on the fly. */
- if (!(rpmvsFlags(vs) & RPMVSF_NEEDPAYLOAD)) {
- /* Fish interesting tags from the main header. This is a bit hacky... */
- rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST);
+ /* Fish interesting tags from the main header. This is a bit hacky... */
+ rpmvsAppendTag(vs, blob, RPMTAG_PAYLOADDIGEST);
+ /* If needed and not explicitly disabled, read the payload as well. */
+ if (rpmvsRange(vs) & RPMSIG_PAYLOAD) {
/* Initialize digests ranging over the payload only */
rpmvsInitRange(vs, RPMSIG_PAYLOAD);
diff --git a/lib/rpmvs.c b/lib/rpmvs.c
index 622e48011..0d475af86 100644
--- a/lib/rpmvs.c
+++ b/lib/rpmvs.c
@@ -396,6 +396,18 @@ void rpmvsFiniRange(struct rpmvs_s *sis, int range)
}
}
+int rpmvsRange(struct rpmvs_s *vs)
+{
+ int range = 0;
+ for (int i = 0; i < vs->nsigs; i++) {
+ if (rpmsinfoDisabled(&vs->sigs[i], vs->vsflags))
+ continue;
+ range |= vs->sigs[i].range;
+ }
+
+ return range;
+}
+
static int sinfoCmp(const void *a, const void *b)
{
const struct rpmsinfo_s *sa = a;
--- rpm-4.14.3/lib/rpmvs.h.orig 2020-04-28 10:57:19.727347211 +0200
+++ rpm-4.14.3/lib/rpmvs.h 2020-04-28 10:57:43.622612015 +0200
@@ -66,6 +66,8 @@
void rpmvsFiniRange(struct rpmvs_s *sis, int range);
+int rpmvsRange(struct rpmvs_s *vs);
+
int rpmvsVerify(struct rpmvs_s *sis, int type,
rpmsinfoCb cb, void *cbdata);
--
2.20.1

@ -0,0 +1,27 @@
From d97d7b71de158660eb96b4f11d40b6626b85521a Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Tue, 16 Apr 2019 09:50:57 +0200
Subject: [PATCH] Pass RPM_BUILD_NCPUS to build scripts
Use %_smp_build_ncpus instead of the initial value
---
macros.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/macros.in b/macros.in
index fc587997d..a15e46f26 100644
--- a/macros.in
+++ b/macros.in
@@ -807,7 +807,8 @@ package or when debugging this package.\
RPM_OPT_FLAGS=\"%{optflags}\"\
RPM_ARCH=\"%{_arch}\"\
RPM_OS=\"%{_os}\"\
- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\
+ RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\
+ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\
RPM_DOC_DIR=\"%{_docdir}\"\
export RPM_DOC_DIR\
RPM_PACKAGE_NAME=\"%{NAME}\"\
--
2.21.0

@ -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 {

@ -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

@ -0,0 +1,41 @@
From aea53a4aead8bd71f519df35fcffd9eec76fbc01 Mon Sep 17 00:00:00 2001
Message-Id: <aea53a4aead8bd71f519df35fcffd9eec76fbc01.1554884465.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 26 Feb 2019 11:27:51 +0200
Subject: [PATCH] Return NULL string as None from utf8FromString()
Commit 84920f898315d09a57a3f1067433eaeb7de5e830 regressed dnf install
to segfault at the end due to some NULL string passed to strlen().
Check for NULL and return it as None, make it an inline function
to make this saner.
---
python/rpmsystem-py.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
index 87c750571..25938464a 100644
--- a/python/rpmsystem-py.h
+++ b/python/rpmsystem-py.h
@@ -19,11 +19,17 @@
#define PyInt_AsSsize_t PyLong_AsSsize_t
#endif
+static inline PyObject * utf8FromString(const char *s)
+{
/* In Python 3, we return all strings as surrogate-escaped utf-8 */
#if PY_MAJOR_VERSION >= 3
-#define utf8FromString(_s) PyUnicode_DecodeUTF8(_s, strlen(_s), "surrogateescape")
+ if (s != NULL)
+ return PyUnicode_DecodeUTF8(s, strlen(s), "surrogateescape");
#else
-#define utf8FromString(_s) PyBytes_FromString(_s)
+ if (s != NULL)
+ return PyBytes_FromString(s);
#endif
+ Py_RETURN_NONE;
+}
#endif /* H_SYSTEM_PYTHON */
--
2.20.1

@ -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

@ -0,0 +1,37 @@
From cb6aa82dbc10d554f8d234e934ae7c77e39a3ce2 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Tue, 12 Jan 2021 13:35:23 +0200
Subject: [PATCH] Unblock signals in forked scriptlets
Since commit c5f82d3f6223ebd0c5cc0a07ea60393ae7284929 we've blocked
most signals during transactions, which makes sense to rpm itself but
the signal mask is inherited to childs and carried even across exec(),
so all scriptlets are executing with those signals blocked as well.
Which in turn does not make sense, the scriptlets could run stuff that
actually depends on signal delivery (such as SIGALARM in RhBug:1913765).
Unblock all signals for forked scriptlet execution (Lua scriptlets are
totally different as they execute in-process for now)
---
lib/rpmscript.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
index 2ae3378f7..c69d29554 100644
--- a/lib/rpmscript.c
+++ b/lib/rpmscript.c
@@ -152,6 +152,11 @@ static void doScriptExec(ARGV_const_t argv, ARGV_const_t prefixes,
FD_t scriptFd, FD_t out)
{
int xx;
+ sigset_t set;
+
+ /* Unmask all signals, the scripts may need them */
+ sigfillset(&set);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
/* SIGPIPE is ignored in rpm, reset to default for the scriptlet */
(void) signal(SIGPIPE, SIG_DFL);
--
2.29.2

@ -0,0 +1,58 @@
From fc2c986d8f5e4174885ae377750185339636f062 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Mon, 15 Apr 2019 15:46:09 +0200
Subject: [PATCH] Use RPM_BUILD_NCPUS in brp-strip-static-archive
to speed the script up for large number of files to be looked at.
Use xargs -P instead of find -exec.
Add xargs to the test environment
Resolves rhbz1691822
---
scripts/brp-strip-static-archive | 8 +++++---
tests/Makefile.am | 2 +-
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive
index ddd3b2422..4dc449061 100755
--- a/scripts/brp-strip-static-archive
+++ b/scripts/brp-strip-static-archive
@@ -5,6 +5,7 @@ if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
fi
STRIP=${1:-strip}
+NCPUS=${RPM_BUILD_NCPUS:-1}
case `uname -a` in
Darwin*) exit 0 ;;
@@ -12,9 +13,10 @@ Darwin*) exit 0 ;;
esac
# Strip static libraries.
-for f in `find "$RPM_BUILD_ROOT" -type f -a -exec file {} \; | \
- grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
+for f in `find "$RPM_BUILD_ROOT" -type f | \
+ grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
+ xargs -r -P$NCPUS -n16 file | sed 's/: */: /' | \
grep 'current ar archive' | \
- sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do
+ sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p'`; do
$STRIP -g "$f"
done
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e2d759d82..ad9549a68 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -144,7 +144,7 @@ populate_testing:
for d in dev etc magic tmp var; do if [ ! -d testing/$${d} ]; then mkdir testing/$${d}; fi; done
for node in urandom stdin stderr stdout null full; do ln -s /dev/$${node} testing/dev/$${node}; done
for cf in hosts resolv.conf passwd shadow group gshadow mtab ; do [ -f /etc/$${cf} ] && ln -s /etc/$${cf} testing/etc/$${cf}; done
- for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done
+ for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils xargs; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done
for d in /proc /sys /selinux /etc/selinux; do if [ -d $${d} ]; then ln -s $${d} testing/$${d}; fi; done
(cd testing/magic && file -C)
HOME=$(abs_builddir)/testing gpg2 --import ${abs_srcdir}/data/keys/*.secret
--
2.21.0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,29 @@
From 9aae21d7610a7e8067ae932f36d1c8bb8583fe59 Mon Sep 17 00:00:00 2001
From: Pavlina Moravcova Varekova <pmoravco@redhat.com>
Date: Wed, 5 Jun 2019 06:07:00 +0200
Subject: [PATCH] Use [ ] in condition to avoid sub processes in
find-debuginfo.sh (#735)
Introduced in commit 1da9e83, spotted by covscan.
Modified to fix another covscan warning
---
scripts/find-debuginfo.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/find-debuginfo.sh b/scripts/find-debuginfo.sh
index 23286139e..d75da1108 100755
--- a/scripts/find-debuginfo.sh
+++ b/scripts/find-debuginfo.sh
@@ -213,7 +213,7 @@ if test -n "$build_id_seed" -a "$no_recompute_build_id" = "true"; then
exit 2
fi
-if ("$strip_g" = "true") && ("$strip_glibs" = "true"); then
+if [ "$strip_g" = "true" ] && [ "$strip_glibs" = "true" ]; then
echo >&2 "*** ERROR: -g and --g-libs cannot be used together"
exit 2
fi
--
2.21.0

@ -0,0 +1,26 @@
From 09d181d78c16e1751779586c606e85c11f360407 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Tue, 25 Jun 2019 18:04:20 +0200
Subject: [PATCH] Use newline as a delimiter to avoid xargs messing up file
names with quotes
which is the default behaviour otherwise.
Fixes rhbz#1721348
---
scripts/brp-strip-static-archive | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/brp-strip-static-archive b/scripts/brp-strip-static-archive
index 13d9a098b..f7fb26b87 100755
--- a/scripts/brp-strip-static-archive
+++ b/scripts/brp-strip-static-archive
@@ -15,4 +15,4 @@ esac
# Strip static libraries.
find "$RPM_BUILD_ROOT" -type f | \
grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
- xargs -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -I\{\} $STRIP -g \{\}" ARG0
+ xargs -d '\n' -r -P$NCPUS -n32 sh -c "file \"\$@\" | sed 's/: */: /' | grep 'current ar archive' | sed -n -e 's/^\(.*\):[ ]*current ar archive/\1/p' | xargs -d '\n' -I\{\} $STRIP -g \{\}" ARG0
--
2.21.0

@ -0,0 +1,38 @@
From 9cbc1fe444b048c3f7cf5ea09ab650d1c146d54a Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Wed, 20 Feb 2019 14:49:19 +0200
Subject: [PATCH] When doing the same thing more than once, use a loop...
No functional changes but this'll simplify the next commit quite a bit.
---
build/spec.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/build/spec.c b/build/spec.c
index e414e4102..80eaca611 100644
--- a/build/spec.c
+++ b/build/spec.c
@@ -303,15 +303,13 @@ rpmSpec newSpec(void)
spec->pool = rpmstrPoolCreate();
#ifdef WITH_LUA
- {
/* make sure patches and sources tables always exist */
rpmlua lua = NULL; /* global state */
- rpmluaDelVar(lua, "patches");
- rpmluaDelVar(lua, "sources");
- rpmluaPushTable(lua, "patches");
- rpmluaPushTable(lua, "sources");
- rpmluaPop(lua);
- rpmluaPop(lua);
+ const char * luavars[] = { "patches", "sources", NULL, };
+ for (const char **vp = luavars; vp && *vp; vp++) {
+ rpmluaDelVar(lua, *vp);
+ rpmluaPushTable(lua, *vp);
+ rpmluaPop(lua);
}
#endif
return spec;
--
2.26.2

@ -0,0 +1,44 @@
From 8fefd2bd21b30996ad0748eab6baadf915610642 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 13 Aug 2020 13:29:10 +0300
Subject: [PATCH] Work around buggy signature region preventing resigning
(RhBug:1851508)
Various proprietary packages in the wild have subtly malformed data
in the signature header, in particular wrt the immutable region size,
presumably from using some in-house/3rd party signing tools which do
not understand the immutable region business at all. This can prevent
resigning and signature deletion on such packages due to the more
thorough checking that rpmsign does.
As the old wisdom goes, be liberal in what you accept... we can easily
work around the crud by just taking a fresh copy of the contents that
are legit as such (otherwise the package would be uninstallable).
Adjusted for 4.14.3
--- rpm-4.14.3/sign/rpmgensig.c.orig 2020-10-29 16:00:38.785229048 +0100
+++ rpm-4.14.3/sign/rpmgensig.c 2020-10-29 16:08:55.997791345 +0100
@@ -401,12 +401,19 @@
if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) {
oh = headerCopyLoad(utd->data);
- nh = headerCopy(oh);
- headerFree(oh);
rpmtdFreeData(utd);
+ } else {
+ /* XXX should we warn if the immutable region is corrupt/missing? */
+ oh = headerLink(*hdrp);
+ }
+
+ if (oh) {
+ /* Perform a copy to eliminate crud from buggy signing tools etc */
+ nh = headerCopy(oh);
headerFree(*hdrp);
*hdrp = headerLink(nh);
headerFree(nh);
+ headerFree(oh);
}
}

@ -0,0 +1,490 @@
From ce6e8556a8f93327d6de0446f21ac5e549861d82 Mon Sep 17 00:00:00 2001
Message-Id: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
From: Mark Wielaard <mark@klomp.org>
Date: Mon, 17 Jun 2019 11:23:24 +0200
Subject: [PATCH 1/3] debugedit: Refactor reading/writing of relocated values.
This refactors the reading and writing of relocated values into seperate
helper functions (setup_relbuf and update_rela_data). It will be easier
to reuse this code in case we want to read/write relocated values in other
sections than DEBUG_INFO. The only functional change is that we explicitly
track whether the relocation data is updated, and only explicitly update
and write out the relocation data if so. In the case there were no strp
or stmt updates, there will also not be any relocation updates, even if
there is relocation data available.
All new debugedit testcases pass before and after this refactoring.
---
tools/debugedit.c | 395 +++++++++++++++++++++++++---------------------
1 file changed, 216 insertions(+), 179 deletions(-)
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 4be85b979..cf9cc3ca9 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -401,13 +401,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v)
relend). Might just update the addend. So relocations need to be
updated at the end. */
+static bool rel_updated;
+
#define do_write_32_relocated(ptr,val) ({ \
if (relptr && relptr < relend && relptr->ptr == ptr) \
{ \
if (reltype == SHT_REL) \
do_write_32 (ptr, val - relptr->addend); \
else \
- relptr->addend = val; \
+ { \
+ relptr->addend = val; \
+ rel_updated = true; \
+ } \
} \
else \
do_write_32 (ptr,val); \
@@ -418,14 +423,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v)
ptr += 4; \
})
-static struct
+typedef struct debug_section
{
const char *name;
unsigned char *data;
Elf_Data *elf_data;
size_t size;
int sec, relsec;
- } debug_sections[] =
+ REL *relbuf;
+ REL *relend;
+ } debug_section;
+
+static debug_section debug_sections[] =
{
#define DEBUG_INFO 0
#define DEBUG_ABBREV 1
@@ -458,6 +467,201 @@ static struct
{ NULL, NULL, NULL, 0, 0, 0 }
};
+static int
+rel_cmp (const void *a, const void *b)
+{
+ REL *rela = (REL *) a, *relb = (REL *) b;
+
+ if (rela->ptr < relb->ptr)
+ return -1;
+
+ if (rela->ptr > relb->ptr)
+ return 1;
+
+ return 0;
+}
+
+/* Returns a malloced REL array, or NULL when there are no relocations
+ for this section. When there are relocations, will setup relend,
+ as the last REL, and reltype, as SHT_REL or SHT_RELA. */
+static void
+setup_relbuf (DSO *dso, debug_section *sec, int *reltype)
+{
+ int ndx, maxndx;
+ GElf_Rel rel;
+ GElf_Rela rela;
+ GElf_Sym sym;
+ GElf_Addr base = dso->shdr[sec->sec].sh_addr;
+ Elf_Data *symdata = NULL;
+ int rtype;
+ REL *relbuf;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ int i = sec->relsec;
+
+ /* No relocations, or did we do this already? */
+ if (i == 0 || sec->relbuf != NULL)
+ {
+ relptr = sec->relbuf;
+ relend = sec->relend;
+ return;
+ }
+
+ scn = dso->scn[i];
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && data->d_buf != NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0);
+ assert (data->d_size == dso->shdr[i].sh_size);
+ maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
+ relbuf = malloc (maxndx * sizeof (REL));
+ *reltype = dso->shdr[i].sh_type;
+ if (relbuf == NULL)
+ error (1, errno, "%s: Could not allocate memory", dso->filename);
+
+ symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
+ assert (symdata != NULL && symdata->d_buf != NULL);
+ assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) == NULL);
+ assert (symdata->d_off == 0);
+ assert (symdata->d_size == dso->shdr[dso->shdr[i].sh_link].sh_size);
+
+ for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
+ {
+ if (dso->shdr[i].sh_type == SHT_REL)
+ {
+ gelf_getrel (data, ndx, &rel);
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ }
+ else
+ gelf_getrela (data, ndx, &rela);
+ gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
+ /* Relocations against section symbols are uninteresting in REL. */
+ if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
+ continue;
+ /* Only consider relocations against .debug_str, .debug_line
+ and .debug_abbrev. */
+ if (sym.st_shndx != debug_sections[DEBUG_STR].sec
+ && sym.st_shndx != debug_sections[DEBUG_LINE].sec
+ && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
+ continue;
+ rela.r_addend += sym.st_value;
+ rtype = ELF64_R_TYPE (rela.r_info);
+ switch (dso->ehdr.e_machine)
+ {
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
+ goto fail;
+ break;
+ case EM_386:
+ if (rtype != R_386_32)
+ goto fail;
+ break;
+ case EM_PPC:
+ case EM_PPC64:
+ if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
+ goto fail;
+ break;
+ case EM_S390:
+ if (rtype != R_390_32)
+ goto fail;
+ break;
+ case EM_IA_64:
+ if (rtype != R_IA64_SECREL32LSB)
+ goto fail;
+ break;
+ case EM_X86_64:
+ if (rtype != R_X86_64_32)
+ goto fail;
+ break;
+ case EM_ALPHA:
+ if (rtype != R_ALPHA_REFLONG)
+ goto fail;
+ break;
+#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
+ case EM_AARCH64:
+ if (rtype != R_AARCH64_ABS32)
+ goto fail;
+ break;
+#endif
+ case EM_68K:
+ if (rtype != R_68K_32)
+ goto fail;
+ break;
+#if defined(EM_RISCV) && defined(R_RISCV_32)
+ case EM_RISCV:
+ if (rtype != R_RISCV_32)
+ goto fail;
+ break;
+#endif
+ default:
+ fail:
+ error (1, 0, "%s: Unhandled relocation %d in %s section",
+ dso->filename, rtype, sec->name);
+ }
+ relend->ptr = sec->data
+ + (rela.r_offset - base);
+ relend->addend = rela.r_addend;
+ relend->ndx = ndx;
+ ++(relend);
+ }
+ if (relbuf == relend)
+ {
+ free (relbuf);
+ relbuf = NULL;
+ relend = NULL;
+ }
+ else
+ qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
+
+ sec->relbuf = relbuf;
+ sec->relend = relend;
+ relptr = relbuf;
+}
+
+/* Updates SHT_RELA section associated with the given section based on
+ the relbuf data. The relbuf data is freed at the end. */
+static void
+update_rela_data (DSO *dso, struct debug_section *sec)
+{
+ Elf_Data *symdata;
+ int relsec_ndx = sec->relsec;
+ Elf_Data *data = elf_getdata (dso->scn[relsec_ndx], NULL);
+ symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link],
+ NULL);
+
+ relptr = sec->relbuf;
+ relend = sec->relend;
+ while (relptr < relend)
+ {
+ GElf_Sym sym;
+ GElf_Rela rela;
+ int ndx = relptr->ndx;
+
+ if (gelf_getrela (data, ndx, &rela) == NULL)
+ error (1, 0, "Couldn't get relocation: %s",
+ elf_errmsg (-1));
+
+ if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info),
+ &sym) == NULL)
+ error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1));
+
+ rela.r_addend = relptr->addend - sym.st_value;
+
+ if (gelf_update_rela (data, ndx, &rela) == 0)
+ error (1, 0, "Couldn't update relocations: %s",
+ elf_errmsg (-1));
+
+ ++relptr;
+ }
+ elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
+
+ free (sec->relbuf);
+}
+
struct abbrev_attr
{
unsigned int attr;
@@ -1743,20 +1947,6 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
return ptr;
}
-static int
-rel_cmp (const void *a, const void *b)
-{
- REL *rela = (REL *) a, *relb = (REL *) b;
-
- if (rela->ptr < relb->ptr)
- return -1;
-
- if (rela->ptr > relb->ptr)
- return 1;
-
- return 0;
-}
-
static int
line_rel_cmp (const void *a, const void *b)
{
@@ -1871,132 +2061,7 @@ edit_dwarf2 (DSO *dso)
htab_t abbrev;
struct abbrev_tag tag, *t;
int phase;
- REL *relbuf = NULL;
-
- if (debug_sections[DEBUG_INFO].relsec)
- {
- int ndx, maxndx;
- GElf_Rel rel;
- GElf_Rela rela;
- GElf_Sym sym;
- GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
- Elf_Data *symdata = NULL;
- int rtype;
-
- i = debug_sections[DEBUG_INFO].relsec;
- scn = dso->scn[i];
- data = elf_getdata (scn, NULL);
- assert (data != NULL && data->d_buf != NULL);
- assert (elf_getdata (scn, data) == NULL);
- assert (data->d_off == 0);
- assert (data->d_size == dso->shdr[i].sh_size);
- maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
- relbuf = malloc (maxndx * sizeof (REL));
- reltype = dso->shdr[i].sh_type;
- if (relbuf == NULL)
- error (1, errno, "%s: Could not allocate memory", dso->filename);
-
- symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
- assert (symdata != NULL && symdata->d_buf != NULL);
- assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata)
- == NULL);
- assert (symdata->d_off == 0);
- assert (symdata->d_size
- == dso->shdr[dso->shdr[i].sh_link].sh_size);
-
- for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
- {
- if (dso->shdr[i].sh_type == SHT_REL)
- {
- gelf_getrel (data, ndx, &rel);
- rela.r_offset = rel.r_offset;
- rela.r_info = rel.r_info;
- rela.r_addend = 0;
- }
- else
- gelf_getrela (data, ndx, &rela);
- gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
- /* Relocations against section symbols are uninteresting
- in REL. */
- if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
- continue;
- /* Only consider relocations against .debug_str, .debug_line
- and .debug_abbrev. */
- if (sym.st_shndx != debug_sections[DEBUG_STR].sec
- && sym.st_shndx != debug_sections[DEBUG_LINE].sec
- && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
- continue;
- rela.r_addend += sym.st_value;
- rtype = ELF64_R_TYPE (rela.r_info);
- switch (dso->ehdr.e_machine)
- {
- case EM_SPARC:
- case EM_SPARC32PLUS:
- case EM_SPARCV9:
- if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
- goto fail;
- break;
- case EM_386:
- if (rtype != R_386_32)
- goto fail;
- break;
- case EM_PPC:
- case EM_PPC64:
- if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
- goto fail;
- break;
- case EM_S390:
- if (rtype != R_390_32)
- goto fail;
- break;
- case EM_IA_64:
- if (rtype != R_IA64_SECREL32LSB)
- goto fail;
- break;
- case EM_X86_64:
- if (rtype != R_X86_64_32)
- goto fail;
- break;
- case EM_ALPHA:
- if (rtype != R_ALPHA_REFLONG)
- goto fail;
- break;
-#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
- case EM_AARCH64:
- if (rtype != R_AARCH64_ABS32)
- goto fail;
- break;
-#endif
- case EM_68K:
- if (rtype != R_68K_32)
- goto fail;
- break;
-#if defined(EM_RISCV) && defined(R_RISCV_32)
- case EM_RISCV:
- if (rtype != R_RISCV_32)
- goto fail;
- break;
-#endif
- default:
- fail:
- error (1, 0, "%s: Unhandled relocation %d in .debug_info section",
- dso->filename, rtype);
- }
- relend->ptr = debug_sections[DEBUG_INFO].data
- + (rela.r_offset - base);
- relend->addend = rela.r_addend;
- relend->ndx = ndx;
- ++relend;
- }
- if (relbuf == relend)
- {
- free (relbuf);
- relbuf = NULL;
- relend = NULL;
- }
- else
- qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
- }
+ bool info_rel_updated = false;
for (phase = 0; phase < 2; phase++)
{
@@ -2008,7 +2073,8 @@ edit_dwarf2 (DSO *dso)
break;
ptr = debug_sections[DEBUG_INFO].data;
- relptr = relbuf;
+ setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype);
+ rel_updated = false;
endsec = ptr + debug_sections[DEBUG_INFO].size;
while (ptr < endsec)
{
@@ -2096,6 +2162,10 @@ edit_dwarf2 (DSO *dso)
htab_delete (abbrev);
}
+ /* Remember whether any .debug_info relocations might need
+ to be updated. */
+ info_rel_updated = rel_updated;
+
/* We might have to recalculate/rewrite the debug_line
section. We need to do that before going into phase one
so we have all new offsets. We do this separately from
@@ -2240,41 +2310,8 @@ edit_dwarf2 (DSO *dso)
dirty_section (DEBUG_INFO);
/* Update any debug_info relocations addends we might have touched. */
- if (relbuf != NULL && reltype == SHT_RELA)
- {
- Elf_Data *symdata;
- int relsec_ndx = debug_sections[DEBUG_INFO].relsec;
- data = elf_getdata (dso->scn[relsec_ndx], NULL);
- symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link],
- NULL);
-
- relptr = relbuf;
- while (relptr < relend)
- {
- GElf_Sym sym;
- GElf_Rela rela;
- int ndx = relptr->ndx;
-
- if (gelf_getrela (data, ndx, &rela) == NULL)
- error (1, 0, "Couldn't get relocation: %s",
- elf_errmsg (-1));
-
- if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info),
- &sym) == NULL)
- error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1));
-
- rela.r_addend = relptr->addend - sym.st_value;
-
- if (gelf_update_rela (data, ndx, &rela) == 0)
- error (1, 0, "Couldn't update relocations: %s",
- elf_errmsg (-1));
-
- ++relptr;
- }
- elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
- }
-
- free (relbuf);
+ if (info_rel_updated)
+ update_rela_data (dso, &debug_sections[DEBUG_INFO]);
}
return 0;
--
2.23.0

@ -0,0 +1,304 @@
From 201a71ce18734b1cebc337225f345fd754a6414f Mon Sep 17 00:00:00 2001
Message-Id: <201a71ce18734b1cebc337225f345fd754a6414f.1573552234.git.pmatilai@redhat.com>
In-Reply-To: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
References: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
From: Mark Wielaard <mark@klomp.org>
Date: Mon, 17 Jun 2019 11:23:25 +0200
Subject: [PATCH 2/3] Handle .debug_macro in debugedit.
When compiling with -g3 gcc will generate a .debug_macro section
which has pointers to the .debug_str section. Since we might rewrite
the .debug_str section, we also need to update any .debug_macro
pointers.
Updated the debugedit.at testcase by building everything with -g
and add various checks to see the .debug_macro section looks OK
after running debugedit. Added a new rpmbuild.at testcase to check
handing of .debug_macro in the whole rpmbuild debuginfo pipeline
to double check the separate .debug file also contains the macros.
Original patch by Michael Schroeder <mls@suse.de>. Extended by
Mark Wielaard <mark@klomp.org> to deal with relocations and possible
multiple COMDAT .debug_macro sections.
---
tests/Makefile.am | 1 +
tests/data/SPECS/hello-g3.spec | 60 ++++++++++
tests/debugedit.at | 79 ++++++++++++-
tests/rpmbuild.at | 33 ++++++
tools/debugedit.c | 196 +++++++++++++++++++++++++++++++--
5 files changed, 356 insertions(+), 13 deletions(-)
create mode 100644 tests/data/SPECS/hello-g3.spec
[ test-suite part edited out, too painful to backport ]
diff --git a/tools/debugedit.c b/tools/debugedit.c
index cf9cc3ca9..84483ef5e 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -41,6 +41,7 @@
#include <gelf.h>
#include <dwarf.h>
+
/* Unfortunately strtab manipulation functions were only officially added
to elfutils libdw in 0.167. Before that there were internal unsupported
ebl variants. While libebl.h isn't supported we'll try to use it anyway
@@ -432,6 +433,7 @@ typedef struct debug_section
int sec, relsec;
REL *relbuf;
REL *relend;
+ struct debug_section *next; /* Only happens for COMDAT .debug_macro. */
} debug_section;
static debug_section debug_sections[] =
@@ -1989,11 +1991,35 @@ edit_dwarf2 (DSO *dso)
for (j = 0; debug_sections[j].name; ++j)
if (strcmp (name, debug_sections[j].name) == 0)
{
+ struct debug_section *debug_sec = &debug_sections[j];
if (debug_sections[j].data)
{
- error (0, 0, "%s: Found two copies of %s section",
- dso->filename, name);
- return 1;
+ if (j != DEBUG_MACRO)
+ {
+ error (0, 0, "%s: Found two copies of %s section",
+ dso->filename, name);
+ return 1;
+ }
+ else
+ {
+ /* In relocatable files .debug_macro might
+ appear multiple times as COMDAT
+ section. */
+ struct debug_section *sec;
+ sec = calloc (sizeof (struct debug_section), 1);
+ if (sec == NULL)
+ error (1, errno,
+ "%s: Could not allocate more macro sections",
+ dso->filename);
+ sec->name = ".debug_macro";
+
+ struct debug_section *macro_sec = debug_sec;
+ while (macro_sec->next != NULL)
+ macro_sec = macro_sec->next;
+
+ macro_sec->next = sec;
+ debug_sec = sec;
+ }
}
scn = dso->scn[i];
@@ -2002,10 +2028,10 @@ edit_dwarf2 (DSO *dso)
assert (elf_getdata (scn, data) == NULL);
assert (data->d_off == 0);
assert (data->d_size == dso->shdr[i].sh_size);
- debug_sections[j].data = data->d_buf;
- debug_sections[j].elf_data = data;
- debug_sections[j].size = data->d_size;
- debug_sections[j].sec = i;
+ debug_sec->data = data->d_buf;
+ debug_sec->elf_data = data;
+ debug_sec->size = data->d_size;
+ debug_sec->sec = i;
break;
}
@@ -2028,7 +2054,26 @@ edit_dwarf2 (DSO *dso)
+ (dso->shdr[i].sh_type == SHT_RELA),
debug_sections[j].name) == 0)
{
- debug_sections[j].relsec = i;
+ if (j == DEBUG_MACRO)
+ {
+ /* Pick the correct one. */
+ int rel_target = dso->shdr[i].sh_info;
+ struct debug_section *macro_sec = &debug_sections[j];
+ while (macro_sec != NULL)
+ {
+ if (macro_sec->sec == rel_target)
+ {
+ macro_sec->relsec = i;
+ break;
+ }
+ macro_sec = macro_sec->next;
+ }
+ if (macro_sec == NULL)
+ error (0, 1, "No .debug_macro reloc section: %s",
+ dso->filename);
+ }
+ else
+ debug_sections[j].relsec = i;
break;
}
}
@@ -2062,6 +2107,7 @@ edit_dwarf2 (DSO *dso)
struct abbrev_tag tag, *t;
int phase;
bool info_rel_updated = false;
+ bool macro_rel_updated = false;
for (phase = 0; phase < 2; phase++)
{
@@ -2279,6 +2325,113 @@ edit_dwarf2 (DSO *dso)
}
}
+ /* The .debug_macro section also contains offsets into the
+ .debug_str section and references to the .debug_line
+ tables, so we need to update those as well if we update
+ the strings or the stmts. */
+ if ((need_strp_update || need_stmt_update)
+ && debug_sections[DEBUG_MACRO].data)
+ {
+ /* There might be multiple (COMDAT) .debug_macro sections. */
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
+ {
+ setup_relbuf(dso, macro_sec, &reltype);
+ rel_updated = false;
+
+ ptr = macro_sec->data;
+ endsec = ptr + macro_sec->size;
+ int op = 0, macro_version, macro_flags;
+ int offset_len = 4, line_offset = 0;
+
+ while (ptr < endsec)
+ {
+ if (!op)
+ {
+ macro_version = read_16 (ptr);
+ macro_flags = read_8 (ptr);
+ if (macro_version < 4 || macro_version > 5)
+ error (1, 0, "unhandled .debug_macro version: %d",
+ macro_version);
+ if ((macro_flags & ~2) != 0)
+ error (1, 0, "unhandled .debug_macro flags: 0x%x",
+ macro_flags);
+
+ offset_len = (macro_flags & 0x01) ? 8 : 4;
+ line_offset = (macro_flags & 0x02) ? 1 : 0;
+
+ if (offset_len != 4)
+ error (0, 1,
+ "Cannot handle 8 byte macro offsets: %s",
+ dso->filename);
+
+ /* Update the line_offset if it is there. */
+ if (line_offset)
+ {
+ if (phase == 0)
+ ptr += offset_len;
+ else
+ {
+ size_t idx, new_idx;
+ idx = do_read_32_relocated (ptr);
+ new_idx = find_new_list_offs (&dso->lines,
+ idx);
+ write_32_relocated (ptr, new_idx);
+ }
+ }
+ }
+
+ op = read_8 (ptr);
+ if (!op)
+ continue;
+ switch(op)
+ {
+ case DW_MACRO_GNU_define:
+ case DW_MACRO_GNU_undef:
+ read_uleb128 (ptr);
+ ptr = ((unsigned char *) strchr ((char *) ptr, '\0')
+ + 1);
+ break;
+ case DW_MACRO_GNU_start_file:
+ read_uleb128 (ptr);
+ read_uleb128 (ptr);
+ break;
+ case DW_MACRO_GNU_end_file:
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ read_uleb128 (ptr);
+ if (phase == 0)
+ {
+ size_t idx = read_32_relocated (ptr);
+ record_existing_string_entry_idx (&dso->strings,
+ idx);
+ }
+ else
+ {
+ struct stridxentry *entry;
+ size_t idx, new_idx;
+ idx = do_read_32_relocated (ptr);
+ entry = string_find_entry (&dso->strings, idx);
+ new_idx = strent_offset (entry->entry);
+ write_32_relocated (ptr, new_idx);
+ }
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ ptr += offset_len;
+ break;
+ default:
+ error (1, 0, "Unhandled DW_MACRO op 0x%x", op);
+ break;
+ }
+ }
+
+ if (rel_updated)
+ macro_rel_updated = true;
+ macro_sec = macro_sec->next;
+ }
+ }
+
/* Same for the debug_str section. Make sure everything is
in place for phase 1 updating of debug_info
references. */
@@ -2308,10 +2461,24 @@ edit_dwarf2 (DSO *dso)
new strp, strings and/or linep offsets. */
if (need_strp_update || need_string_replacement || need_stmt_update)
dirty_section (DEBUG_INFO);
+ if (need_strp_update || need_stmt_update)
+ dirty_section (DEBUG_MACRO);
+ if (need_stmt_update)
+ dirty_section (DEBUG_LINE);
- /* Update any debug_info relocations addends we might have touched. */
+ /* Update any relocations addends we might have touched. */
if (info_rel_updated)
update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+
+ if (macro_rel_updated)
+ {
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
+ {
+ update_rela_data (dso, macro_sec);
+ macro_sec = macro_sec->next;
+ }
+ }
}
return 0;
@@ -2843,6 +3010,17 @@ main (int argc, char *argv[])
destroy_lines (&dso->lines);
free (dso);
+ /* In case there were multiple (COMDAT) .debug_macro sections,
+ free them. */
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ macro_sec = macro_sec->next;
+ while (macro_sec != NULL)
+ {
+ struct debug_section *next = macro_sec->next;
+ free (macro_sec);
+ macro_sec = next;
+ }
+
poptFreeContext (optCon);
return 0;
--
2.23.0

@ -0,0 +1,77 @@
From 172e1f5ec0e37c8aab91a2ae35bd73ea594432cb Mon Sep 17 00:00:00 2001
Message-Id: <172e1f5ec0e37c8aab91a2ae35bd73ea594432cb.1571920849.git.pmatilai@redhat.com>
In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 4 Oct 2018 13:36:09 +0300
Subject: [PATCH 2/5] Use Python 3 -compatible exception syntax in tests
Makes a few tests pass that failed before, and others now fail
a little bit later...
(cherry picked from commit 511eef19298765e3639bccbe98bc3a50023f45b2)
---
tests/rpmpython.at | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
index 3a7c251f1..1daaf1216 100644
--- a/tests/rpmpython.at
+++ b/tests/rpmpython.at
@@ -96,7 +96,7 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]:
try:
x = getattr(h, a)
myprint(x)
- except AttributeError, exc:
+ except AttributeError as exc:
myprint(exc)
],
[testpkg-5:1.0-1.noarch
@@ -119,7 +119,7 @@ h2['dirindexes'] = [ 0, 0, 1 ]
for h in [h1, h2]:
try:
myprint(','.join(h['filenames']))
- except rpm.error, exc:
+ except rpm.error as exc:
myprint(exc)
],
[invalid header data
@@ -164,7 +164,7 @@ rpm.setLogFile(sink)
try:
h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm')
myprint(h['arch'])
-except rpm.error, e:
+except rpm.error as e:
myprint(e)
],
[public key not available
@@ -183,7 +183,7 @@ ts.setKeyring(keyring)
try:
h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-2.0-1.x86_64-signed.rpm')
myprint(h['arch'])
-except rpm.error, e:
+except rpm.error as e:
myprint(e)
],
[x86_64]
@@ -207,7 +207,7 @@ h = rpm.hdr()
h['name'] = "foo"
try:
ts.addInstall(h, 'foo', 'u')
-except rpm.error, err:
+except rpm.error as err:
myprint(err)
for e in ts:
myprint(e.NEVRA())
@@ -228,7 +228,7 @@ h['dirnames'] = ['/opt' '/flopt']
h['dirindexes'] = [ 1, 2, 3 ]
try:
ts.addInstall(h, 'foo', 'u')
-except rpm.error, err:
+except rpm.error as err:
myprint(err)
for e in ts:
myprint(e.NEVRA())
--
2.21.0

@ -0,0 +1,44 @@
From 6525a9bf1529944741f273cb9fde5619f006a673 Mon Sep 17 00:00:00 2001
Message-Id: <6525a9bf1529944741f273cb9fde5619f006a673.1571920849.git.pmatilai@redhat.com>
In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 4 Oct 2018 17:41:19 +0300
Subject: [PATCH 3/5] Fix couple of bytes vs strings issues in Python tests
For the purposes of rpmio testing and importing public key, we're
dealing with bytes rather than encoded strings. In the carefree days
of Python 2 such details didn't matter, in Python 3 they cause failures.
The signed package test still fails after this one but it's due to
a more general issue.
(cherry picked from commit 86f7898dd6a7fa8718c02675f5a7ee04ff987422)
---
tests/rpmpython.at | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
index 1daaf1216..ae020ae95 100644
--- a/tests/rpmpython.at
+++ b/tests/rpmpython.at
@@ -33,7 +33,7 @@ prexp(mname)
[])
RPMPY_TEST([basic rpmio],[
-msg = 'Killroy was here\n'
+msg = b'Killroy was here\n'
data = msg * 10
# TODO: test other compression types too if built in
for iot in [ 'fpio', 'fdio', 'ufdio', 'gzdio' ]:
@@ -173,7 +173,7 @@ except rpm.error as e:
RPMPY_TEST([reading a signed package file 2],[
-keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub').read()
+keydata = open('${RPMDATA}/keys/rpm.org-rsa-2048-test.pub', 'rb').read()
pubkey = rpm.pubkey(keydata)
keyring = rpm.keyring()
keyring.addKey(pubkey)
--
2.21.0

@ -0,0 +1,114 @@
From df089e178da0918dc74a8572a99324b0987bce30 Mon Sep 17 00:00:00 2001
Message-Id: <df089e178da0918dc74a8572a99324b0987bce30.1554983206.git.pmatilai@redhat.com>
In-Reply-To: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com>
References: <2ec0832287bd1443ebf336f8a98293f30bfa2036.1554983205.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 18 Mar 2019 15:56:34 +0200
Subject: [PATCH 3/3] Verify packages before signing (RhBug:1646388)
Permitting corrupted packages to be signed is bad business for everybody
involved, this is something we should've always done. Besides being an
actual security risk, it can lead to odd results with verification
especially with the payload digest on signed packages.
One point worth noting is that this means that pre 4.14-packages cannot
be signed in FIPS mode now because there's no way to validate the package
payload range due to MD5 being disabled. This seems like a feature and
not a limitation, so disabler for the verify step intentionally left out.
Optimally we'd verify the package on the same read that's passed
to gpg but for simplicitys sake that's left as an future exercise,
now we simply read the package twice.
---
sign/rpmgensig.c | 32 ++++++++++++++++++++++++++++++++
tests/rpmsigdig.at | 20 ++++++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 2bcbab768..5be542001 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -21,6 +21,7 @@
#include "lib/rpmlead.h"
#include "lib/signature.h"
+#include "lib/rpmvs.h"
#include "sign/rpmsignfiles.h"
#include "debug.h"
@@ -489,6 +490,31 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
#endif
}
+static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)
+{
+ char **msg = cbdata;
+ if (sinfo->rc && *msg == NULL)
+ *msg = rpmsinfoMsg(sinfo);
+ return (sinfo->rc != RPMRC_FAIL);
+}
+
+/* Require valid digests on entire package for signing. */
+static int checkPkg(FD_t fd, char **msg)
+{
+ int rc;
+ struct rpmvs_s *vs = rpmvsCreate(RPMSIG_DIGEST_TYPE, 0, NULL);
+ off_t offset = Ftell(fd);
+
+ Fseek(fd, 0, SEEK_SET);
+ rc = rpmpkgRead(vs, fd, NULL, NULL, msg);
+ if (!rc)
+ rc = rpmvsVerify(vs, RPMSIG_DIGEST_TYPE, msgCb, msg);
+ Fseek(fd, offset, SEEK_SET);
+
+ rpmvsFree(vs);
+ return rc;
+}
+
/** \ingroup rpmcli
* Create/modify elements in signature header.
* @param rpm path to package
@@ -519,6 +545,12 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)
if (manageFile(&fd, rpm, O_RDWR))
goto exit;
+ /* Ensure package is intact before attempting to sign */
+ if ((rc = checkPkg(fd, &msg))) {
+ rpmlog(RPMLOG_ERR, "not signing corrupt package %s: %s\n", rpm, msg);
+ goto exit;
+ }
+
if ((rc = rpmLeadRead(fd, &msg)) != RPMRC_OK) {
rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg);
goto exit;
diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at
index 413c3d2c8..e93420306 100644
--- a/tests/rpmsigdig.at
+++ b/tests/rpmsigdig.at
@@ -472,3 +472,23 @@ run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64-sign
[],
[])
AT_CLEANUP
+
+AT_SETUP([rpmsign --addsign <corrupted>])
+AT_KEYWORDS([rpmsign signature])
+AT_CHECK([
+RPMDB_CLEAR
+RPMDB_INIT
+rm -rf "${TOPDIR}"
+
+pkg="hello-2.0-1.x86_64.rpm"
+cp "${RPMTEST}"/data/RPMS/${pkg} "${RPMTEST}"/tmp/${pkg}
+dd if=/dev/zero of="${RPMTEST}"/tmp/${pkg} \
+ conv=notrunc bs=1 seek=333 count=4 2> /dev/null
+run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}/tmp/${pkg}"
+],
+[1],
+[/home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm:
+],
+[error: not signing corrupt package /home/pmatilai/repos/rpm/tests/testing/tmp/hello-2.0-1.x86_64.rpm: MD5 digest: BAD (Expected 007ca1d8b35cca02a1854ba301c5432e != 137ca1d8b35cca02a1854ba301c5432e)
+])
+AT_CLEANUP
--
2.20.1

@ -0,0 +1,30 @@
From 00a0afd5e079a73ef6871f1538f34fa4e67892e6 Mon Sep 17 00:00:00 2001
Message-Id: <00a0afd5e079a73ef6871f1538f34fa4e67892e6.1573552234.git.pmatilai@redhat.com>
In-Reply-To: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
References: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
From: Mark Wielaard <mark@klomp.org>
Date: Mon, 17 Jun 2019 11:23:26 +0200
Subject: [PATCH 3/3] debugedit: Make sure .debug_line old/new idx start equal.
Found by running the debugedit tests under valgrind.
If the old and new .debug_line offset isn't changed then we might
write out an uninitialized new_idx.
---
tools/debugedit.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 84483ef5e..9f8dcd0fb 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -1177,6 +1177,7 @@ get_line_table (DSO *dso, size_t off, struct line_table **table)
*table = NULL;
t->old_idx = off;
+ t->new_idx = off;
t->size_diff = 0;
t->replace_dirs = false;
t->replace_files = false;
--
2.23.0

@ -0,0 +1,109 @@
From 0b1456ed4c00a021389acea4b6b10d475986b660 Mon Sep 17 00:00:00 2001
Message-Id: <0b1456ed4c00a021389acea4b6b10d475986b660.1571920849.git.pmatilai@redhat.com>
In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 4 Oct 2018 18:05:37 +0300
Subject: [PATCH 4/5] Bump the minimum Python version requirement to 2.7
Older Python versions are long since past their EOL, we don't need to
support them either. Python 2.7 is also the least incompatible version
compared to Python 3, going forward. Nuke the now unnecessary compat
macros.
(cherry picked from commit 3f3cb3eabf7bb49dcc6e691601f89500b3487e06)
---
configure.ac | 2 +-
python/header-py.c | 4 ++--
python/rpmsystem-py.h | 33 ---------------------------------
python/spec-py.c | 2 +-
4 files changed, 4 insertions(+), 37 deletions(-)
diff --git a/configure.ac b/configure.ac
index 34ea85f9f..4d1a48e5f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -800,7 +800,7 @@ esac],
WITH_PYTHON_SUBPACKAGE=0
AS_IF([test "$enable_python" = yes],[
- AM_PATH_PYTHON([2.6],[
+ AM_PATH_PYTHON([2.7],[
PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}], [WITH_PYTHON_SUBPACKAGE=1])
AC_SUBST(PYTHON_CFLAGS)
AC_SUBST(PYTHON_LIB)
diff --git a/python/header-py.c b/python/header-py.c
index 628b48534..c9d54e869 100644
--- a/python/header-py.c
+++ b/python/header-py.c
@@ -376,8 +376,8 @@ static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
if (obj == NULL) {
h = headerNew();
- } else if (CAPSULE_CHECK(obj)) {
- h = CAPSULE_EXTRACT(obj, "rpm._C_Header");
+ } else if (PyCapsule_CheckExact(obj)) {
+ h = PyCapsule_GetPointer(obj, "rpm._C_Header");
headerLink(h);
} else if (hdrObject_Check(obj)) {
h = headerCopy(((hdrObject*) obj)->h);
diff --git a/python/rpmsystem-py.h b/python/rpmsystem-py.h
index c8423e3dc..955d60cd3 100644
--- a/python/rpmsystem-py.h
+++ b/python/rpmsystem-py.h
@@ -9,39 +9,6 @@
#include <Python.h>
#include <structmember.h>
-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0205
-typedef ssize_t Py_ssize_t;
-typedef Py_ssize_t (*lenfunc)(PyObject *);
-#endif
-
-/* Compatibility macros for Python < 2.6 */
-#ifndef PyVarObject_HEAD_INIT
-#define PyVarObject_HEAD_INIT(type, size) \
- PyObject_HEAD_INIT(type) size,
-#endif
-
-#ifndef Py_TYPE
-#define Py_TYPE(o) ((o)->ob_type)
-#endif
-
-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) < 0x0206
-#define PyBytes_Check PyString_Check
-#define PyBytes_FromString PyString_FromString
-#define PyBytes_FromStringAndSize PyString_FromStringAndSize
-#define PyBytes_Size PyString_Size
-#define PyBytes_AsString PyString_AsString
-#endif
-
-#if ((PY_MAJOR_VERSION << 8) | (PY_MINOR_VERSION << 0)) >= 0x0207
-#define CAPSULE_BUILD(ptr,name) PyCapsule_New(ptr, name, NULL)
-#define CAPSULE_CHECK(obj) PyCapsule_CheckExact(obj)
-#define CAPSULE_EXTRACT(obj,name) PyCapsule_GetPointer(obj, name)
-#else
-#define CAPSULE_BUILD(ptr,name) PyCObject_FromVoidPtr(ptr, NULL)
-#define CAPSULE_CHECK(obj) PyCObject_Check(obj)
-#define CAPSULE_EXTRACT(obj,name) PyCObject_AsVoidPtr(obj)
-#endif
-
/* For Python 3, use the PyLong type throughout in place of PyInt */
#if PY_MAJOR_VERSION >= 3
#define PyInt_Check PyLong_Check
diff --git a/python/spec-py.c b/python/spec-py.c
index fa7e58928..4efdbf4bf 100644
--- a/python/spec-py.c
+++ b/python/spec-py.c
@@ -34,7 +34,7 @@ static PyObject *makeHeader(Header h)
PyObject *rpmmod = PyImport_ImportModuleNoBlock("rpm");
if (rpmmod == NULL) return NULL;
- PyObject *ptr = CAPSULE_BUILD(h, "rpm._C_Header");
+ PyObject *ptr = PyCapsule_New(h, "rpm._C_Header", NULL);
PyObject *hdr = PyObject_CallMethod(rpmmod, "hdr", "(O)", ptr);
Py_XDECREF(ptr);
Py_XDECREF(rpmmod);
--
2.21.0

@ -0,0 +1,41 @@
From 98470eccf09b80ed11528ac893852d649c50be72 Mon Sep 17 00:00:00 2001
Message-Id: <98470eccf09b80ed11528ac893852d649c50be72.1571920849.git.pmatilai@redhat.com>
In-Reply-To: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
References: <6b6c4d881dc6fc99f949dac4aaf9a513542f9956.1571920849.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 5 Oct 2018 14:05:27 +0300
Subject: [PATCH 5/5] Drop an unnecessary Python 2 vs 3 incompatibility from
the test
Python 2 speaks about 'type' whereas 3 speaks about 'class', which from
our perspective is just unnecessary pain with no gain.
(cherry picked from commit ff3d8ac2e5cb4456ad1355f227f3ccef08e01972)
---
tests/rpmpython.at | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/rpmpython.at b/tests/rpmpython.at
index ae020ae95..bc42e49e4 100644
--- a/tests/rpmpython.at
+++ b/tests/rpmpython.at
@@ -92,7 +92,7 @@ h['arch'] = 'noarch'
myprint(h['nevra'])
del h['epoch']
myprint(h['nevra'])
-for a in ['name', 'bugurl', '__class__', '__foo__', ]:
+for a in ['name', 'bugurl', '__foo__', ]:
try:
x = getattr(h, a)
myprint(x)
@@ -103,7 +103,6 @@ for a in ['name', 'bugurl', '__class__', '__foo__', ]:
testpkg-1.0-1.noarch
testpkg
None
-<type 'rpm.hdr'>
'rpm.hdr' object has no attribute '__foo__']
)
--
2.21.0

@ -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

@ -0,0 +1,26 @@
From 682397a8e2758058f780cccd51b570d39415b9b2 Mon Sep 17 00:00:00 2001
From: Tomas Orsava <torsava@redhat.com>
Date: Tue, 3 Jul 2018 14:58:32 +0200
Subject: [PATCH] Compile with Platform-Python binary where relevant
---
scripts/brp-python-bytecompile | 3 +++
1 file changed, 3 insertions(+)
diff --git a/scripts/brp-python-bytecompile b/scripts/brp-python-bytecompile
index 7ed1d7f..9d0a421 100644
--- a/scripts/brp-python-bytecompile
+++ b/scripts/brp-python-bytecompile
@@ -60,6 +60,9 @@ shopt -s nullglob
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
+ python_binary=/usr/libexec/platform-python
+ fi
real_libdir=${python_libdir/$RPM_BUILD_ROOT/}
echo "Bytecompiling .py files below $python_libdir using $python_binary"
--
2.14.4

@ -0,0 +1,11 @@
--- a/platform.in 2018-07-19 17:24:58.737922904 +0200
+++ b/platform.in 2018-07-19 17:25:25.480028741 +0200
@@ -65,7 +65,7 @@
%__arch_install_post @ARCH_INSTALL_POST@
%_python_bytecompile_errors_terminate_build 0
-%_python_bytecompile_extra 1
+%_python_bytecompile_extra 0
# Standard brp-macro naming:
# convert all '-' in basename to '_', add two leading underscores.

@ -0,0 +1,11 @@
--- rpm-4.14.3/plugins/selinux.c.orig 2020-05-11 16:07:22.873791795 +0200
+++ rpm-4.14.3/plugins/selinux.c 2020-05-11 16:10:11.701771157 +0200
@@ -47,7 +47,7 @@
sehandle = selabel_open(SELABEL_CTX_FILE, opts, 1);
- rpmlog(RPMLOG_DEBUG, "selabel_open: (%s) %s\n",
+ rpmlog((sehandle == NULL) ? RPMLOG_ERR : RPMLOG_DEBUG, "selabel_open: (%s) %s\n",
path, (sehandle == NULL ? strerror(errno) : ""));
return (sehandle != NULL) ? RPMRC_OK : RPMRC_FAIL;

@ -0,0 +1,12 @@
diff -up rpm-4.11.1-rc1/macros.in.siteconfig rpm-4.11.1-rc1/macros.in
--- rpm-4.11.1-rc1/macros.in.siteconfig 2013-06-07 13:19:21.000000000 +0300
+++ rpm-4.11.1-rc1/macros.in 2013-06-11 15:06:59.525747503 +0300
@@ -647,6 +647,8 @@ package or when debugging this package.\
export CLASSPATH}\
PKG_CONFIG_PATH=\"${PKG_CONFIG_PATH}:%{_libdir}/pkgconfig:%{_datadir}/pkgconfig\"\
export PKG_CONFIG_PATH\
+ CONFIG_SITE=${CONFIG_SITE:-NONE}\
+ export CONFIG_SITE\
\
%{verbose:set -x}%{!verbose:exec > /dev/null}\
umask 022\

@ -0,0 +1,18 @@
diff --git a/rpm2cpio.c b/rpm2cpio.c
index 89ebdfa..ae999ff 100644
--- a/rpm2cpio.c
+++ b/rpm2cpio.c
@@ -84,7 +84,12 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- rc = (ufdCopy(gzdi, fdo) == payload_size) ? EXIT_SUCCESS : EXIT_FAILURE;
+ /*
+ * XXX HACK for #1142949: should be equality test, but archive size
+ * short by cpio trailer size in packages built with rpm 4.12.0
+ * and its pre-releases.
+ */
+ rc = (ufdCopy(gzdi, fdo) >= payload_size) ? EXIT_SUCCESS : EXIT_FAILURE;
Fclose(fdo);

@ -0,0 +1,95 @@
diff --git a/lib/tagexts.c b/lib/tagexts.c
index f72ff60..2c0b179 100644
--- a/lib/tagexts.c
+++ b/lib/tagexts.c
@@ -535,15 +535,6 @@ static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags);
}
-/* I18N look aside diversions */
-
-#if defined(ENABLE_NLS)
-extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
-#endif
-static const char * const language = "LANGUAGE";
-
-static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
-
/**
* Retrieve i18n text.
* @param h header
@@ -554,59 +545,30 @@ static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
*/
static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
{
- int rc;
+ int rc = headerGet(h, tag, td, HEADERGET_ALLOC);
#if defined(ENABLE_NLS)
- char * dstring = rpmExpand(_macro_i18ndomains, NULL);
-
- td->type = RPM_STRING_TYPE;
- td->data = NULL;
- td->count = 0;
-
- if (dstring && *dstring) {
- char *domain, *de;
- const char * langval;
- char * msgkey;
- const char * msgid;
+ if (rc) {
+ static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
+ char *de, *dstring = rpmExpand(_macro_i18ndomains, NULL);
+ const char *domain;
- rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME),
- rpmTagGetName(tag));
-
- /* change to en_US for msgkey -> msgid resolution */
- langval = getenv(language);
- (void) setenv(language, "en_US", 1);
- ++_nl_msg_cat_cntr;
-
- msgid = NULL;
for (domain = dstring; domain != NULL; domain = de) {
+ const char *msgid = td->data;
+ const char *msg = NULL;
+
de = strchr(domain, ':');
if (de) *de++ = '\0';
- msgid = dgettext(domain, msgkey);
- if (msgid != msgkey) break;
- }
-
- /* restore previous environment for msgid -> msgstr resolution */
- if (langval)
- (void) setenv(language, langval, 1);
- else
- unsetenv(language);
- ++_nl_msg_cat_cntr;
-
- if (domain && msgid) {
- td->data = dgettext(domain, msgid);
- td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
- td->count = 1;
- td->flags = RPMTD_ALLOCED;
+ msg = dgettext(domain, td->data);
+ if (msg != msgid) {
+ free(td->data);
+ td->data = xstrdup(msg);
+ break;
+ }
}
- dstring = _free(dstring);
- free(msgkey);
- if (td->data)
- return 1;
+ free(dstring);
}
-
- free(dstring);
#endif
- rc = headerGet(h, tag, td, HEADERGET_ALLOC);
return rc;
}

@ -0,0 +1,16 @@
diff -up rpm-4.9.1.1/macros.in.jx rpm-4.9.1.1/macros.in
--- rpm-4.9.1.1/macros.in.jx 2011-08-03 16:19:05.000000000 -0400
+++ rpm-4.9.1.1/macros.in 2011-08-08 09:41:52.981064316 -0400
@@ -674,10 +674,11 @@ print (t)\
RPM_SOURCE_DIR=\"%{u2p:%{_sourcedir}}\"\
RPM_BUILD_DIR=\"%{u2p:%{_builddir}}\"\
RPM_OPT_FLAGS=\"%{optflags}\"\
+ RPM_LD_FLAGS=\"%{?__global_ldflags}\"\
RPM_ARCH=\"%{_arch}\"\
RPM_OS=\"%{_os}\"\
RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\
- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\
+ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_LD_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\
RPM_DOC_DIR=\"%{_docdir}\"\
export RPM_DOC_DIR\
RPM_PACKAGE_NAME=\"%{NAME}\"\

@ -0,0 +1,28 @@
From bf636421120aa2c97f9e0fdcee3c211b4241bd86 Mon Sep 17 00:00:00 2001
From: Tomas Orsava <torsava@redhat.com>
Date: Mon, 29 Jan 2018 16:13:18 +0100
Subject: [PATCH] Add envvar that will be present during RPM build
Part of a Fedora Change for F28:
"Avoid /usr/bin/python in RPM build"
https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build
---
macros.in | 2 ++
1 file changed, 2 insertions(+)
diff --git a/macros.in b/macros.in
index dd6ef67..68449e3 100644
--- a/macros.in
+++ b/macros.in
@@ -804,6 +804,8 @@ package or when debugging this package.\
export PKG_CONFIG_PATH\
CONFIG_SITE=${CONFIG_SITE:-NONE}\
export CONFIG_SITE\
+ PYTHON_DISALLOW_AMBIGUOUS_VERSION=warn\
+ export PYTHON_DISALLOW_AMBIGUOUS_VERSION\
\
%{verbose:set -x}%{!verbose:exec > /dev/null}\
umask 022\
--
2.13.6

@ -0,0 +1,107 @@
From 8390fa8515f499994646cf3bd113423744dc7bd9 Mon Sep 17 00:00:00 2001
From: Florian Festi <ffesti@redhat.com>
Date: Fri, 30 Nov 2018 11:02:52 +0100
Subject: [PATCH] Add RPMTAG_MODULARITYLABEL to distinguish packages build for
modularity
Tag can be set with a ModularityLabel: statement in the spec file preamble or
via the modularitylabel macro
---
build/parsePreamble.c | 4 ++++
build/parseSpec.c | 1 +
lib/rpmtag.h | 1 +
macros.in | 5 +++++
tests/rpmgeneral.at | 1 +
5 files changed, 12 insertions(+)
diff --git a/build/parsePreamble.c b/build/parsePreamble.c
index f5e06bac8..e340e5c7a 100644
--- a/build/parsePreamble.c
+++ b/build/parsePreamble.c
@@ -43,6 +43,7 @@ static const rpmTagVal copyTagsDuringParse[] = {
RPMTAG_DISTTAG,
RPMTAG_BUGURL,
RPMTAG_GROUP,
+ RPMTAG_MODULARITYLABEL,
0
};
@@ -526,6 +527,7 @@ static struct optionalTag {
{ RPMTAG_DISTURL, "%{disturl}" },
{ RPMTAG_DISTTAG, "%{disttag}" },
{ RPMTAG_BUGURL, "%{bugurl}" },
+ { RPMTAG_MODULARITYLABEL, "%{modularitylabel}"},
{ -1, NULL }
};
@@ -779,6 +781,7 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
case RPMTAG_URL:
case RPMTAG_DISTTAG:
case RPMTAG_BUGURL:
+ case RPMTAG_MODULARITYLABEL:
/* XXX TODO: validate format somehow */
case RPMTAG_VCS:
SINGLE_TOKEN_ONLY;
@@ -1018,6 +1021,7 @@ static struct PreambleRec_s const preambleList[] = {
{RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")},
{RPMTAG_ORDERNAME, 2, 0, LEN_AND_STR("orderwithrequires")},
{RPMTAG_REMOVEPATHPOSTFIXES,0, 0, LEN_AND_STR("removepathpostfixes")},
+ {RPMTAG_MODULARITYLABEL, 0, 0, LEN_AND_STR("modularitylabel")},
{0, 0, 0, 0}
};
diff --git a/build/parseSpec.c b/build/parseSpec.c
index bf4789942..c80802baf 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -517,6 +517,7 @@ static const rpmTagVal sourceTags[] = {
RPMTAG_BUGURL,
RPMTAG_HEADERI18NTABLE,
RPMTAG_VCS,
+ RPMTAG_MODULARITYLABEL,
0
};
diff --git a/lib/rpmtag.h b/lib/rpmtag.h
index 973a6b69d..b9623ef24 100644
--- a/lib/rpmtag.h
+++ b/lib/rpmtag.h
@@ -368,6 +368,7 @@
RPMTAG_FILESIGNATURELENGTH = 5091, /* i */
RPMTAG_PAYLOADDIGEST = 5092, /* s[] */
RPMTAG_PAYLOADDIGESTALGO = 5093, /* i */
+ RPMTAG_MODULARITYLABEL = 5096, /* s */
RPMTAG_FIRSTFREE_TAG /*!< internal */
} rpmTag;
diff --git a/macros.in b/macros.in
index e0a1aea4e..cb4929c10 100644
--- a/macros.in
+++ b/macros.in
@@ -357,6 +357,11 @@ package or when debugging this package.\
%_javadir %{_datadir}/java
%_javadocdir %{_datadir}/javadoc
+
+# Set ModularityLabel: for packages being build
+#
+#%modularitylabel
+
# A colon separated list of paths where files should *not* be installed.
# Usually, these are network file system mount points.
#
diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at
index 509277f2c..45d38698b 100644
--- a/tests/rpmgeneral.at
+++ b/tests/rpmgeneral.at
@@ -150,6 +150,7 @@ LONGARCHIVESIZE
LONGFILESIZES
LONGSIGSIZE
LONGSIZE
+MODULARITYLABEL
N
NAME
NEVR
--
2.17.2

@ -0,0 +1,275 @@
From 820dcc1db9f2130a21fdaf721217034376eb8e38 Mon Sep 17 00:00:00 2001
Message-Id: <820dcc1db9f2130a21fdaf721217034376eb8e38.1544785848.git.pmatilai@redhat.com>
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 30 Nov 2018 13:10:44 +0200
Subject: [PATCH] Add support for logging audit events for package installs as
per OSPP v4.2
If enabled at build-time, log audit events for package install, update
and remove. The log includes the operation, package nevra, signature
check result, whether signatures are being enforced enforced and overall
success result. Package install/update/remove are logged as such,
obsoletion is logged as install + remove (whereas the erasure element
on updates is silent)
Loosely based on initial RHEL 7-8 implementations by Pavlina Moravcova
Varekova and Florian Festi (RhBug:1555326, RhBug:1607612)
(cherry picked from commit cfc9dde70fe65e91c83e03e9a9441e627b741489)
---
configure.ac | 21 +++++++++
lib/Makefile.am | 1 +
lib/rpmte.c | 11 +++++
lib/rpmte_internal.h | 6 +++
lib/transaction.c | 104 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 143 insertions(+)
diff --git a/configure.ac b/configure.ac
index 34ea85f9f..ab8a368d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -312,6 +312,27 @@ fi
AC_SUBST(WITH_BEECRYPT_LIB)
AC_SUBST(WITH_BEECRYPT_INCLUDE)
+
+#=================
+# Check for audit library.
+AC_ARG_WITH(audit,
+AS_HELP_STRING([--with-audit],[log results using Linux Audit]),
+with_audit=$withval,
+with_audit=auto)
+
+WITH_AUDIT_LIB=
+AS_IF([test "x$with_audit" != xno],[
+ AC_SEARCH_LIBS([audit_open],[audit],[
+ WITH_AUDIT_LIB="$ac_res"
+ AC_DEFINE(WITH_AUDIT, 1, [libaudit support])
+ ],
+ [if test "x$with_audit" != xauto; then
+ AC_MSG_ERROR([missing audit library])
+ fi
+ ])
+])
+AC_SUBST(WITH_AUDIT_LIB)
+
#=================
# Check for OpenSSL library.
# We need evp.h from OpenSSL.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index baf3238ee..c055962a3 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -51,6 +51,7 @@ librpm_la_LIBADD = \
@WITH_POPT_LIB@ \
@WITH_CAP_LIB@ \
@WITH_ACL_LIB@ \
+ @WITH_AUDIT_LIB@ \
@LIBINTL@
if WITH_LUA
diff --git a/lib/rpmte.c b/lib/rpmte.c
index d980a37a4..bd5d53edc 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -69,6 +69,7 @@ struct rpmte_s {
int nrelocs; /*!< (TR_ADDED) No. of relocations. */
uint8_t *badrelocs; /*!< (TR_ADDED) Bad relocations (or NULL) */
FD_t fd; /*!< (TR_ADDED) Payload file descriptor. */
+ int verified; /*!< (TR_ADDED) Verification status */
#define RPMTE_HAVE_PRETRANS (1 << 0)
#define RPMTE_HAVE_POSTTRANS (1 << 1)
@@ -753,6 +754,16 @@ rpmfs rpmteGetFileStates(rpmte te)
return te->fs;
}
+void rpmteSetVerified(rpmte te, int verified)
+{
+ te->verified = verified;
+}
+
+int rpmteGetVerified(rpmte te)
+{
+ return te->verified;
+}
+
int rpmteProcess(rpmte te, pkgGoal goal, int num)
{
/* Only install/erase resets pkg file info */
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
index a5a991ec5..2895925ce 100644
--- a/lib/rpmte_internal.h
+++ b/lib/rpmte_internal.h
@@ -86,6 +86,12 @@ int rpmteHaveTransScript(rpmte te, rpmTagVal tag);
/* XXX should be internal too but build code needs for now... */
rpmfs rpmteGetFileStates(rpmte te);
+RPM_GNUC_INTERNAL
+void rpmteSetVerified(rpmte te, int verified);
+
+RPM_GNUC_INTERNAL
+int rpmteGetVerified(rpmte te);
+
/** \ingroup rpmte
* Retrieve size in bytes of package header.
* @param te transaction element
diff --git a/lib/transaction.c b/lib/transaction.c
index 67b9db579..866e87fc2 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -7,6 +7,10 @@
#include <inttypes.h>
#include <libgen.h>
+#if WITH_AUDIT
+#include <libaudit.h>
+#endif
+
#include <rpm/rpmlib.h> /* rpmMachineScore, rpmReadPackageFile */
#include <rpm/rpmmacro.h> /* XXX for rpmExpand */
#include <rpm/rpmlog.h>
@@ -1195,12 +1199,17 @@ static rpm_loff_t countPkgs(rpmts ts, rpmElementTypes types)
struct vfydata_s {
char *msg;
+ int signature;
int vfylevel;
};
static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata)
{
struct vfydata_s *vd = cbdata;
+
+ if (sinfo->type == RPMSIG_SIGNATURE_TYPE && sinfo->rc == RPMRC_OK)
+ vd->signature = RPMRC_OK;
+
switch (sinfo->rc) {
case RPMRC_OK:
break;
@@ -1241,6 +1250,7 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)
struct rpmvs_s *vs = rpmvsCreate(vfylevel, vsflags, keyring);
struct vfydata_s vd = {
.msg = NULL,
+ .signature = RPMRC_NOTFOUND,
.vfylevel = vfylevel,
};
rpmRC prc = RPMRC_FAIL;
@@ -1255,6 +1265,9 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)
if (prc == RPMRC_OK)
prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
+ /* Record verify result, signatures only for now */
+ rpmteSetVerified(p, vd.signature == RPMRC_OK);
+
if (prc)
rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0);
@@ -1619,6 +1632,95 @@ rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes,
return rc;
}
+#if WITH_AUDIT
+struct teop {
+ rpmte te;
+ const char *op;
+};
+
+/*
+ * Figure out the actual operations:
+ * Install and remove are straightforward. Updates need to discovered
+ * via their erasure element: locate the updating element, adjust it's
+ * op to update and silence the erasure part. Obsoletion is handled as
+ * as install + remove, which it technically is.
+ */
+static void getAuditOps(rpmts ts, struct teop *ops, int nelem)
+{
+ rpmtsi pi = rpmtsiInit(ts);
+ rpmte p;
+ int i = 0;
+ while ((p = rpmtsiNext(pi, 0)) != NULL) {
+ const char *op = NULL;
+ if (rpmteType(p) == TR_ADDED) {
+ op = "install";
+ } else {
+ op = "remove";
+ rpmte d = rpmteDependsOn(p);
+ /* Fixup op on updating elements, silence the cleanup stage */
+ if (d != NULL && rstreq(rpmteN(d), rpmteN(p))) {
+ /* Linear lookup, but we're only dealing with a few thousand */
+ for (int x = 0; x < i; x++) {
+ if (ops[x].te == d) {
+ ops[x].op = "update";
+ op = NULL;
+ break;
+ }
+ }
+ }
+ }
+ ops[i].te = p;
+ ops[i].op = op;
+ i++;
+ }
+ rpmtsiFree(pi);
+}
+
+/*
+ * If enabled, log audit events for the operations in this transaction.
+ * In the event values, 1 means true/success and 0 false/failure. Shockingly.
+ */
+static void rpmtsAudit(rpmts ts)
+{
+ int auditFd = audit_open();
+ if (auditFd < 0)
+ return;
+
+ int nelem = rpmtsNElements(ts);
+ struct teop *ops = xcalloc(nelem, sizeof(*ops));
+ char *dir = audit_encode_nv_string("root_dir", rpmtsRootDir(ts), 0);
+ int enforce = (rpmtsVfyLevel(ts) & RPMSIG_SIGNATURE_TYPE) != 0;
+
+ getAuditOps(ts, ops, nelem);
+
+ for (int i = 0; i < nelem; i++) {
+ const char *op = ops[i].op;
+ if (op) {
+ rpmte p = ops[i].te;
+ char *nevra = audit_encode_nv_string("sw", rpmteNEVRA(p), 0);
+ char eventTxt[256];
+ int verified = rpmteGetVerified(p);
+ int result = (rpmteFailed(p) == 0);
+
+ snprintf(eventTxt, sizeof(eventTxt),
+ "op=%s %s sw_type=rpm key_enforce=%u gpg_res=%u %s",
+ op, nevra, enforce, verified, dir);
+ audit_log_user_comm_message(auditFd, AUDIT_SOFTWARE_UPDATE,
+ eventTxt, NULL, NULL, NULL, NULL, result);
+ free(nevra);
+ }
+ }
+
+ free(dir);
+ free(ops);
+ audit_close(auditFd);
+}
+#else
+static void rpmtsAudit(rpmts ts)
+{
+}
+#endif
+
int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
{
int rc = -1; /* assume failure */
@@ -1732,6 +1834,8 @@ exit:
rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc);
/* Finish up... */
+ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)))
+ rpmtsAudit(ts);
(void) umask(oldmask);
(void) rpmtsFinish(ts);
rpmpsFree(tsprobs);
--
2.19.2

@ -0,0 +1,12 @@
diff -up rpm-4.14.2/macros.in.pyerror rpm-4.14.2/macros.in
--- rpm-4.14.2/macros.in.pyerror 2019-06-04 13:33:48.450727270 +0300
+++ rpm-4.14.2/macros.in 2019-06-04 13:34:09.717695822 +0300
@@ -50,7 +50,7 @@
%__mv @__MV@
%__patch @__PATCH@
%__perl @__PERL@
-%__python @__PYTHON@
+%__python %{error:attempt to use unversioned python, define %%__python to %{_bindir}/python2 or %{_bindir}/python3 explicitly}
%__restorecon @__RESTORECON@
%__rm @__RM@
%__rsh @__RSH@

@ -0,0 +1,14 @@
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-02-09 14:43:35.393940550 +0100
+++ rpm-4.14.3/scripts/brp-strip 2021-02-09 14:43:49.459222054 +0100
@@ -12,9 +12,8 @@ Darwin*) exit 0 ;;
esac
# Strip ELF binaries
-for f in `find "$RPM_BUILD_ROOT" -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -exec file {} \; | \
+for f in `find "$RPM_BUILD_ROOT" -type f -exec file {} \; | \
grep -v "^${RPM_BUILD_ROOT}/\?usr/lib/debug" | \
- grep -v ' shared object,' | \
sed -n -e 's/^\(.*\):[ ]*ELF.*, not stripped.*/\1/p'`; do
$STRIP -g "$f" || :
done

@ -0,0 +1,186 @@
diff -up rpm-4.14.3/sign/rpmgensig.c.orig rpm-4.14.3/sign/rpmgensig.c
--- rpm-4.14.3/sign/rpmgensig.c.orig 2020-06-26 15:57:43.781333983 +0200
+++ rpm-4.14.3/sign/rpmgensig.c 2020-06-26 15:58:29.819229616 +0200
@@ -8,7 +8,6 @@
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
-#include <libgen.h>
#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
#include <rpm/rpmmacro.h>
@@ -33,68 +32,6 @@ typedef struct sigTarget_s {
rpm_loff_t size;
} *sigTarget;
-/*
- * There is no function for creating unique temporary fifos so create
- * unique temporary directory and then create fifo in it.
- */
-static char *mkTempFifo(void)
-{
- char *tmppath = NULL, *tmpdir = NULL, *fifofn = NULL;
- mode_t mode;
-
- tmppath = rpmExpand("%{_tmppath}", NULL);
- if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1))
- goto exit;
-
-
- tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL);
- mode = umask(0077);
- tmpdir = mkdtemp(tmpdir);
- umask(mode);
- if (tmpdir == NULL) {
- rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n"),
- tmpdir);
- tmpdir = _free(tmpdir);
- goto exit;
- }
-
- fifofn = rpmGetPath(tmpdir, "/fifo", NULL);
- if (mkfifo(fifofn, 0600) == -1) {
- rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n"), fifofn);
- fifofn = _free(fifofn);
- }
-
-exit:
- if (fifofn == NULL && tmpdir != NULL)
- unlink(tmpdir);
-
- free(tmppath);
- free(tmpdir);
-
- return fifofn;
-}
-
-/* Delete fifo and then temporary directory in which it was located */
-static int rpmRmTempFifo(const char *fn)
-{
- int rc = 0;
- char *dfn = NULL, *dir = NULL;
-
- if ((rc = unlink(fn)) != 0) {
- rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n"), fn);
- return rc;
- }
-
- dfn = xstrdup(fn);
- dir = dirname(dfn);
-
- if ((rc = rmdir(dir)) != 0)
- rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n"), dir);
- free(dfn);
-
- return rc;
-}
-
static int closeFile(FD_t *fdp)
{
if (fdp == NULL || *fdp == NULL)
@@ -241,27 +178,38 @@ exit:
static int runGPG(sigTarget sigt, const char *sigfile)
{
int pid = 0, status;
- FD_t fnamedPipe = NULL;
- char *namedPipeName = NULL;
+ int pipefd[2];
+ FILE *fpipe = NULL;
unsigned char buf[BUFSIZ];
ssize_t count;
ssize_t wantCount;
rpm_loff_t size;
int rc = 1; /* assume failure */
- namedPipeName = mkTempFifo();
+ if (pipe(pipefd) < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not create pipe for signing: %m\n"));
+ goto exit;
+ }
- rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1);
+ rpmPushMacro(NULL, "__plaintext_filename", NULL, "-", -1);
rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1);
if (!(pid = fork())) {
char *const *av;
char *cmd = NULL;
- const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
+ const char *tty = ttyname(STDIN_FILENO);
+ const char *gpg_path = NULL;
+
+ if (!getenv("GPG_TTY") && (!tty || setenv("GPG_TTY", tty, 0)))
+ rpmlog(RPMLOG_WARNING, _("Could not set GPG_TTY to stdin: %m\n"));
+ gpg_path = rpmExpand("%{?_gpg_path}", NULL);
if (gpg_path && *gpg_path != '\0')
(void) setenv("GNUPGHOME", gpg_path, 1);
+ dup2(pipefd[0], STDIN_FILENO);
+ close(pipefd[1]);
+
unsetenv("MALLOC_CHECK_");
cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
@@ -276,9 +224,10 @@ static int runGPG(sigTarget sigt, const
rpmPopMacro(NULL, "__plaintext_filename");
rpmPopMacro(NULL, "__signature_filename");
- fnamedPipe = Fopen(namedPipeName, "w");
- if (!fnamedPipe) {
- rpmlog(RPMLOG_ERR, _("Fopen failed\n"));
+ close(pipefd[0]);
+ fpipe = fdopen(pipefd[1], "w");
+ if (!fpipe) {
+ rpmlog(RPMLOG_ERR, _("Could not open pipe for writing: %m\n"));
goto exit;
}
@@ -291,8 +240,8 @@ static int runGPG(sigTarget sigt, const
size = sigt->size;
wantCount = size < sizeof(buf) ? size : sizeof(buf);
while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) {
- Fwrite(buf, sizeof(buf[0]), count, fnamedPipe);
- if (Ferror(fnamedPipe)) {
+ fwrite(buf, sizeof(buf[0]), count, fpipe);
+ if (ferror(fpipe)) {
rpmlog(RPMLOG_ERR, _("Could not write to pipe\n"));
goto exit;
}
@@ -304,8 +253,13 @@ static int runGPG(sigTarget sigt, const
sigt->fileName, Fstrerror(sigt->fd));
goto exit;
}
- Fclose(fnamedPipe);
- fnamedPipe = NULL;
+
+exit:
+
+ if (fpipe)
+ fclose(fpipe);
+ if (pipefd[1])
+ close(pipefd[1]);
(void) waitpid(pid, &status, 0);
pid = 0;
@@ -314,20 +268,6 @@ static int runGPG(sigTarget sigt, const
} else {
rc = 0;
}
-
-exit:
-
- if (fnamedPipe)
- Fclose(fnamedPipe);
-
- if (pid)
- waitpid(pid, &status, 0);
-
- if (namedPipeName) {
- rpmRmTempFifo(namedPipeName);
- free(namedPipeName);
- }
-
return rc;
}

@ -0,0 +1,378 @@
From c33faabc2d09b9ad8c80b941b6114c1e4c2be80f Mon Sep 17 00:00:00 2001
Message-Id: <c33faabc2d09b9ad8c80b941b6114c1e4c2be80f.1612252390.git.pmatilai@redhat.com>
From: Radovan Sroka <rsroka@redhat.com>
Date: Tue, 27 Oct 2020 16:18:04 +0100
Subject: [PATCH] Added fapolicyd rpm plugin
Fapolicyd (File Access Policy Daemon) implements application whitelisting
to decide file access rights. Applications that are known via a reputation
source are allowed access while unknown applications are not.
The rpm plugin allows us to use rpm database as a source of trust.
We used dnf plugin since the beggining but it only provides notification
when transaction ends. With "integrity checking" requirement we need
a continual addition of files which are installed during the system
update. With fapolicyd rpm plugin we can allow using of recently
added/updated files in scriptlets during rpm transaction.
The fapolicyd plugin gathers metadata of currently installed files.
It sends the information about files and about ongoing rpm transaction
to the fapolicyd daemon. The information is written to Linux pipe which
is placed in /var/run/fapolicyd/fapolicyd.fifo.
The data format is "%s %lu %64s\n". [path, size, sha256]
The fapolicyd rpm plugin can be enabled with "--with-fapolicyd"
configure option.
Related PRs:
https://github.com/linux-application-whitelisting/fapolicyd/pull/105
https://github.com/linux-application-whitelisting/fapolicyd/pull/106
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
(cherry picked from commit 39595ccee321497dc3b08c7cab8a10304345429c)
Backported from commit 39595ccee321497dc3b08c7cab8a10304345429c
---
Makefile.am | 1 +
configure.ac | 8 ++
doc/Makefile.am | 2 +-
doc/rpm-plugin-fapolicyd.8 | 21 +++++
macros.in | 1 +
plugins/Makefile.am | 6 ++
plugins/fapolicyd.c | 189 +++++++++++++++++++++++++++++++++++++
7 files changed, 227 insertions(+), 1 deletion(-)
create mode 100644 doc/rpm-plugin-fapolicyd.8
create mode 100644 plugins/fapolicyd.c
diff --git a/Makefile.am b/Makefile.am
index 1f20f05b7..8e92f0cde 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
--with-selinux \
--with-imaevm \
--with-crypto=openssl \
+ --with-fapolicyd \
--disable-dependency-tracking
include $(top_srcdir)/rpm.am
diff --git a/configure.ac b/configure.ac
index 3fcb3ff20..3d0e9ef91 100644
--- a/configure.ac
+++ b/configure.ac
@@ -983,6 +983,14 @@ AS_IF([test "$enable_inhibit_plugin" = yes],[
])
AM_CONDITIONAL(ENABLE_INHIBIT_PLUGIN,[test "$enable_inhibit_plugin" = yes])
+#=================
+# Check for fapolicyd support
+AC_ARG_WITH(fapolicyd,
+AS_HELP_STRING([--with-fapolicyd],[build with File Access Policy Daemon support]),
+with_fapolicyd=$withval,
+with_fapolicyd=auto)
+AM_CONDITIONAL(FAPOLICYD,[test "$with_fapolicyd" = yes])
+
with_dbus=no
AS_IF([test "$enable_plugins" != no],[
AS_IF([test "$enable_inhibit_plugin" != no],[
diff --git a/doc/Makefile.am b/doc/Makefile.am
index d2f520d64..535ad3ec3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -9,7 +9,7 @@ EXTRA_DIST += $(man_man1_DATA)
man_man8dir = $(mandir)/man8
man_man8_DATA = rpm.8 rpm-misc.8 rpmbuild.8 rpmdeps.8 rpmgraph.8 rpm2cpio.8
man_man8_DATA += rpmdb.8 rpmkeys.8 rpmsign.8 rpmspec.8
-man_man8_DATA += rpm-plugin-systemd-inhibit.8
+man_man8_DATA += rpm-plugin-systemd-inhibit.8 rpm-plugin-fapolicyd.8
EXTRA_DIST += $(man_man8_DATA)
man_fr_man8dir = $(mandir)/fr/man8
diff --git a/doc/rpm-plugin-fapolicyd.8 b/doc/rpm-plugin-fapolicyd.8
new file mode 100644
index 000000000..fe7a8c78e
--- /dev/null
+++ b/doc/rpm-plugin-fapolicyd.8
@@ -0,0 +1,21 @@
+'\" t
+.TH "RPM-FAPOLICYD" "8" "28 Jan 2021" "Red Hat, Inc."
+.SH NAME
+rpm-plugin-fapolicyd \- Fapolicyd plugin for the RPM Package Manager
+
+.SH Description
+
+The plugin gathers metadata of currently installed files. It sends the
+information about files and about ongoing rpm transaction to the fapolicyd daemon.
+The information is written to Linux pipe which is placed in
+/var/run/fapolicyd/fapolicyd.fifo.
+
+.SH Configuration
+
+There are currently no options for this plugin in particular. See
+.BR rpm-plugins (8)
+on how to control plugins in general.
+
+.SH SEE ALSO
+.IR fapolicyd (8)
+.IR rpm-plugins (8)
diff --git a/macros.in b/macros.in
index a6069ee4d..2fbda64cc 100644
--- a/macros.in
+++ b/macros.in
@@ -1173,6 +1173,7 @@ package or when debugging this package.\
%__transaction_selinux %{__plugindir}/selinux.so
%__transaction_syslog %{__plugindir}/syslog.so
%__transaction_ima %{__plugindir}/ima.so
+%__transaction_fapolicyd %{__plugindir}/fapolicyd.so
%__transaction_prioreset %{__plugindir}/prioreset.so
#------------------------------------------------------------------------------
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index ab4eee34f..cbfb81e19 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -42,3 +42,9 @@ ima_la_sources = ima.c
ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
plugins_LTLIBRARIES += ima.la
endif
+
+if FAPOLICYD
+fapolicyd_la_sources = fapolicyd.c
+fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
+plugins_LTLIBRARIES += fapolicyd.la
+endif
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
new file mode 100644
index 000000000..50f50155c
--- /dev/null
+++ b/plugins/fapolicyd.c
@@ -0,0 +1,189 @@
+#include "system.h"
+
+#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include "lib/rpmplugin.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+struct fapolicyd_data {
+ int fd;
+ long changed_files;
+ const char * fifo_path;
+};
+
+static struct fapolicyd_data fapolicyd_state = {
+ .fd = -1,
+ .changed_files = 0,
+ .fifo_path = "/run/fapolicyd/fapolicyd.fifo",
+};
+
+static rpmRC open_fifo(struct fapolicyd_data* state)
+{
+ int fd = -1;
+ struct stat s;
+
+ fd = open(state->fifo_path, O_RDWR);
+ if (fd == -1) {
+ rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
+ goto bad;
+ }
+
+ if (stat(state->fifo_path, &s) == -1) {
+ rpmlog(RPMLOG_DEBUG, "Stat: %s -> %s\n", state->fifo_path, strerror(errno));
+ goto bad;
+ }
+
+ if (!S_ISFIFO(s.st_mode)) {
+ rpmlog(RPMLOG_DEBUG, "File: %s exists but it is not a pipe!\n", state->fifo_path);
+ goto bad;
+ }
+
+ /* keep only file's permition bits */
+ mode_t mode = s.st_mode & ~S_IFMT;
+
+ /* we require pipe to have 0660 permission */
+ if (mode != 0660) {
+ rpmlog(RPMLOG_ERR, "File: %s has %o instead of 0660 \n",
+ state->fifo_path,
+ mode );
+ goto bad;
+ }
+
+ state->fd = fd;
+ /* considering success */
+ return RPMRC_OK;
+
+ bad:
+ if (fd > 0)
+ close(fd);
+ return RPMRC_FAIL;
+}
+
+static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
+{
+ ssize_t len = strlen(str);
+ ssize_t written = 0;
+ ssize_t n = 0;
+
+ while (written < len) {
+ if ((n = write(state->fd, str + written, len - written)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ rpmlog(RPMLOG_DEBUG, "Write: %s -> %s\n", state->fifo_path, strerror(errno));
+ goto bad;
+ }
+ written += n;
+ }
+
+ return RPMRC_OK;
+
+ bad:
+ return RPMRC_FAIL;
+}
+
+static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
+{
+ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
+ goto end;
+
+ if (!rstreq(rpmtsRootDir(ts), "/"))
+ goto end;
+
+ (void) open_fifo(&fapolicyd_state);
+
+ end:
+ return RPMRC_OK;
+}
+
+static void fapolicyd_cleanup(rpmPlugin plugin)
+{
+ if (fapolicyd_state.fd > 0)
+ (void) close(fapolicyd_state.fd);
+
+ fapolicyd_state.fd = -1;
+}
+
+static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
+{
+ if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
+ goto end;
+
+ /* we are ready */
+ if (fapolicyd_state.fd > 0) {
+ /* send a signal that transaction is over */
+ (void) write_fifo(&fapolicyd_state, "1\n");
+ /* flush cache */
+ (void) write_fifo(&fapolicyd_state, "2\n");
+ }
+
+ end:
+ return RPMRC_OK;
+}
+
+static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
+ int type)
+{
+ if (fapolicyd_state.fd == -1)
+ goto end;
+
+ if (fapolicyd_state.changed_files > 0) {
+ /* send signal to flush cache */
+ (void) write_fifo(&fapolicyd_state, "2\n");
+
+ /* optimize flushing */
+ /* flush only when there was an actual change */
+ fapolicyd_state.changed_files = 0;
+ }
+
+ end:
+ return RPMRC_OK;
+}
+
+static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+ const char *path, const char *dest,
+ mode_t file_mode, rpmFsmOp op)
+{
+ /* not ready */
+ if (fapolicyd_state.fd == -1)
+ goto end;
+
+ rpmFileAction action = XFO_ACTION(op);
+
+ /* Ignore skipped files and unowned directories */
+ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
+ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping early: path %s dest %s\n",
+ path, dest);
+ goto end;
+ }
+
+ if (!S_ISREG(rpmfiFMode(fi))) {
+ rpmlog(RPMLOG_DEBUG, "fapolicyd skipping non regular: path %s dest %s\n",
+ path, dest);
+ goto end;
+ }
+
+ fapolicyd_state.changed_files++;
+
+ char buffer[4096];
+
+ rpm_loff_t size = rpmfiFSize(fi);
+ char * sha = rpmfiFDigestHex(fi, NULL);
+
+ snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
+ (void) write_fifo(&fapolicyd_state, buffer);
+
+ end:
+ return RPMRC_OK;
+}
+
+struct rpmPluginHooks_s fapolicyd_hooks = {
+ .init = fapolicyd_init,
+ .cleanup = fapolicyd_cleanup,
+ .scriptlet_pre = fapolicyd_scriptlet_pre,
+ .tsm_post = fapolicyd_tsm_post,
+ .fsm_file_prepare = fapolicyd_fsm_file_prepare,
+};
--
2.29.2
commit c66cee32e74ce1e507c031605e3d7b2c1391a52c
Author: Radovan Sroka <rsroka@redhat.com>
Date: Wed Feb 10 17:04:55 2021 +0100
Fixed issues find by coverity
- enhance the check for the file descriptor fd because 0 is also a valid
descriptor
- added free() for sha so it doesn't leak memory for every file that is
processed
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
index 50f50155c..48f65ae11 100644
--- a/plugins/fapolicyd.c
+++ b/plugins/fapolicyd.c
@@ -58,7 +58,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
return RPMRC_OK;
bad:
- if (fd > 0)
+ if (fd >= 0)
close(fd);
return RPMRC_FAIL;
}
@@ -176,6 +176,8 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
(void) write_fifo(&fapolicyd_state, buffer);
+ free(sha);
+
end:
return RPMRC_OK;
}

@ -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

@ -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

@ -0,0 +1,12 @@
diff -up rpm-4.14.3/lib/header.c.orig rpm-4.14.3/lib/header.c
--- rpm-4.14.3/lib/header.c.orig 2020-04-28 14:50:11.816399041 +0200
+++ rpm-4.14.3/lib/header.c 2021-02-03 16:47:23.567245743 +0100
@@ -1910,7 +1910,7 @@ rpmRC hdrblobRead(FD_t fd, int magic, in
if (regionTag == RPMTAG_HEADERSIGNATURES) {
il_max = 32;
- dl_max = 8192;
+ dl_max = 64 * 1024 * 1024;
}
memset(block, 0, sizeof(block));

@ -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

@ -0,0 +1,101 @@
diff -up rpm-4.14.3/lib/rpmscript.c.orig rpm-4.14.3/lib/rpmscript.c
--- rpm-4.14.3/lib/rpmscript.c.orig 2021-02-08 14:07:44.527197946 +0100
+++ rpm-4.14.3/lib/rpmscript.c 2021-02-08 14:09:05.732749080 +0100
@@ -46,27 +46,27 @@ struct scriptInfo_s {
};
static const struct scriptInfo_s scriptInfo[] = {
- { RPMSCRIPT_PREIN, "%prein", 0,
+ { RPMSCRIPT_PREIN, "prein", 0,
RPMTAG_PREIN, RPMTAG_PREINPROG, RPMTAG_PREINFLAGS },
- { RPMSCRIPT_PREUN, "%preun", 0,
+ { RPMSCRIPT_PREUN, "preun", 0,
RPMTAG_PREUN, RPMTAG_PREUNPROG, RPMTAG_PREUNFLAGS },
- { RPMSCRIPT_POSTIN, "%post", 0,
+ { RPMSCRIPT_POSTIN, "post", 0,
RPMTAG_POSTIN, RPMTAG_POSTINPROG, RPMTAG_POSTINFLAGS },
- { RPMSCRIPT_POSTUN, "%postun", 0,
+ { RPMSCRIPT_POSTUN, "postun", 0,
RPMTAG_POSTUN, RPMTAG_POSTUNPROG, RPMTAG_POSTUNFLAGS },
- { RPMSCRIPT_PRETRANS, "%pretrans", 0,
+ { RPMSCRIPT_PRETRANS, "pretrans", 0,
RPMTAG_PRETRANS, RPMTAG_PRETRANSPROG, RPMTAG_PRETRANSFLAGS },
- { RPMSCRIPT_POSTTRANS, "%posttrans", 0,
+ { RPMSCRIPT_POSTTRANS, "posttrans", 0,
RPMTAG_POSTTRANS, RPMTAG_POSTTRANSPROG, RPMTAG_POSTTRANSFLAGS },
- { RPMSCRIPT_TRIGGERPREIN, "%triggerprein", RPMSENSE_TRIGGERPREIN,
+ { RPMSCRIPT_TRIGGERPREIN, "triggerprein", RPMSENSE_TRIGGERPREIN,
RPMTAG_TRIGGERPREIN, 0, 0 },
- { RPMSCRIPT_TRIGGERUN, "%triggerun", RPMSENSE_TRIGGERUN,
+ { RPMSCRIPT_TRIGGERUN, "triggerun", RPMSENSE_TRIGGERUN,
RPMTAG_TRIGGERUN, 0, 0 },
- { RPMSCRIPT_TRIGGERIN, "%triggerin", RPMSENSE_TRIGGERIN,
+ { RPMSCRIPT_TRIGGERIN, "triggerin", RPMSENSE_TRIGGERIN,
RPMTAG_TRIGGERIN, 0, 0 },
- { RPMSCRIPT_TRIGGERPOSTUN, "%triggerpostun", RPMSENSE_TRIGGERPOSTUN,
+ { RPMSCRIPT_TRIGGERPOSTUN, "triggerpostun", RPMSENSE_TRIGGERPOSTUN,
RPMTAG_TRIGGERPOSTUN, 0, 0 },
- { RPMSCRIPT_VERIFY, "%verify", 0,
+ { RPMSCRIPT_VERIFY, "verify", 0,
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
{ 0, "unknown", 0,
RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND, RPMTAG_NOT_FOUND }
@@ -457,7 +457,7 @@ static const char * tag2sln(rpmTagVal ta
}
static rpmScript rpmScriptNew(Header h, rpmTagVal tag, const char *body,
- rpmscriptFlags flags)
+ rpmscriptFlags flags, const char *prefix)
{
char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
rpmScript script = xcalloc(1, sizeof(*script));
@@ -465,7 +465,7 @@ static rpmScript rpmScriptNew(Header h,
script->type = getScriptType(tag);
script->flags = flags;
script->body = (body != NULL) ? xstrdup(body) : NULL;
- rasprintf(&script->descr, "%s(%s)", tag2sln(tag), nevra);
+ rasprintf(&script->descr, "%%%s%s(%s)", prefix, tag2sln(tag), nevra);
/* macros need to be expanded before possible queryformat */
if (script->body && (script->flags & RPMSCRIPT_FLAG_EXPAND)) {
@@ -556,6 +556,7 @@ rpmScript rpmScriptFromTriggerTag(Header
rpmScript script = NULL;
struct rpmtd_s tscripts, tprogs, tflags;
headerGetFlags hgflags = HEADERGET_MINMEM;
+ const char *prefix = "";
switch (tm) {
case RPMSCRIPT_NORMALTRIGGER:
@@ -567,11 +568,13 @@ rpmScript rpmScriptFromTriggerTag(Header
headerGet(h, RPMTAG_FILETRIGGERSCRIPTS, &tscripts, hgflags);
headerGet(h, RPMTAG_FILETRIGGERSCRIPTPROG, &tprogs, hgflags);
headerGet(h, RPMTAG_FILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ prefix = "file";
break;
case RPMSCRIPT_TRANSFILETRIGGER:
headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTS, &tscripts, hgflags);
headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTPROG, &tprogs, hgflags);
headerGet(h, RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS, &tflags, hgflags);
+ prefix = "transfile";
break;
}
@@ -582,7 +585,8 @@ rpmScript rpmScriptFromTriggerTag(Header
if (rpmtdSetIndex(&tflags, ix) >= 0)
sflags = rpmtdGetNumber(&tflags);
- script = rpmScriptNew(h, triggerTag, rpmtdGetString(&tscripts), sflags);
+ script = rpmScriptNew(h, triggerTag,
+ rpmtdGetString(&tscripts), sflags, prefix);
/* hack up a hge-style NULL-terminated array */
script->args = xmalloc(2 * sizeof(*script->args) + strlen(prog) + 1);
@@ -608,7 +612,7 @@ rpmScript rpmScriptFromTag(Header h, rpm
script = rpmScriptNew(h, scriptTag,
headerGetString(h, scriptTag),
- headerGetNumber(h, getFlagTag(scriptTag)));
+ headerGetNumber(h, getFlagTag(scriptTag)), "");
if (headerGet(h, progTag, &prog, (HEADERGET_ALLOC|HEADERGET_ARGV))) {
script->args = prog.data;

@ -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

@ -0,0 +1,100 @@
commit 8f4b3c3cab8922a2022b9e47c71f1ecf906077ef
Author: Demi Marie Obenour <athena@invisiblethingslab.com>
Date: Mon Feb 8 16:05:01 2021 -0500
hdrblobInit() needs bounds checks too
Users can pass untrusted data to hdrblobInit() and it must be robust
against this.
diff --git a/lib/header.c b/lib/header.c
index ea39e679f..ebba9c2b0 100644
--- a/lib/header.c
+++ b/lib/header.c
@@ -11,6 +11,7 @@
#include "system.h"
#include <netdb.h>
#include <errno.h>
+#include <inttypes.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmstring.h>
#include "lib/header_internal.h"
@@ -1912,6 +1913,25 @@ hdrblob hdrblobFree(hdrblob blob)
return NULL;
}
+static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl,
+ char **emsg) {
+ uint32_t il_max = HEADER_TAGS_MAX;
+ uint32_t dl_max = HEADER_DATA_MAX;
+ if (regionTag == RPMTAG_HEADERSIGNATURES) {
+ il_max = 32;
+ dl_max = 64 * 1024 * 1024;
+ }
+ if (hdrchkRange(il_max, il)) {
+ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il);
+ return RPMRC_FAIL;
+ }
+ if (hdrchkRange(dl_max, dl)) {
+ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
+
rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg)
{
int32_t block[4];
@@ -1924,13 +1944,6 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl
size_t nb;
rpmRC rc = RPMRC_FAIL; /* assume failure */
int xx;
- int32_t il_max = HEADER_TAGS_MAX;
- int32_t dl_max = HEADER_DATA_MAX;
-
- if (regionTag == RPMTAG_HEADERSIGNATURES) {
- il_max = 32;
- dl_max = 64 * 1024 * 1024;
- }
memset(block, 0, sizeof(block));
if ((xx = Freadall(fd, bs, blen)) != blen) {
@@ -1943,15 +1956,9 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl
goto exit;
}
il = ntohl(block[2]);
- if (hdrchkRange(il_max, il)) {
- rasprintf(emsg, _("hdr tags: BAD, no. of tags(%d) out of range"), il);
- goto exit;
- }
dl = ntohl(block[3]);
- if (hdrchkRange(dl_max, dl)) {
- rasprintf(emsg, _("hdr data: BAD, no. of bytes(%d) out of range"), dl);
+ if (hdrblobVerifyLengths(regionTag, il, dl, emsg))
goto exit;
- }
nb = (il * sizeof(struct entryInfo_s)) + dl;
uc = sizeof(il) + sizeof(dl) + nb;
@@ -1995,11 +2002,18 @@ rpmRC hdrblobInit(const void *uh, size_t uc,
struct hdrblob_s *blob, char **emsg)
{
rpmRC rc = RPMRC_FAIL;
-
memset(blob, 0, sizeof(*blob));
+ if (uc && uc < 8) {
+ rasprintf(emsg, _("hdr length: BAD"));
+ goto exit;
+ }
+
blob->ei = (int32_t *) uh; /* discards const */
- blob->il = ntohl(blob->ei[0]);
- blob->dl = ntohl(blob->ei[1]);
+ blob->il = ntohl((uint32_t)(blob->ei[0]));
+ blob->dl = ntohl((uint32_t)(blob->ei[1]));
+ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK)
+ goto exit;
+
blob->pe = (entryInfo) &(blob->ei[2]);
blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) +
(blob->il * sizeof(*blob->pe)) + blob->dl;

@ -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);
}

@ -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

@ -0,0 +1,162 @@
commit d6a86b5e69e46cc283b1e06c92343319beb42e21
Author: Panu Matilainen <pmatilai@redhat.com>
Date: Thu Mar 4 13:21:19 2021 +0200
Be much more careful about copying data from the signature header
Only look for known tags, and ensure correct type and size where known
before copying over. Bump the old arbitrary 16k count limit to 16M limit
though, it's not inconceivable that a package could have that many files.
While at it, ensure none of these tags exist in the main header,
which would confuse us greatly.
This is optimized for backporting ease, upstream can remove redundancies
and further improve checking later.
Reported and initial patches by Demi Marie Obenour.
Fixes: RhBug:1935049, RhBug:1933867, RhBug:1935035, RhBug:1934125, ...
Fixes: CVE-2021-3421, CVE-2021-20271
Combined with e2f1f1931c5ccf3ecbe4e1e12cacb1e17a277776 and backported into
4.14.3
diff -up rpm-4.14.3/lib/package.c.orig rpm-4.14.3/lib/package.c
--- rpm-4.14.3/lib/package.c.orig 2021-05-31 12:32:49.970393976 +0200
+++ rpm-4.14.3/lib/package.c 2021-05-31 13:53:58.250673275 +0200
@@ -31,76 +31,72 @@ struct pkgdata_s {
rpmRC rc;
};
+struct taglate_s {
+ rpmTagVal stag;
+ rpmTagVal xtag;
+ rpm_count_t count;
+ int quirk;
+} const xlateTags[] = {
+ { RPMSIGTAG_SIZE, RPMTAG_SIGSIZE, 1, 0 },
+ { RPMSIGTAG_PGP, RPMTAG_SIGPGP, 0, 0 },
+ { RPMSIGTAG_MD5, RPMTAG_SIGMD5, 16, 0 },
+ { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 },
+ /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */
+ { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },
+ { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
+ { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
+ { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
+ { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0, 0 },
+ { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1, 0 },
+ { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1, 0 },
+ { 0 }
+};
+
/** \ingroup header
* Translate and merge legacy signature tags into header.
* @param h header (dest)
* @param sigh signature header (src)
+ * @return failing tag number, 0 on success
*/
static
-void headerMergeLegacySigs(Header h, Header sigh)
+rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg)
{
- HeaderIterator hi;
+ const struct taglate_s *xl;
struct rpmtd_s td;
- hi = headerInitIterator(sigh);
- for (; headerNext(hi, &td); rpmtdFreeData(&td))
- {
- switch (td.tag) {
- /* XXX Translate legacy signature tag values. */
- case RPMSIGTAG_SIZE:
- td.tag = RPMTAG_SIGSIZE;
- break;
- case RPMSIGTAG_PGP:
- td.tag = RPMTAG_SIGPGP;
- break;
- case RPMSIGTAG_MD5:
- td.tag = RPMTAG_SIGMD5;
- break;
- case RPMSIGTAG_GPG:
- td.tag = RPMTAG_SIGGPG;
- break;
- case RPMSIGTAG_PGP5:
- td.tag = RPMTAG_SIGPGP5;
- break;
- case RPMSIGTAG_PAYLOADSIZE:
- td.tag = RPMTAG_ARCHIVESIZE;
- break;
- case RPMSIGTAG_SHA1:
- case RPMSIGTAG_SHA256:
- case RPMSIGTAG_DSA:
- case RPMSIGTAG_RSA:
- default:
- if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE))
+ rpmtdReset(&td);
+ for (xl = xlateTags; xl->stag; xl++) {
+ /* There mustn't be one in the main header */
+ if (headerIsEntry(h, xl->xtag)) {
+ /* Some tags may exist in either header, but never both */
+ if (xl->quirk && !headerIsEntry(sigh, xl->stag))
continue;
break;
}
- if (!headerIsEntry(h, td.tag)) {
- switch (td.type) {
- case RPM_NULL_TYPE:
- continue;
+ if (headerGet(sigh, xl->stag, &td, HEADERGET_RAW|HEADERGET_MINMEM)) {
+ /* Translate legacy tags */
+ if (xl->stag != xl->xtag)
+ td.tag = xl->xtag;
+ /* Ensure type and tag size match expectations */
+ if (td.type != rpmTagGetTagType(td.tag))
break;
- case RPM_CHAR_TYPE:
- case RPM_INT8_TYPE:
- case RPM_INT16_TYPE:
- case RPM_INT32_TYPE:
- case RPM_INT64_TYPE:
- if (td.count != 1)
- continue;
+ if (td.count < 1 || td.count > 16*1024*1024)
break;
- case RPM_STRING_TYPE:
- case RPM_BIN_TYPE:
- if (td.count >= 16*1024)
- continue;
+ if (xl->count && td.count != xl->count)
break;
- case RPM_STRING_ARRAY_TYPE:
- case RPM_I18NSTRING_TYPE:
- continue;
+ if (!headerPut(h, &td, HEADERPUT_DEFAULT))
break;
- }
- (void) headerPut(h, &td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(&td);
}
}
- headerFreeIterator(hi);
+ rpmtdFreeData(&td);
+
+ if (xl->stag) {
+ rasprintf(msg, "invalid signature tag %s (%d)",
+ rpmTagGetName(xl->xtag), xl->xtag);
+ }
+
+ return xl->stag;
}
/**
@@ -363,7 +359,8 @@ rpmRC rpmReadPackageFile(rpmts ts, FD_t
goto exit;
/* Append (and remap) signature tags to the metadata. */
- headerMergeLegacySigs(h, sigh);
+ if (headerMergeLegacySigs(h, sigh, &msg))
+ goto exit;
applyRetrofits(h);
/* Bump reference count for return. */

@ -0,0 +1,13 @@
--- rpm-4.14.3/configure.ac.orig 2020-05-04 21:08:41.481365399 +0200
+++ rpm-4.14.3/configure.ac 2020-05-04 21:09:03.550604043 +0200
@@ -129,8 +129,8 @@
AC_PATH_PROG(__PERL, perl, /usr/bin/perl, $MYPATH)
AC_PATH_PROG(__PGP, pgp, /usr/bin/pgp, $MYPATH)
-AC_PATH_PROG(__PYTHON, python2, /usr/bin/python2, $MYPATH)
-AC_PATH_PROG(PYTHON, python2, /usr/bin/python2, $MYPATH)
+AC_PATH_PROG(__PYTHON, python3, /usr/bin/python3, $MYPATH)
+AC_PATH_PROG(PYTHON, python3, /usr/bin/python3, $MYPATH)
AC_PATH_PROG(__RM, rm, /bin/rm, $MYPATH)
AC_PATH_PROG(__RSH, rsh, /usr/bin/rsh, $MYPATH)
AC_PATH_PROG(__SED, sed, /bin/sed, $MYPATH)

@ -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

@ -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;
}

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,14 @@
diff --git a/rpmrc.in b/rpmrc.in
index 4a6cca9..d62ddaf 100644
--- a/rpmrc.in
+++ b/rpmrc.in
@@ -281,7 +281,7 @@ arch_compat: alphaev5: alpha
arch_compat: alpha: axp noarch
arch_compat: athlon: i686
-arch_compat: geode: i586
+arch_compat: geode: i686
arch_compat: pentium4: pentium3
arch_compat: pentium3: i686
arch_compat: i686: i586

@ -0,0 +1,12 @@
diff -up rpm-4.8.1/macros.in.gpg2 rpm-4.8.1/macros.in
--- rpm-4.8.0/macros.in.gpg2 2011-01-17 12:17:38.000000000 +0200
+++ rpm-4.8.0/macros.in 2011-01-17 12:17:59.000000000 +0200
@@ -40,7 +40,7 @@
%__cp @__CP@
%__cpio @__CPIO@
%__file @__FILE@
-%__gpg @__GPG@
+%__gpg /usr/bin/gpg2
%__grep @__GREP@
%__gzip @__GZIP@
%__id @__ID@

@ -0,0 +1,12 @@
diff -up rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs rpm-4.9.90.git11486/scripts/find-lang.sh
--- rpm-4.9.90.git11486/scripts/find-lang.sh.no-man-dirs 2012-03-07 11:31:10.000000000 +0200
+++ rpm-4.9.90.git11486/scripts/find-lang.sh 2012-03-07 15:11:57.465801075 +0200
@@ -181,7 +181,7 @@ s:%lang(C) ::
find "$TOP_DIR" -type d|sed '
s:'"$TOP_DIR"'::
'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+/\)::
-'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1*:
+'"$ALL_NAME$MAN"'s:\(.*/man/\([^/_]\+\).*/man[a-z0-9]\+$\):%lang(\2) \1/*:
s:^\([^%].*\)::
s:%lang(C) ::
/^$/d' >> $MO_NAME

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save