From bd9c005be9682e8dcc6b8cc5a9c3c04199945aa6 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Aug 14 2024 18:08:01 +0000 Subject: Merge remote-tracking branch 'rh/c9s' into c9s-sig-hyperscale --- diff --git a/0001-Add-SourceLicense-tag-to-spec-syntax.patch b/0001-Add-SourceLicense-tag-to-spec-syntax.patch new file mode 100644 index 0000000..0f48138 --- /dev/null +++ b/0001-Add-SourceLicense-tag-to-spec-syntax.patch @@ -0,0 +1,124 @@ +From 1dc9372821487ccace23ff1ae9cba6b30f02c91c Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 5 Jul 2022 16:34:08 +0200 +Subject: [PATCH] Add SourceLicense tag to spec syntax + +to set a separate license to the source RPM. This can be useful if the +sources have code under additional licenses that do not end up in the +binary packeges. + +Resolves: #2079 + +Note on the backport: The spec document on this branch is ancient and +doesn't even contain the License tag's description so this backport +leaves the documentation part out. + +(backported from commit 9ed9d3fce34bc3c8121989e0cf263528e7e68756) +--- + build/parsePreamble.c | 6 ++++++ + lib/rpmtag.h | 3 +++ + tests/data/SPECS/foo.spec | 1 + + tests/data/SPECS/hello.spec | 1 + + tests/rpmbuild.at | 11 +++++++++++ + tests/rpmspec.at | 1 + + 6 files changed, 23 insertions(+) + +diff --git a/build/parsePreamble.c b/build/parsePreamble.c +index e7d6d8752..bd07ecdf0 100644 +--- a/build/parsePreamble.c ++++ b/build/parsePreamble.c +@@ -831,6 +831,11 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, + if (addLangTag(spec, pkg->header, tag, field, lang)) + goto exit; + break; ++ case RPMTAG_SOURCELICENSE: ++ if (addLangTag(spec, spec->sourcePackage->header, ++ RPMTAG_LICENSE, field, lang)) ++ goto exit; ++ break; + case RPMTAG_BUILDROOT: + /* just silently ignore BuildRoot */ + break; +@@ -1012,6 +1017,7 @@ static struct PreambleRec_s const preambleList[] = { + {RPMTAG_EPOCH, 0, 0, 1, LEN_AND_STR("epoch")}, + {RPMTAG_SUMMARY, 1, 0, 1, LEN_AND_STR("summary")}, + {RPMTAG_LICENSE, 0, 0, 1, LEN_AND_STR("license")}, ++ {RPMTAG_SOURCELICENSE, 0, 0, 1, LEN_AND_STR("sourcelicense")}, + {RPMTAG_DISTRIBUTION, 0, 0, 1, LEN_AND_STR("distribution")}, + {RPMTAG_DISTURL, 0, 0, 1, LEN_AND_STR("disturl")}, + {RPMTAG_VENDOR, 0, 0, 1, LEN_AND_STR("vendor")}, +diff --git a/lib/rpmtag.h b/lib/rpmtag.h +index 7d1943835..1fd829118 100644 +--- a/lib/rpmtag.h ++++ b/lib/rpmtag.h +@@ -375,6 +375,9 @@ typedef enum rpmTag_e { + RPMTAG_MODULARITYLABEL = 5096, /* s */ + RPMTAG_PAYLOADDIGESTALT = 5097, /* s[] */ + ++ /* Backports */ ++ RPMTAG_SOURCELICENSE = 5102, /* internal */ ++ + RPMTAG_FIRSTFREE_TAG /*!< internal */ + } rpmTag; + +diff --git a/tests/data/SPECS/foo.spec b/tests/data/SPECS/foo.spec +index 859e98142..9b1087094 100644 +--- a/tests/data/SPECS/foo.spec ++++ b/tests/data/SPECS/foo.spec +@@ -8,6 +8,7 @@ Source: hello-2.0.tar.gz + Patch1: hello-1.0-modernize.patch + Group: Testing + License: GPLv2+ ++SourceLicense: GPL, ASL 1.0 + BuildArch: noarch + + %description +diff --git a/tests/data/SPECS/hello.spec b/tests/data/SPECS/hello.spec +index 5bc9cfaf7..4b9053aca 100644 +--- a/tests/data/SPECS/hello.spec ++++ b/tests/data/SPECS/hello.spec +@@ -4,6 +4,7 @@ Version: 1.0 + Release: 1 + Group: Utilities + License: GPL ++SourceLicense: GPL, ASL 1.0 + Distribution: RPM test suite. + Vendor: Red Hat Software + Packager: Red Hat Software +diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at +index bff65303b..7680f1502 100644 +--- a/tests/rpmbuild.at ++++ b/tests/rpmbuild.at +@@ -31,6 +31,17 @@ run rpmbuild \ + [0], + [ignore], + [ignore]) ++ ++AT_CHECK([ ++ ++runroot rpm -qp --qf "%{license}\n" /build/SRPMS/hello-1.0-1.src.rpm ++runroot rpm -qp --qf "%{license}\n" /build/RPMS/*/hello-1.0-1.*.rpm ++], ++[0], ++[GPL, ASL 1.0 ++GPL ++], ++[]) + AT_CLEANUP + + AT_SETUP([rpmbuild -ba autosetup]) +diff --git a/tests/rpmspec.at b/tests/rpmspec.at +index 2b11201db..c898ee654 100644 +--- a/tests/rpmspec.at ++++ b/tests/rpmspec.at +@@ -243,6 +243,7 @@ Source: hello-2.0.tar.gz + Patch1: hello-1.0-modernize.patch + Group: Testing + License: GPLv2+ ++SourceLicense: GPL, ASL 1.0 + BuildArch: noarch + + %description +-- +2.45.2 + diff --git a/0001-Add-optional-callback-on-directory-changes-during-rp.patch b/0001-Add-optional-callback-on-directory-changes-during-rp.patch new file mode 100644 index 0000000..bda7110 --- /dev/null +++ b/0001-Add-optional-callback-on-directory-changes-during-rp.patch @@ -0,0 +1,107 @@ +From 186e0ab025b9ad92d900697f611633a6f6162f3b Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Don-t-segfault-on-missing-priority-tag.patch b/0001-Don-t-segfault-on-missing-priority-tag.patch new file mode 100644 index 0000000..32a72dc --- /dev/null +++ b/0001-Don-t-segfault-on-missing-priority-tag.patch @@ -0,0 +1,39 @@ +From fd57fc716231c8296d340fdb4c0f6eac176f7f7c Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Fri, 20 Aug 2021 15:14:16 +0200 +Subject: [PATCH] Don't segfault on missing priority tag + +Resolves: #1636 +Related: #1638 +--- + lib/rpmtriggers.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c +index fc809a65e..d541974e8 100644 +--- a/lib/rpmtriggers.c ++++ b/lib/rpmtriggers.c +@@ -517,7 +517,8 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense, + if (matchFunc(ts, te, pfx, sense)) { + for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) { + struct rpmtd_s priorities; +- unsigned int priority; ++ unsigned int priority = 0; ++ unsigned int *priority_ptr; + unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i); + unsigned int tix = rpmdbIndexIteratorTagNum(ii, i); + +@@ -535,7 +536,9 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense, + trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offset); + headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM); + rpmtdSetIndex(&priorities, tix); +- priority = *rpmtdGetUint32(&priorities); ++ priority_ptr = rpmtdGetUint32(&priorities); ++ if (priority_ptr) ++ priority = *priority_ptr; + headerFree(trigH); + + /* Store file trigger in array */ +-- +2.45.1 + diff --git a/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch new file mode 100644 index 0000000..f910f38 --- /dev/null +++ b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch @@ -0,0 +1,30 @@ +From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Eliminate-code-duplication-from-rpmfiNext.patch b/0001-Eliminate-code-duplication-from-rpmfiNext.patch new file mode 100644 index 0000000..a5e0463 --- /dev/null +++ b/0001-Eliminate-code-duplication-from-rpmfiNext.patch @@ -0,0 +1,35 @@ +From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch new file mode 100644 index 0000000..29fb473 --- /dev/null +++ b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch @@ -0,0 +1,66 @@ +From c140768202e271b60910644c1e4bf848a50218d3 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Expose-and-document-rpmdb-verifydb-operation.patch b/0001-Expose-and-document-rpmdb-verifydb-operation.patch new file mode 100644 index 0000000..23b444a --- /dev/null +++ b/0001-Expose-and-document-rpmdb-verifydb-operation.patch @@ -0,0 +1,148 @@ +From 173b737f40e7da85f79544e3f4ea4ad7b8f7d5c2 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 6 Nov 2023 15:58:54 +0200 +Subject: [PATCH] Expose and document rpmdb --verifydb operation + +After years of BDB, sometimes folks just want some assurance that their db +is still fine. Properly exposing an operation to do so hopefully makes +less likely to poke at the db directly (with eg sqlite3 command). +--- + docs/man/rpmdb.8.md | 4 ++++ + tools/rpmdb.c | 4 ++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/rpmdb.c b/rpmdb.c +index 22b0b3e5d..36efff8af 100644 +--- a/rpmdb.c ++++ b/rpmdb.c +@@ -23,8 +23,8 @@ static struct poptOption dbOptsTable[] = { + { "rebuilddb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_REBUILDDB, + N_("rebuild database inverted lists from installed package headers"), + NULL}, +- { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN), +- &mode, MODE_VERIFYDB, N_("verify database files"), NULL}, ++ { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), ++ &mode, MODE_VERIFYDB, N_("verify database"), NULL}, + { "salvagedb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN), + &mode, MODE_SALVAGEDB, N_("salvage database"), NULL}, + { "exportdb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_EXPORTDB, +-- +2.41.0 + +--- a/doc/rpmdb.8 2020-05-28 12:04:25.024136615 +0200 ++++ b/doc/rpmdb.8 2023-12-13 11:57:30.646202901 +0100 +@@ -1,48 +1,70 @@ +-.TH "RPMDB" "8" "29 June 2010" "Red Hat, Inc" ++.\" Automatically generated by Pandoc 3.1.3 ++.\" ++.\" Define V font for inline verbatim, using C font in formats ++.\" that render this, and otherwise B font. ++.ie "\f[CB]x\f[]"x" \{\ ++. ftr V B ++. ftr VI BI ++. ftr VB B ++. ftr VBI BI ++.\} ++.el \{\ ++. ftr V CR ++. ftr VI CI ++. ftr VB CB ++. ftr VBI CBI ++.\} ++.TH "RPMDB" "8" "29 June 2010" "" "" ++.hy + .SH NAME +-rpmdb \- RPM Database Tool ++.PP ++rpmdb - RPM Database Tool + .SH SYNOPSIS +- +-\fBrpm\fR {\fB--initdb|--rebuilddb\fR} +- +-.SH "DESCRIPTION" +-The general form of an rpm rebuild database command is +-.PP +- +-\fBrpm\fR {\fB--initdb|--rebuilddb\fR} [\fB-v\fR] [\fB--dbpath \fIDIRECTORY\fB\fR] [\fB--root \fIDIRECTORY\fB\fR] +- +-.PP +-Use \fB--initdb\fR to create a new database if one doesn't already exist +-(existing database is not overwritten), use +-\fB--rebuilddb\fR to rebuild the database indices from +-the installed package headers. +-.PP +- +-.SH "SEE ALSO" +- +-.nf +-\fBpopt\fR(3), +-\fBrpm\fR(8), +-\fBrpmkeys\fR(8), +-\fBrpmsign\fR(8), +-\fBrpm2cpio\fR(8), +-\fBrpmbuild\fR(8), +-\fBrpmspec\fR(8), +-.fi +- +-\fBrpm --help\fR - as rpm supports customizing the options via popt aliases +-it's impossible to guarantee that what's described in the manual matches +-what's available. +- +- +-\fBhttp://www.rpm.org/ +-\fR +-.SH "AUTHORS" +- ++.PP ++\f[B]rpmdb\f[R] {\f[B]--initdb|--rebuilddb\f[R]} ++.PP ++\f[B]rpmdb\f[R] {\f[B]--verifydb\f[R]} ++.PP ++\f[B]rpmdb\f[R] {\f[B]--exportdb|--importdb\f[R]} ++.SH DESCRIPTION ++.PP ++The general form of an rpmdb command is ++.PP ++\f[B]rpm\f[R] {\f[B]--initdb|--rebuilddb\f[R]} [\f[B]-v\f[R]] ++[\f[B]--dbpath \f[R]\f[I]DIRECTORY\f[R]] [\f[B]--root ++\f[R]\f[I]DIRECTORY\f[R]] ++.PP ++Use \f[B]--initdb\f[R] to create a new database if one doesn\[aq]t ++already exist (existing database is not overwritten), use ++\f[B]--rebuilddb\f[R] to rebuild the database indices from the installed ++package headers. ++.PP ++\f[B]--verifydb\f[R] performs a low-level integrity check on the ++database. ++.PP ++\f[B]--exportdb\f[R] exports the database in header-list format, ++suitable for transfporting to another host or database type. ++.PP ++\f[B]--importdb\f[R] imports a database from a header-list format as ++created by \f[B]--exportdb\f[R]. ++.SH SEE ALSO ++.PP ++\f[B]popt\f[R](3), \f[B]rpm\f[R](8), \f[B]rpmkeys\f[R](8), ++\f[B]rpmsign\f[R](8), \f[B]rpm2cpio\f[R](8), \f[B]rpmbuild\f[R](8), ++\f[B]rpmspec\f[R](8) ++.PP ++\f[B]rpm --help\f[R] - as rpm supports customizing the options via popt ++aliases it\[aq]s impossible to guarantee that what\[aq]s described in ++the manual matches what\[aq]s available. ++.PP ++\f[B]http://www.rpm.org/ \f[R] ++.SH AUTHORS ++.IP + .nf +-Marc Ewing +-Jeff Johnson +-Erik Troan +-Panu Matilainen ++\f[C] ++Marc Ewing ++Jeff Johnson ++Erik Troan ++Panu Matilainen ++\f[R] + .fi +- diff --git a/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch b/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch new file mode 100644 index 0000000..63cc183 --- /dev/null +++ b/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch @@ -0,0 +1,26 @@ +From 03525592c944957f3b7b200b7daeb9f615cdcde7 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Tue, 23 May 2023 12:46:22 +0300 +Subject: [PATCH] Fix a copy-paste --help description of --whatconflicts + (RhBug:2208661) + +--- + lib/poptQV.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/poptQV.c b/lib/poptQV.c +index ac8e8975d..8bd91c652 100644 +--- a/lib/poptQV.c ++++ b/lib/poptQV.c +@@ -108,7 +108,7 @@ struct poptOption rpmQVSourcePoptTable[] = { + { "verify", 'V', POPT_ARGFLAG_DOC_HIDDEN, NULL, 'V', + N_("rpm verify mode"), NULL }, + { "whatconflicts", '\0', 0, 0, POPT_WHATCONFLICTS, +- N_("query/verify the package(s) which require a dependency"), "CAPABILITY" }, ++ N_("query/verify the package(s) which conflict with a dependency"), "CAPABILITY" }, + { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES, + N_("query/verify the package(s) which require a dependency"), "CAPABILITY" }, + { "whatobsoletes", '\0', 0, 0, POPT_WHATOBSOLETES, +-- +2.41.0 + diff --git a/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch b/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch new file mode 100644 index 0000000..3d4557c --- /dev/null +++ b/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.16.1.3/lib/rpmts.c.orig rpm-4.16.1.3/lib/rpmts.c +--- rpm-4.16.1.3/lib/rpmts.c.orig 2024-07-11 13:55:35.430198126 +0200 ++++ rpm-4.16.1.3/lib/rpmts.c 2024-07-11 13:55:59.243061182 +0200 +@@ -482,6 +482,8 @@ static int makePubkeyHeader(rpmts ts, rp + int rc = -1; + int i; + ++ memset(&kd, 0, sizeof(kd)); ++ + if ((enc = rpmPubkeyBase64(key)) == NULL) + goto exit; + if ((dig = rpmPubkeyDig(key)) == NULL) diff --git a/0001-Fix-potential-use-of-uninitialized-pipe-array.patch b/0001-Fix-potential-use-of-uninitialized-pipe-array.patch new file mode 100644 index 0000000..dcabc59 --- /dev/null +++ b/0001-Fix-potential-use-of-uninitialized-pipe-array.patch @@ -0,0 +1,32 @@ +From bff65aad8af719542c7b0c6429e09223c014a909 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Thu, 6 Jun 2024 09:15:02 +0200 +Subject: [PATCH] Fix potential use of uninitialized pipe array + +We only call pipe(2) after the script is written to disk so if the +latter fails, the array will be left uninitialized and subsequently read +after skipping to the exit label. Fix by initializing it. + +Found by Coverity. + +Fixes: RHEL-22604 +--- + lib/rpmscript.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/rpmscript.c b/lib/rpmscript.c +index 281c55c53..1de4acf8e 100644 +--- a/lib/rpmscript.c ++++ b/lib/rpmscript.c +@@ -316,7 +316,7 @@ static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes, + char * fn = NULL; + pid_t pid, reaped; + int status; +- int inpipe[2]; ++ int inpipe[2] = { -1, -1 }; + FILE *in = NULL; + const char *line; + char *mline = NULL; +-- +2.45.2 + diff --git a/0001-Fix-root-relocation-regression.patch b/0001-Fix-root-relocation-regression.patch new file mode 100644 index 0000000..e4ce8b6 --- /dev/null +++ b/0001-Fix-root-relocation-regression.patch @@ -0,0 +1,91 @@ +From bce17e42f2301a88574d757740627480a38d86aa Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Fri, 26 Jul 2024 10:44:04 +0200 +Subject: [PATCH] Fix root relocation regression + +When relocating the root directory, make sure we insert the new path's +dirname to dirNames[] even if the root itself is owned by the package. + +This appears to have been the intention from the first version (largely +untouched since) of this code as we allow the root to pass through the +first checks (by setting len to 0 in that case) as well as the second +for loop where we do the relocations. + +This allows fsm to properly create and remove the relocated directory +since we're now using fd-based calls (#1919) and the parent directory +needs to be opened first. + +No need to do string comparison here, the empty basename signals that +we're processing the root directory, so just use that. + +Building a relocatable package that owns the root directory seems to be +a handy way to create user-installable packages (see RHEL-28967) and it +happened to work before with the path-based calls so this technically +was a regression. Add a test that emulates this use case. + +Backported from commits: +31c14ba6610568c2d634647fed1fb57221178da9 +308ac60677732e9979b9ce11e5a3085906da1901 + +Fixes: RHEL-28967 +--- + lib/relocation.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/relocation.c b/lib/relocation.c +index 3ba4cfeab..8c35bc1a7 100644 +--- a/lib/relocation.c ++++ b/lib/relocation.c +@@ -123,7 +123,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + char ** baseNames; + char ** dirNames; + uint32_t * dirIndexes; +- rpm_count_t fileCount, dirCount; ++ rpm_count_t fileCount, dirCount, dirCountOrig; + int nrelocated = 0; + int fileAlloced = 0; + char * fn = NULL; +@@ -162,7 +162,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + baseNames = bnames.data; + dirIndexes = dindexes.data; + fileCount = rpmtdCount(&bnames); +- dirCount = rpmtdCount(&dnames); ++ dirCount = dirCountOrig = rpmtdCount(&dnames); + /* XXX TODO: use rpmtdDup() instead */ + dirNames = dnames.data = duparray(dnames.data, dirCount); + dnames.flags |= RPMTD_PTR_ALLOCED; +@@ -179,8 +179,9 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, + rpmFileTypes ft; + int fnlen; + ++ size_t baselen = strlen(baseNames[i]); + size_t len = maxlen + +- strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; ++ strlen(dirNames[dirIndexes[i]]) + baselen + 1; + if (len >= fileAlloced) { + fileAlloced = len * 2; + fn = xrealloc(fn, fileAlloced); +@@ -242,8 +243,9 @@ assert(fn != NULL); /* XXX can't happen */ + continue; + } + +- /* Relocation on full paths only, please. */ +- if (fnlen != len) continue; ++ /* Relocation on '/' and full paths only, please. */ ++ if (baselen && fnlen != len) ++ continue; + + rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", + fn, relocations[j].newPath); +@@ -294,7 +296,7 @@ assert(fn != NULL); /* XXX can't happen */ + } + + /* Finish off by relocating directories. */ +- for (i = dirCount - 1; i >= 0; i--) { ++ for (i = dirCountOrig - 1; i >= 0; i--) { + for (j = numRelocations - 1; j >= 0; j--) { + + if (relocations[j].oldPath == NULL) /* XXX can't happen */ +-- +2.45.2 + diff --git a/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch b/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch new file mode 100644 index 0000000..e06709a --- /dev/null +++ b/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch @@ -0,0 +1,50 @@ +From 321933f060896f721e361a1c8a8d3731bdcee827 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Wed, 22 Jun 2022 14:07:01 +0200 +Subject: [PATCH] Fix short circuiting of version strings in expressions + +We use an empty string when discarding a value due to short circuiting, but +an empty string is not allowed for versions. So use "0" in that case. + +Fixes: #1883 +--- + rpmio/expression.c | 2 +- + tests/rpmmacro.at | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/rpmio/expression.c b/rpmio/expression.c +index a389a04d5..98a44bbdb 100644 +--- a/rpmio/expression.c ++++ b/rpmio/expression.c +@@ -477,7 +477,7 @@ static int rdToken(ParseState state) + if (qtok == TOK_STRING) { + v = valueMakeString(temp); + } else { +- v = valueMakeVersion(temp); ++ v = valueMakeVersion(state->flags & RPMEXPR_DISCARD ? "0" : temp); + free(temp); /* version doesn't take ownership of the string */ + if (v == 0) { + exprErr(state, _("invalid version"), p+1); +diff --git a/tests/rpmmacro.at b/tests/rpmmacro.at +index d1490b4d9..c4376d49e 100644 +--- a/tests/rpmmacro.at ++++ b/tests/rpmmacro.at +@@ -533,6 +533,7 @@ runroot rpm \ + --eval '%["%{aaa}"]' \ + --eval '%[%{?ccc}]' \ + --eval '%[v"1:2.3-4"]' \ ++ --eval '%[v"0" && v"0"]' \ + ]], + [0], + [4096 +@@ -542,6 +543,7 @@ runroot rpm \ + 5 + 0 + 1:2.3-4 ++0 + ], + []) + AT_CLEANUP +-- +2.41.0 + diff --git a/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch new file mode 100644 index 0000000..1d73765 --- /dev/null +++ b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch @@ -0,0 +1,46 @@ +From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch new file mode 100644 index 0000000..177aa0f --- /dev/null +++ b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch @@ -0,0 +1,158 @@ +From ac7b0dbd5a18d2c57a942ca14ac856b8047425ff Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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/ima.c b/plugins/ima.c +index fe6d3ad7f..9c28a41a3 100644 +--- a/plugins/ima.c ++++ b/plugins/ima.c +@@ -39,7 +39,7 @@ static int check_zero_hdr(const unsigned char *fsig, size_t siglen) + 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) +@@ -68,8 +68,13 @@ + + fsig = rpmfiFSignature(fi, &len); + if (fsig && (check_zero_hdr(fsig, len) == 0)) { +- if (lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0) < 0) { +- int is_err = errno != EOPNOTSUPP; ++ 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)); +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 */ +diff --git a/plugins/selinux.c b/plugins/selinux.c +index 32c3b7529..a7f20aeca 100644 +--- a/plugins/selinux.c ++++ b/plugins/selinux.c +@@ -149,7 +149,7 @@ static rpmRC selinux_scriptlet_fork_post(rpmPlugin plugin, + 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) + { +@@ -194,13 +194,17 @@ + if (sehandle && !XFA_SKIPPING(action)) { + char *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(loglvl(rc != RPMRC_OK), "lsetfilecon: (%s, %s) %s\n", +- path, scon, (conrc < 0 ? strerror(errno) : "")); ++ rpmlog(loglvl(rc != RPMRC_OK), "lsetfilecon: (%d %s, %s) %s\n", ++ fd, path, scon, (conrc < 0 ? strerror(errno) : "")); + + freecon(scon); + } else { +-- +2.41.0 + diff --git a/0001-Print-full-path-if-file-removal-fails.patch b/0001-Print-full-path-if-file-removal-fails.patch new file mode 100644 index 0000000..266bd69 --- /dev/null +++ b/0001-Print-full-path-if-file-removal-fails.patch @@ -0,0 +1,32 @@ +From f1503ab6e898430b80017c0f8347860f3a74d5bb Mon Sep 17 00:00:00 2001 +From: Florian Festi +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 + diff --git a/0001-RPM-with-Copy-on-Write.patch b/0001-RPM-with-Copy-on-Write.patch index 151d2d8..49a0f32 100644 --- a/0001-RPM-with-Copy-on-Write.patch +++ b/0001-RPM-with-Copy-on-Write.patch @@ -85,9 +85,10 @@ and other non file types. Nothing has been removed, and none of the changes are intended to be used externally, so I don't think a soname bump is warranted here. --- + .gitignore | 1 + Makefile.am | 6 +- lib/depends.c | 2 + - lib/fsm.c | 45 +++- + lib/fsm.c | 61 +++++- lib/package.c | 40 ++++ lib/rpmlib.h | 9 + lib/rpmplugins.c | 21 +- @@ -100,7 +101,7 @@ used externally, so I don't think a soname bump is warranted here. rpm2extents.c | 519 ++++++++++++++++++++++++++++++++++++++++++++ rpmio/rpmpgp.c | 10 + rpmio/rpmpgp.h | 9 + - 15 files changed, 1004 insertions(+), 12 deletions(-) + 16 files changed, 1020 insertions(+), 13 deletions(-) create mode 100644 plugins/reflink.c create mode 100644 rpm2extents.c @@ -108,7 +109,7 @@ diff --git a/Makefile.am b/Makefile.am index e5c75d7b4..288668819 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -99,7 +99,7 @@ pkginclude_HEADERS += build/rpmfc.h +@@ -106,7 +106,7 @@ pkginclude_HEADERS += build/rpmfc.h pkginclude_HEADERS += build/rpmspec.h @@ -117,7 +118,7 @@ index e5c75d7b4..288668819 100644 if WITH_ARCHIVE bin_PROGRAMS += rpm2archive endif -@@ -154,6 +154,10 @@ rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h +@@ -160,6 +160,10 @@ rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la rpm2cpio_LDADD += @WITH_POPT_LIB@ @@ -132,7 +133,7 @@ diff --git a/lib/depends.c b/lib/depends.c index 30234df3d..8998afcd3 100644 --- a/lib/depends.c +++ b/lib/depends.c -@@ -81,6 +81,8 @@ static rpmRC headerCheckPayloadFormat(Header h) { +@@ -80,6 +80,8 @@ static rpmRC headerCheckPayloadFormat(Header h) { */ if (!payloadfmt) return rc; @@ -146,33 +147,33 @@ index 935a0a5c6..90193c749 100644 --- a/lib/fsm.c +++ b/lib/fsm.c @@ -8,6 +8,7 @@ - + #include #include #include +#include - #if WITH_CAP + #include + #ifdef WITH_CAP #include - #endif -@@ -19,6 +20,7 @@ +@@ -17,6 +18,7 @@ + #include + #include + #include ++#include #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ - #include "lib/fsm.h" -+#include "lib/rpmlib.h" - #include "lib/rpmte_internal.h" /* XXX rpmfs */ - #include "lib/rpmplugins.h" /* rpm plugins hooks */ - #include "lib/rpmug.h" -@@ -52,6 +54,7 @@ struct filedata_s { + #include "fsm.h" +@@ -54,6 +56,7 @@ struct filedata_s { int stage; int setmeta; int skip; -+ int plugin_contents; ++ bool plugin_contents; rpmFileAction action; const char *suffix; char *fpath; -@@ -891,6 +894,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -885,6 +888,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); struct filedata_s *firstlink = NULL; - + struct diriter_s di = { -1, -1 }; + Header h = rpmteHeader(te); + const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT); + bool cpio = true; @@ -180,21 +181,14 @@ index 935a0a5c6..90193c749 100644 + if (payloadfmt && rstreq(payloadfmt, "clon")) { + cpio = false; + } -+ + /* transaction id used for temporary path suffix while installing */ rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); - -@@ -911,12 +922,23 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Remap file perms, owner, and group. */ - rc = rpmfiStat(fi, 1, &fp->sb); +@@ -909,7 +919,20 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + fp->setmeta = (fp->skip == 0) && + (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH); - setFileState(fs, fx); - fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Run fsm file pre hook for all plugins */ - rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, - fp->sb.st_mode, fp->action); -+ fp->plugin_contents = false; + switch (rc) { + case RPMRC_OK: + setFileState(fs, fx); @@ -205,57 +199,95 @@ index 935a0a5c6..90193c749 100644 + // this is from a hard link. + rc = RPMRC_OK; + break; ++ default: ++ fp->action = FA_SKIP; ++ fp->skip = XFA_SKIPPING(fp->action); + } + fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb); + fp->stage = FILE_PRE; - } - fi = rpmfiFree(fi); -@@ -924,10 +946,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -919,8 +942,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (rc) goto exit; -- fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -- if (fi == NULL) { -- rc = RPMERR_BAD_MAGIC; -- goto exit; +- fi = fsmIter(payload, files, +- payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + if (cpio) { -+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ if (fi == NULL) { -+ rc = RPMERR_BAD_MAGIC; -+ goto exit; -+ } ++ fi = fsmIter(payload, files, ++ payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + } else { + fi = rpmfilesIter(files, RPMFI_ITER_FWD); - } ++ } + + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; +@@ -943,6 +970,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!fp->skip) { + int mayopen = 0; + int fd = -1; ++ ++ if (!cpio && di.dirfd >= 0) ++ fsmClose(&di.dirfd); + rc = ensureDir(plugins, rpmfiDN(fi), 0, + (fp->action == FA_CREATE), 0, &di.dirfd); - /* Detect and create directories not explicitly in package. */ -@@ -969,8 +995,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -952,9 +982,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + } + + /* Run fsm file pre hook for all plugins */ +- if (!rc) ++ if (!rc) { + rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, + fp->sb.st_mode, fp->action); ++ if (rc == RPMRC_PLUGIN_CONTENTS) { ++ fp->plugin_contents = true; ++ rc = RPMRC_OK; ++ } ++ } + if (rc) + goto setmeta; /* for error notification */ + +@@ -984,9 +1019,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (S_ISREG(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firstlink, &firstlinkfile); -+ if(fp->plugin_contents) { +- rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, +- &firstlink, &firstlinkfile, &di.firstdir, +- &fd); ++ if (fp->plugin_contents) { + rc = RPMRC_OK; -+ }else { -+ rc = fsmMkfile(fi, fp, files, psm, nodigest, -+ &firstlink, &firstlinkfile); ++ } else { ++ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile, ++ &di.firstdir, &fd); + } } } else if (S_ISDIR(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { -@@ -1078,6 +1108,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); +@@ -1054,11 +1093,17 @@ setmeta: + rc = fx; + + /* If all went well, commit files to final destination */ +- fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ if (cpio) { ++ fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ } else { ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ } + while (!rc && (fx = rpmfiNext(fi)) >= 0) { + struct filedata_s *fp = &fdata[fx]; + + if (!fp->skip) { ++ if (!cpio && di.dirfd >= 0) ++ fsmClose(&di.dirfd); + if (!rc) + rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd); - exit: -+ h = headerFree(h); - fi = rpmfiFree(fi); - Fclose(payload); - free(tid); diff --git a/lib/package.c b/lib/package.c index 281275029..90bd0d8a7 100644 --- a/lib/package.c +++ b/lib/package.c -@@ -404,5 +404,45 @@ exit: +@@ -402,5 +402,45 @@ exit: return rc; } @@ -305,7 +337,7 @@ diff --git a/lib/rpmlib.h b/lib/rpmlib.h index 0879d04e5..a09ba0daf 100644 --- a/lib/rpmlib.h +++ b/lib/rpmlib.h -@@ -155,6 +155,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg); +@@ -156,6 +156,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg); rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp); @@ -325,16 +357,17 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c index 62d75c4cf..c5084d398 100644 --- a/lib/rpmplugins.c +++ b/lib/rpmplugins.c -@@ -356,13 +356,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, +@@ -364,14 +364,29 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, plugin_fsm_file_pre_func hookFunc; int i; rpmRC rc = RPMRC_OK; + rpmRC hook_rc; + 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; + if (hookFunc) { @@ -344,9 +377,9 @@ index 62d75c4cf..c5084d398 100644 + rc = RPMRC_FAIL; + } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) { + if (rc == RPMRC_PLUGIN_CONTENTS) { -+ /* -+ Another plugin already said it'd handle contents. It's undefined how -+ these would combine, so treat this as a failure condition. ++ /* Another plugin already said it'd handle contents. It's ++ * undefined how these would combine, so treat this as a ++ * failure condition. + */ + rc = RPMRC_FAIL; + } else { @@ -356,12 +389,12 @@ index 62d75c4cf..c5084d398 100644 + } } } - + free(apath); diff --git a/lib/rpmte.c b/lib/rpmte.c index 3663604e7..d43dc41ad 100644 --- a/lib/rpmte.c +++ b/lib/rpmte.c -@@ -423,6 +423,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd) +@@ -421,6 +421,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd) return NULL; } @@ -404,7 +437,7 @@ diff --git a/macros.in b/macros.in index e90cefa9a..363252b0f 100644 --- a/macros.in +++ b/macros.in -@@ -1143,6 +1143,7 @@ package or when debugging this package.\ +@@ -1189,6 +1189,7 @@ package or when debugging this package.\ # Transaction plugin macros %__plugindir %{_libdir}/rpm-plugins @@ -416,7 +449,7 @@ diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 3a929d0ce..ad0d3bce7 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am -@@ -42,6 +42,10 @@ prioreset_la_SOURCES = prioreset.c +@@ -33,6 +33,10 @@ prioreset_la_SOURCES = prioreset.c prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la plugins_LTLIBRARIES += prioreset.la @@ -1302,7 +1335,7 @@ diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c index 015c15a5c..7b972b4a6 100644 --- a/rpmio/rpmpgp.c +++ b/rpmio/rpmpgp.c -@@ -283,6 +283,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se) +@@ -298,6 +298,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se) return vs->val; } diff --git a/0001-Skip-to-hashed-subpacket-data-directly.patch b/0001-Skip-to-hashed-subpacket-data-directly.patch new file mode 100644 index 0000000..f0eaf1f --- /dev/null +++ b/0001-Skip-to-hashed-subpacket-data-directly.patch @@ -0,0 +1,35 @@ +From 331afbf2b6b32582b29ceadcd37b43a4f905b7f4 Mon Sep 17 00:00:00 2001 +From: Michal Domonkos +Date: Mon, 5 Aug 2024 14:40:57 +0200 +Subject: [PATCH] Skip to hashed subpacket data directly + +Make OpenScanHub grok the bigger picture here, instead of producing a +spurious overrun warning for v->hashlen when we're dereferencing p +later. + +No functional change. + +Resolves: RHEL-22607 +--- + rpmio/rpmpgp.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index d0688ebe9..6a7049954 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -618,10 +618,9 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype); + pgpPrtNL(); + +- p = &v->hashlen[0]; + if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen)) + return 1; +- p += sizeof(v->hashlen); ++ p = h + sizeof(*v); + + if ((p + plen) > (h + hlen)) + return 1; +-- +2.45.2 + diff --git a/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch new file mode 100644 index 0000000..3210c07 --- /dev/null +++ b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch @@ -0,0 +1,90 @@ +From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +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 + diff --git a/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch b/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch new file mode 100644 index 0000000..e198993 --- /dev/null +++ b/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch @@ -0,0 +1,57 @@ +From d29651be364ef72c7c0f468157602e4ed5cab4ff Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Wed, 12 Jun 2024 15:46:12 +0200 +Subject: [PATCH] Talk about rpmsign in the rpmsign man page + +In the past handling signatures was done by the rpm / rpmbuild binaries +directly. When this functionality was split into rpmsign the man page +was not adjusted accoringly. This is the long overdue update. + +Resolves: # 3125 + +(backported from commit 8e1f55c7004e8c1a7d9140ab2dd9456a7ace3e77) +--- + doc/rpmsign.8 | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 +index f7ceae89b..6c5bcc8ef 100644 +--- a/doc/rpmsign.8 ++++ b/doc/rpmsign.8 +@@ -5,9 +5,9 @@ rpmsign \- RPM Package Signing + .SS "SIGNING PACKAGES:" + .PP + +-\fBrpm\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR ++\fBrpmsign\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR + +-\fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR ++\fBrpmsign\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR + + .SS "rpmsign-options" + .PP +@@ -22,10 +22,10 @@ options generate and insert new signatures for each package + existing signatures. There are two options for historical reasons, + there is no difference in behavior currently. + +-To create a signature rpm needs to verify the package's checksum. As a result ++To create a signature rpmsign needs to verify the package's checksum. As a result + packages with a MD5/SHA1 checksums cannot be signed in FIPS mode. + +-\fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR ++\fBrpmsign\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR + + .PP + Delete all signatures from each package \fIPACKAGE_FILE\fR given. +@@ -36,7 +36,7 @@ Delete all signatures from each package \fIPACKAGE_FILE\fR given. + \fB--rpmv3\fR + Force RPM V3 header+payload signature addition. + These are expensive and redundant baggage on packages where a separate +-payload digest exists (packages built with rpm >= 4.14). Rpm will ++payload digest exists (packages built with rpm >= 4.14). Rpmsign will + automatically detect the need for V3 signatures, but this option can be + used to force their creation if the packages must be fully + signature verifiable with rpm < 4.14 or other interoperability reasons. +-- +2.45.2 + diff --git a/0001-Use-file-state-machine-from-rpm-4.19.patch b/0001-Use-file-state-machine-from-rpm-4.19.patch new file mode 100644 index 0000000..2bb5dd9 --- /dev/null +++ b/0001-Use-file-state-machine-from-rpm-4.19.patch @@ -0,0 +1,1631 @@ +From 36ee14a07630668629a0d461fba8b5b2248d7d71 Mon Sep 17 00:00:00 2001 +From: Florian Festi +Date: Tue, 10 Oct 2023 16:46:17 +0200 +Subject: [PATCH] Use file state machine from rpm-4.19 + +This new implementation fixes several race conditions when placing down +files on disc +--- + lib/fsm.c | 1164 +++++++++++++++++++++++++--------------------- + lib/rpmarchive.h | 3 + + lib/rpmfiles.h | 3 + + +diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h +index c864e5b56..e5cda4f97 100644 +--- a/lib/rpmarchive.h ++++ b/lib/rpmarchive.h +@@ -26,6 +26,8 @@ enum rpmfilesErrorCodes { + RPMERR_FILE_SIZE = -12, + RPMERR_ITER_SKIP = -13, + RPMERR_EXIST_AS_DIR = -14, ++ RPMERR_INVALID_SYMLINK = -15, ++ RPMERR_ENOTDIR = -16, + + RPMERR_OPEN_FAILED = -32768, + RPMERR_CHMOD_FAILED = -32769, +@@ -47,6 +49,7 @@ enum rpmfilesErrorCodes { + RPMERR_COPY_FAILED = -32785, + RPMERR_LSETFCON_FAILED = -32786, + RPMERR_SETCAP_FAILED = -32787, ++ RPMERR_CLOSE_FAILED = -32788, + }; + + #ifdef __cplusplus +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index daf572cf4..e74bb2201 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e { + #define XFA_SKIPPING(_a) \ + ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) + ++#define XFA_CREATING(_a) \ ++ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) ++ + /** + * We pass these around as an array with a sentinel. + */ +--- rpm-4.16.1.3/lib/fsm.c.orig 2023-11-11 10:05:19.208206675 +0100 ++++ rpm-4.16.1.3/lib/fsm.c 2023-11-11 10:05:43.559432708 +0100 +@@ -5,9 +5,11 @@ + + #include "system.h" + ++#include + #include + #include +-#if WITH_CAP ++#include ++#ifdef WITH_CAP + #include + #endif + +@@ -17,10 +19,11 @@ + #include + + #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ +-#include "lib/fsm.h" +-#include "lib/rpmte_internal.h" /* XXX rpmfs */ +-#include "lib/rpmplugins.h" /* rpm plugins hooks */ +-#include "lib/rpmug.h" ++#include "fsm.h" ++#include "rpmte_internal.h" /* XXX rpmfs */ ++#include "rpmfi_internal.h" /* rpmfiSetOnChdir */ ++#include "rpmplugins.h" /* rpm plugins hooks */ ++#include "rpmug.h" + + #include "debug.h" + +@@ -38,172 +41,92 @@ + #define _dirPerms 0755 + #define _filePerms 0644 + ++enum filestage_e { ++ FILE_COMMIT = -1, ++ FILE_NONE = 0, ++ FILE_PRE = 1, ++ FILE_UNPACK = 2, ++ FILE_PREP = 3, ++ FILE_POST = 4, ++}; ++ ++struct filedata_s { ++ int stage; ++ int setmeta; ++ int skip; ++ rpmFileAction action; ++ const char *suffix; ++ char *fpath; ++ struct stat sb; ++}; ++ + /* + * XXX Forward declarations for previously exported functions to avoid moving + * things around needlessly + */ + static const char * fileActionString(rpmFileAction a); ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir); ++static int fsmClose(int *wfdp); + + /** \ingroup payload + * Build path to file from file info, optionally ornamented with suffix. ++ * "/" needs special handling to avoid appearing as empty path. + * @param fi file info iterator + * @param suffix suffix to use (NULL disables) +- * @retval path to file (malloced) ++ * @param[out] path to file (malloced) + */ + static char * fsmFsPath(rpmfi fi, const char * suffix) + { +- return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL); +-} +- +-/** \ingroup payload +- * Directory name iterator. +- */ +-typedef struct dnli_s { +- rpmfiles fi; +- char * active; +- int reverse; +- int isave; +- int i; +-} * DNLI_t; +- +-/** \ingroup payload +- * Destroy directory name iterator. +- * @param dnli directory name iterator +- * @retval NULL always +- */ +-static DNLI_t dnlFreeIterator(DNLI_t dnli) +-{ +- if (dnli) { +- if (dnli->active) free(dnli->active); +- free(dnli); +- } +- return NULL; ++ const char *bn = rpmfiBN(fi); ++ return rstrscat(NULL, *bn ? bn : "/", suffix ? suffix : "", NULL); + } + +-/** \ingroup payload +- * Create directory name iterator. +- * @param fi file info set +- * @param fs file state set +- * @param reverse traverse directory names in reverse order? +- * @return directory name iterator +- */ +-static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse) ++static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path) + { +- DNLI_t dnli; +- int i, j; +- int dc; +- +- if (fi == NULL) +- return NULL; +- dc = rpmfilesDC(fi); +- dnli = xcalloc(1, sizeof(*dnli)); +- dnli->fi = fi; +- dnli->reverse = reverse; +- dnli->i = (reverse ? dc : 0); +- +- if (dc) { +- dnli->active = xcalloc(dc, sizeof(*dnli->active)); +- int fc = rpmfilesFC(fi); +- +- /* Identify parent directories not skipped. */ +- for (i = 0; i < fc; i++) +- if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) +- dnli->active[rpmfilesDI(fi, i)] = 1; +- +- /* Exclude parent directories that are explicitly included. */ +- for (i = 0; i < fc; i++) { +- int dil; +- size_t dnlen, bnlen; ++ int rc = linkat(odirfd, opath, dirfd, path, 0); + +- if (!S_ISDIR(rpmfilesFMode(fi, i))) +- continue; +- +- dil = rpmfilesDI(fi, i); +- dnlen = strlen(rpmfilesDN(fi, dil)); +- bnlen = strlen(rpmfilesBN(fi, i)); +- +- for (j = 0; j < dc; j++) { +- const char * dnl; +- size_t jlen; +- +- if (!dnli->active[j] || j == dil) +- continue; +- dnl = rpmfilesDN(fi, j); +- jlen = strlen(dnl); +- if (jlen != (dnlen+bnlen+1)) +- continue; +- if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen)) +- continue; +- if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen)) +- continue; +- if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') +- continue; +- /* This directory is included in the package. */ +- dnli->active[j] = 0; +- break; +- } +- } +- +- /* Print only once per package. */ +- if (!reverse) { +- j = 0; +- for (i = 0; i < dc; i++) { +- if (!dnli->active[i]) continue; +- if (j == 0) { +- j = 1; +- rpmlog(RPMLOG_DEBUG, +- "========== Directories not explicitly included in package:\n"); +- } +- rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i)); +- } +- if (j) +- rpmlog(RPMLOG_DEBUG, "==========\n"); +- } ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } +- return dnli; ++ ++ if (rc < 0) ++ rc = RPMERR_LINK_FAILED; ++ return rc; + } + +-/** \ingroup payload +- * Return next directory name (from file info). +- * @param dnli directory name iterator +- * @return next directory name +- */ +-static +-const char * dnlNextIterator(DNLI_t dnli) ++#ifdef WITH_CAP ++static int cap_set_fileat(int dirfd, const char *path, cap_t fcaps) + { +- const char * dn = NULL; +- +- if (dnli) { +- rpmfiles fi = dnli->fi; +- int dc = rpmfilesDC(fi); +- int i = -1; +- +- if (dnli->active) +- do { +- i = (!dnli->reverse ? dnli->i++ : --dnli->i); +- } while (i >= 0 && i < dc && !dnli->active[i]); +- +- if (i >= 0 && i < dc) +- dn = rpmfilesDN(fi, i); +- else +- i = -1; +- dnli->isave = i; ++ int rc = -1; ++ int fd = fsmOpenat(dirfd, path, O_RDONLY|O_NOFOLLOW, 0); ++ if (fd >= 0) { ++ rc = cap_set_fd(fd, fcaps); ++ fsmClose(&fd); + } +- return dn; ++ return rc; + } ++#endif + +-static int fsmSetFCaps(const char *path, const char *captxt) ++static int fsmSetFCaps(int fd, int dirfd, const char *path, const char *captxt) + { + int rc = 0; +-#if WITH_CAP ++ ++#ifdef WITH_CAP + if (captxt && *captxt != '\0') { + cap_t fcaps = cap_from_text(captxt); +- if (fcaps == NULL || cap_set_file(path, fcaps) != 0) { +- rc = RPMERR_SETCAP_FAILED; ++ ++ if (fd >= 0) { ++ if (fcaps == NULL || cap_set_fd(fd, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; ++ } else { ++ if (fcaps == NULL || cap_set_fileat(dirfd, path, fcaps)) ++ rc = RPMERR_SETCAP_FAILED; + } ++ + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- path, captxt, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %s) %s\n", __func__, ++ fd, dirfd, path, captxt, (rc < 0 ? strerror(errno) : "")); + } + cap_free(fcaps); + } +@@ -211,101 +134,104 @@ + return rc; + } + +-static void wfd_close(FD_t *wfdp) ++static int fsmClose(int *wfdp) + { +- if (wfdp && *wfdp) { ++ int rc = 0; ++ if (wfdp && *wfdp >= 0) { + int myerrno = errno; + static int oneshot = 0; + static int flush_io = 0; ++ int fdno = *wfdp; ++ + if (!oneshot) { + flush_io = (rpmExpandNumeric("%{?_flush_io}") > 0); + oneshot = 1; + } + if (flush_io) { +- int fdno = Fileno(*wfdp); + fsync(fdno); + } +- Fclose(*wfdp); +- *wfdp = NULL; ++ if (close(fdno)) ++ rc = RPMERR_CLOSE_FAILED; ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__, ++ fdno, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = -1; + errno = myerrno; + } ++ return rc; + } + +-static int wfd_open(FD_t *wfdp, const char *dest) ++static int fsmOpen(int *wfdp, int dirfd, const char *dest) + { + int rc = 0; + /* Create the file with 0200 permissions (write by owner). */ +- { +- mode_t old_umask = umask(0577); +- *wfdp = Fopen(dest, "wx.ufdio"); +- umask(old_umask); +- } +- if (Ferror(*wfdp)) { ++ int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200); ++ ++ if (fd < 0) + rc = RPMERR_OPEN_FAILED; +- goto exit; +- } + +- return 0; ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__, ++ dest, fd, (rc < 0 ? strerror(errno) : "")); ++ } ++ *wfdp = fd; + +-exit: +- wfd_close(wfdp); + return rc; + } + +-/** \ingroup payload +- * Create file from payload stream. +- * @return 0 on success +- */ +-static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) ++static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest) + { +- FD_t wfd = NULL; +- int rc; +- +- rc = wfd_open(&wfd, dest); +- if (rc != 0) +- goto exit; +- +- rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm); +- wfd_close(&wfd); +-exit: ++ FD_t fd = fdDup(fdno); ++ int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm); ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s %" PRIu64 " bytes [%d]) %s\n", __func__, ++ rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd), ++ (rc < 0 ? strerror(errno) : "")); ++ } ++ Fclose(fd); + return rc; + } + +-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, +- rpmpsm psm, int nodigest, int *setmeta, +- int * firsthardlink, FD_t *firstlinkfile) ++static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files, ++ rpmpsm psm, int nodigest, ++ struct filedata_s ** firstlink, int *firstlinkfile, ++ int *firstdir, int *fdp) + { + int rc = 0; +- int numHardlinks = rpmfiFNlink(fi); ++ int fd = -1; + +- if (numHardlinks > 1) { +- /* Create first hardlinked file empty */ +- if (*firsthardlink < 0) { +- *firsthardlink = rpmfiFX(fi); +- rc = wfd_open(firstlinkfile, dest); +- } else { +- /* Create hard links for others */ +- char *fn = rpmfilesFN(files, *firsthardlink); +- rc = link(fn, dest); +- if (rc < 0) { +- rc = RPMERR_LINK_FAILED; +- } +- free(fn); ++ if (*firstlink == NULL) { ++ /* First encounter, open file for writing */ ++ rc = fsmOpen(&fd, dirfd, fp->fpath); ++ /* If it's a part of a hardlinked set, the content may come later */ ++ if (fp->sb.st_nlink > 1) { ++ *firstlink = fp; ++ *firstlinkfile = fd; ++ *firstdir = dup(dirfd); ++ } ++ } else { ++ /* Create hard links for others and avoid redundant metadata setting */ ++ if (*firstlink != fp) { ++ rc = fsmLink(*firstdir, (*firstlink)->fpath, dirfd, fp->fpath); + } ++ fd = *firstlinkfile; + } +- /* Write normal files or fill the last hardlinked (already +- existing) file with content */ +- if (numHardlinks<=1) { +- if (!rc) +- rc = expandRegular(fi, dest, psm, nodigest); +- } else if (rpmfiArchiveHasContent(fi)) { ++ ++ /* If the file has content, unpack it */ ++ if (rpmfiArchiveHasContent(fi)) { + if (!rc) +- rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); +- wfd_close(firstlinkfile); +- *firsthardlink = -1; +- } else { +- *setmeta = 0; ++ rc = fsmUnpack(fi, fd, psm, nodigest); ++ /* Last file of hardlink set, ensure metadata gets set */ ++ if (*firstlink) { ++ fp->setmeta = 1; ++ *firstlink = NULL; ++ *firstlinkfile = -1; ++ fsmClose(firstdir); ++ } + } ++ *fdp = fd; + + return rc; + } +@@ -330,18 +256,15 @@ + return rc; + } + +-static int fsmStat(const char *path, int dolstat, struct stat *sb) ++static int fsmStat(int dirfd, const char *path, int dolstat, struct stat *sb) + { +- int rc; +- if (dolstat){ +- rc = lstat(path, sb); +- } else { +- rc = stat(path, sb); +- } ++ int flags = dolstat ? AT_SYMLINK_NOFOLLOW : 0; ++ int rc = fstatat(dirfd, path, sb, flags); ++ + if (_fsm_debug && rc && errno != ENOENT) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, ost) %s\n", + __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) { + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED); + /* Ensure consistent struct content on failure */ +@@ -350,12 +273,12 @@ + return rc; + } + +-static int fsmRmdir(const char *path) ++static int fsmRmdir(int dirfd, const char *path) + { +- int rc = rmdir(path); ++ int rc = unlinkat(dirfd, path, AT_REMOVEDIR); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + switch (errno) { + case ENOENT: rc = RPMERR_ENOENT; break; +@@ -365,148 +288,194 @@ + return rc; + } + +-static int fsmMkdir(const char *path, mode_t mode) ++static int fsmMkdir(int dirfd, const char *path, mode_t mode) + { +- int rc = mkdir(path, (mode & 07777)); ++ int rc = mkdirat(dirfd, path, (mode & 07777)); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", __func__, ++ dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_MKDIR_FAILED; + return rc; + } + +-static int fsmMkfifo(const char *path, mode_t mode) ++static int fsmOpenat(int dirfd, const char *path, int flags, int dir) + { +- int rc = mkfifo(path, (mode & 07777)); +- +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", +- __func__, path, (unsigned)(mode & 07777), +- (rc < 0 ? strerror(errno) : "")); ++ struct stat lsb, sb; ++ int sflags = flags | O_NOFOLLOW; ++ int fd = openat(dirfd, path, sflags); ++ ++ /* ++ * Only ever follow symlinks by root or target owner. Since we can't ++ * open the symlink itself, the order matters: we stat the link *after* ++ * opening the target, and if the link ownership changed between the calls ++ * it could've only been the link owner or root. ++ */ ++ if (fd < 0 && errno == ELOOP && flags != sflags) { ++ int ffd = openat(dirfd, path, flags); ++ if (ffd >= 0) { ++ if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) { ++ if (fstat(ffd, &sb) == 0) { ++ if (lsb.st_uid == 0 || lsb.st_uid == sb.st_uid) { ++ fd = ffd; ++ } ++ } ++ } ++ if (ffd != fd) ++ close(ffd); ++ } + } + +- if (rc < 0) +- rc = RPMERR_MKFIFO_FAILED; +- +- return rc; ++ /* O_DIRECTORY equivalent */ ++ if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) { ++ errno = ENOTDIR; ++ fsmClose(&fd); ++ } ++ return fd; + } + +-static int fsmMknod(const char *path, mode_t mode, dev_t dev) ++static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn, ++ const char *apath, ++ int owned, mode_t mode, int *fdp) + { +- /* FIX: check S_IFIFO or dev != 0 */ +- int rc = mknod(path, (mode & ~07777), dev); ++ int rc; ++ rpmFsmOp op = (FA_CREATE); ++ if (!owned) ++ op |= FAF_UNOWNED; + +- if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", +- __func__, path, (unsigned)(mode & ~07777), +- (unsigned)dev, (rc < 0 ? strerror(errno) : "")); ++ /* Run fsm file pre hook for all plugins */ ++ rc = rpmpluginsCallFsmFilePre(plugins, NULL, apath, mode, op); ++ ++ if (!rc) ++ rc = fsmMkdir(dirfd, dn, mode); ++ ++ if (!rc) { ++ *fdp = fsmOpenat(dirfd, dn, O_RDONLY|O_NOFOLLOW, 1); ++ if (*fdp == -1) ++ rc = RPMERR_ENOTDIR; + } + +- if (rc < 0) +- rc = RPMERR_MKNOD_FAILED; ++ if (!rc) { ++ rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, *fdp, apath, apath, mode, op); ++ } ++ ++ /* Run fsm file post hook for all plugins */ ++ rpmpluginsCallFsmFilePost(plugins, NULL, apath, mode, op, rc); ++ ++ if (!rc) { ++ rpmlog(RPMLOG_DEBUG, ++ "%s directory created with perms %04o\n", ++ apath, (unsigned)(mode & 07777)); ++ } + + return rc; + } + +-/** +- * Create (if necessary) directories not explicitly included in package. +- * @param files file data +- * @param fs file states +- * @param plugins rpm plugins handle +- * @return 0 on success +- */ +-static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins) ++static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create, ++ int quiet, int *dirfdp) + { +- DNLI_t dnli = dnlInitIterator(files, fs, 0); +- struct stat sb; +- const char *dpath; ++ char *sp = NULL, *bn; ++ char *apath = NULL; ++ int oflags = O_RDONLY; + int rc = 0; +- int i; +- size_t ldnlen = 0; +- const char * ldn = NULL; +- +- while ((dpath = dnlNextIterator(dnli)) != NULL) { +- size_t dnlen = strlen(dpath); +- char * te, dn[dnlen+1]; + +- if (dnlen <= 1) +- continue; ++ if (*dirfdp >= 0) ++ return rc; + +- if (dnlen == ldnlen && rstreq(dpath, ldn)) +- continue; ++ int dirfd = fsmOpenat(-1, "/", oflags, 1); ++ int fd = dirfd; /* special case of "/" */ + +- /* Copy as we need to modify the string */ +- (void) stpcpy(dn, dpath); ++ char *path = xstrdup(p); ++ char *dp = path; + +- /* Assume '/' directory exists, "mkdir -p" for others if non-existent */ +- for (i = 1, te = dn + 1; *te != '\0'; te++, i++) { +- if (*te != '/') +- continue; ++ while ((bn = strtok_r(dp, "/", &sp)) != NULL) { ++ fd = fsmOpenat(dirfd, bn, oflags, 1); ++ /* assemble absolute path for plugins benefit, sigh */ ++ apath = rstrscat(&apath, "/", bn, NULL); ++ ++ if (fd < 0 && errno == ENOENT && create) { ++ mode_t mode = S_IFDIR | (_dirPerms & 07777); ++ rc = fsmDoMkDir(plugins, dirfd, bn, apath, owned, mode, &fd); ++ } + +- /* Already validated? */ +- if (i < ldnlen && +- (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i)) +- continue; ++ fsmClose(&dirfd); ++ if (fd >= 0) { ++ dirfd = fd; ++ } else { ++ if (!quiet) { ++ rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"), ++ bn, p, strerror(errno)); ++ } ++ rc = RPMERR_OPEN_FAILED; ++ break; ++ } + +- /* Validate next component of path. */ +- *te = '\0'; +- rc = fsmStat(dn, 1, &sb); /* lstat */ +- *te = '/'; ++ dp = NULL; ++ } + +- /* Directory already exists? */ +- if (rc == 0 && S_ISDIR(sb.st_mode)) { +- continue; +- } else if (rc == RPMERR_ENOENT) { +- *te = '\0'; +- mode_t mode = S_IFDIR | (_dirPerms & 07777); +- rpmFsmOp op = (FA_CREATE|FAF_UNOWNED); +- +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op); +- +- if (!rc) +- rc = fsmMkdir(dn, mode); +- +- if (!rc) { +- rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn, +- mode, op); +- } ++ if (rc) { ++ fsmClose(&fd); ++ fsmClose(&dirfd); ++ } else { ++ rc = 0; ++ } ++ *dirfdp = dirfd; + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc); ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%s: %d) %s\n", __func__, ++ p, dirfd, (rc < 0 ? strerror(errno) : "")); ++ } + +- if (!rc) { +- rpmlog(RPMLOG_DEBUG, +- "%s directory created with perms %04o\n", +- dn, (unsigned)(mode & 07777)); +- } +- *te = '/'; +- } +- if (rc) +- break; +- } +- if (rc) break; ++ free(path); ++ free(apath); ++ return rc; ++} + +- /* Save last validated path. */ +- ldn = dpath; +- ldnlen = dnlen; ++static int fsmMkfifo(int dirfd, const char *path, mode_t mode) ++{ ++ int rc = mkfifoat(dirfd, path, (mode & 07777)); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & 07777), ++ (rc < 0 ? strerror(errno) : "")); + } +- dnlFreeIterator(dnli); ++ ++ if (rc < 0) ++ rc = RPMERR_MKFIFO_FAILED; + + return rc; + } + +-static void removeSBITS(const char *path) ++static int fsmMknod(int dirfd, const char *path, mode_t mode, dev_t dev) ++{ ++ /* FIX: check S_IFIFO or dev != 0 */ ++ int rc = mknodat(dirfd, path, (mode & ~07777), dev); ++ ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%o, 0x%x) %s\n", ++ __func__, dirfd, path, (unsigned)(mode & ~07777), ++ (unsigned)dev, (rc < 0 ? strerror(errno) : "")); ++ } ++ ++ if (rc < 0) ++ rc = RPMERR_MKNOD_FAILED; ++ ++ return rc; ++} ++ ++static void removeSBITS(int dirfd, const char *path) + { + struct stat stb; +- if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) { ++ /* We now know it's not a link so no need to worry about following */ + if ((stb.st_mode & 06000) != 0) { +- (void) chmod(path, stb.st_mode & 0777); ++ (void) fchmodat(dirfd, path, stb.st_mode & 0777, 0); + } +-#if WITH_CAP ++#ifdef WITH_CAP + if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { +- (void) cap_set_file(path, NULL); ++ (void) cap_set_fileat(dirfd, path, NULL); + } + #endif + } +@@ -522,13 +491,13 @@ + (fpath ? fpath : "")); + } + +-static int fsmSymlink(const char *opath, const char *path) ++static int fsmSymlink(const char *opath, int dirfd, const char *path) + { +- int rc = symlink(opath, path); ++ int rc = symlinkat(opath, dirfd, path); + + if (_fsm_debug) { +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%s, %d %s) %s\n", __func__, ++ opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + } + + if (rc < 0) +@@ -536,96 +505,125 @@ + return rc; + } + +-static int fsmUnlink(const char *path) ++static int fsmUnlink(int dirfd, const char *path) + { + int rc = 0; +- removeSBITS(path); +- rc = unlink(path); ++ removeSBITS(dirfd, path); ++ rc = unlinkat(dirfd, path, 0); + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__, +- path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__, ++ dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED); + return rc; + } + +-static int fsmRename(const char *opath, const char *path) ++static int fsmRename(int odirfd, const char *opath, int dirfd, const char *path) + { +- removeSBITS(path); +- int rc = rename(opath, path); ++ removeSBITS(dirfd, path); ++ int rc = renameat(odirfd, opath, dirfd, path); + #if defined(ETXTBSY) && defined(__HPUX__) + /* XXX HP-UX (and other os'es) don't permit rename to busy files. */ + if (rc && errno == ETXTBSY) { + char *rmpath = NULL; + rstrscat(&rmpath, path, "-RPMDELETE", NULL); +- rc = rename(path, rmpath); +- if (!rc) rc = rename(opath, path); ++ /* Rename within the original directory */ ++ rc = renameat(odirfd, path, odirfd, rmpath); ++ if (!rc) rc = renameat(odirfd, opath, dirfd, path); + free(rmpath); + } + #endif + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__, +- opath, path, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__, ++ odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) + rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED); + return rc; + } + +-static int fsmRemove(const char *path, mode_t mode) ++static int fsmRemove(int dirfd, const char *path, mode_t mode) + { +- return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path); ++ return S_ISDIR(mode) ? fsmRmdir(dirfd, path) : fsmUnlink(dirfd, path); + } + +-static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid) ++static int fsmChown(int fd, int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid) + { +- int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid) +- rc = 0; ++ int rc; ++ struct stat st; ++ ++ if (fd >= 0) { ++ rc = fchown(fd, uid, gid); ++ if (rc < 0) { ++ if (fstat(fd, &st) == 0 && (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } ++ } else { ++ int flags = AT_SYMLINK_NOFOLLOW; ++ rc = fchownat(dirfd, path, uid, gid, flags); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, flags) == 0 && ++ (st.st_uid == uid && st.st_gid == gid)) { ++ rc = 0; ++ } ++ } + } +- if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__, +- path, (int)uid, (int)gid, ++ if (_fsm_debug) { ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %d, %d) %s\n", __func__, ++ fd, dirfd, path, (int)uid, (int)gid, + (rc < 0 ? strerror(errno) : "")); ++ } + if (rc < 0) rc = RPMERR_CHOWN_FAILED; + return rc; + } + +-static int fsmChmod(const char *path, mode_t mode) ++static int fsmChmod(int fd, int dirfd, const char *path, mode_t mode) + { +- int rc = chmod(path, (mode & 07777)); +- if (rc < 0) { +- struct stat st; +- if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777)) +- rc = 0; ++ mode_t fmode = (mode & 07777); ++ int rc; ++ if (fd >= 0) { ++ rc = fchmod(fd, fmode); ++ if (rc < 0) { ++ struct stat st; ++ if (fstat(fd, &st) == 0 && (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } ++ } else { ++ rc = fchmodat(dirfd, path, fmode, 0); ++ if (rc < 0) { ++ struct stat st; ++ if (fstatat(dirfd, path, &st, AT_SYMLINK_NOFOLLOW) == 0 && ++ (st.st_mode & 07777) == fmode) { ++ rc = 0; ++ } ++ } + } + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__, +- path, (unsigned)(mode & 07777), ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0%04o) %s\n", __func__, ++ fd, dirfd, path, (unsigned)(mode & 07777), + (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_CHMOD_FAILED; + return rc; + } + +-static int fsmUtime(const char *path, mode_t mode, time_t mtime) ++static int fsmUtime(int fd, int dirfd, const char *path, mode_t mode, time_t mtime) + { + int rc = 0; +- struct timeval stamps[2] = { +- { .tv_sec = mtime, .tv_usec = 0 }, +- { .tv_sec = mtime, .tv_usec = 0 }, ++ struct timespec stamps[2] = { ++ { .tv_sec = mtime, .tv_nsec = 0 }, ++ { .tv_sec = mtime, .tv_nsec = 0 }, + }; + +-#if HAVE_LUTIMES +- rc = lutimes(path, stamps); +-#else +- if (!S_ISLNK(mode)) +- rc = utimes(path, stamps); +-#endif ++ if (fd >= 0) ++ rc = futimens(fd, stamps); ++ else ++ rc = utimensat(dirfd, path, stamps, AT_SYMLINK_NOFOLLOW); + + if (_fsm_debug) +- rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__, +- path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); ++ rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0x%x) %s\n", __func__, ++ fd, dirfd, path, (unsigned)mtime, (rc < 0 ? strerror(errno) : "")); + if (rc < 0) rc = RPMERR_UTIME_FAILED; + /* ...but utime error is not critical for directories */ + if (rc && S_ISDIR(mode)) +@@ -633,24 +631,24 @@ + return rc; + } + +-static int fsmVerify(const char *path, rpmfi fi) ++static int fsmVerify(int dirfd, const char *path, rpmfi fi) + { + int rc; + int saveerrno = errno; + struct stat dsb; + mode_t mode = rpmfiFMode(fi); + +- rc = fsmStat(path, 1, &dsb); ++ rc = fsmStat(dirfd, path, 1, &dsb); + if (rc) + return rc; + + if (S_ISREG(mode)) { + /* HP-UX (and other os'es) don't permit unlink on busy files. */ + char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL); +- rc = fsmRename(path, rmpath); ++ rc = fsmRename(dirfd, path, dirfd, rmpath); + /* XXX shouldn't we take unlink return code here? */ + if (!rc) +- (void) fsmUnlink(rmpath); ++ (void) fsmUnlink(dirfd, rmpath); + else + rc = RPMERR_UNLINK_FAILED; + free(rmpath); +@@ -659,7 +657,7 @@ + if (S_ISDIR(dsb.st_mode)) return 0; + if (S_ISLNK(dsb.st_mode)) { + uid_t luid = dsb.st_uid; +- rc = fsmStat(path, 0, &dsb); ++ rc = fsmStat(dirfd, path, 0, &dsb); + if (rc == RPMERR_ENOENT) rc = 0; + if (rc) return rc; + errno = saveerrno; +@@ -685,7 +683,7 @@ + if (S_ISSOCK(dsb.st_mode)) return 0; + } + /* XXX shouldn't do this with commit/undo. */ +- rc = fsmUnlink(path); ++ rc = fsmUnlink(dirfd, path); + if (rc == 0) rc = RPMERR_ENOENT; + return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */ + } +@@ -699,7 +697,7 @@ + + + /* Rename pre-existing modified or unmanaged file. */ +-static int fsmBackup(rpmfi fi, rpmFileAction action) ++static int fsmBackup(int dirfd, rpmfi fi, rpmFileAction action) + { + int rc = 0; + const char *suffix = NULL; +@@ -720,9 +718,10 @@ + if (suffix) { + char * opath = fsmFsPath(fi, NULL); + char * path = fsmFsPath(fi, suffix); +- rc = fsmRename(opath, path); ++ rc = fsmRename(dirfd, opath, dirfd, path); + if (!rc) { +- rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path); ++ rpmlog(RPMLOG_WARNING, _("%s%s saved as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), path); + } + free(path); + free(opath); +@@ -730,7 +729,8 @@ + return rc; + } + +-static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins, ++static int fsmSetmeta(int fd, int dirfd, const char *path, ++ rpmfi fi, rpmPlugins plugins, + rpmFileAction action, const struct stat * st, + int nofcaps) + { +@@ -738,27 +738,28 @@ + const char *dest = rpmfiFN(fi); + + if (!rc && !getuid()) { +- rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid); ++ rc = fsmChown(fd, dirfd, path, st->st_mode, st->st_uid, st->st_gid); + } + if (!rc && !S_ISLNK(st->st_mode)) { +- rc = fsmChmod(path, st->st_mode); ++ rc = fsmChmod(fd, dirfd, path, st->st_mode); + } + /* Set file capabilities (if enabled) */ + if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) { +- rc = fsmSetFCaps(path, rpmfiFCaps(fi)); ++ rc = fsmSetFCaps(fd, dirfd, path, rpmfiFCaps(fi)); + } + if (!rc) { +- rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi)); ++ rc = fsmUtime(fd, dirfd, path, st->st_mode, rpmfiFMtime(fi)); + } + if (!rc) { + rc = rpmpluginsCallFsmFilePrepare(plugins, fi, +- path, dest, st->st_mode, action); ++ fd, path, dest, ++ st->st_mode, action); + } + + return rc; + } + +-static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix) ++static int fsmCommit(int dirfd, char **path, rpmfi fi, rpmFileAction action, const char *suffix) + { + int rc = 0; + +@@ -772,15 +773,18 @@ + + /* Rename temporary to final file name if needed. */ + if (dest != *path) { +- rc = fsmRename(*path, dest); +- if (!rc && nsuffix) { +- char * opath = fsmFsPath(fi, NULL); +- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), +- opath, dest); +- free(opath); +- } +- free(*path); +- *path = dest; ++ rc = fsmRename(dirfd, *path, dirfd, dest); ++ if (!rc) { ++ if (nsuffix) { ++ char * opath = fsmFsPath(fi, NULL); ++ rpmlog(RPMLOG_WARNING, _("%s%s created as %s%s\n"), ++ rpmfiDN(fi), opath, rpmfiDN(fi), dest); ++ free(opath); ++ } ++ free(*path); ++ *path = dest; ++ } else ++ free(dest); + } + } + +@@ -831,191 +835,277 @@ + } + } + ++struct diriter_s { ++ int dirfd; ++ int firstdir; ++}; ++ ++static int onChdir(rpmfi fi, void *data) ++{ ++ struct diriter_s *di = data; ++ ++ fsmClose(&(di->dirfd)); ++ return 0; ++} ++ ++static rpmfi fsmIter(FD_t payload, rpmfiles files, rpmFileIter iter, void *data) ++{ ++ rpmfi fi; ++ if (payload) ++ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ else ++ fi = rpmfilesIter(files, iter); ++ if (fi && data) ++ rpmfiSetOnChdir(fi, onChdir, data); ++ return fi; ++} ++ ++static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di) ++{ ++ fsmClose(&(di->dirfd)); ++ fsmClose(&(di->firstdir)); ++ return rpmfiFree(fi); ++} ++ + int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { + FD_t payload = rpmtePayload(te); +- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ rpmfi fi = NULL; + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; +- int saveerrno = errno; + int rc = 0; ++ int fx = -1; ++ int fc = rpmfilesFC(files); + int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; + int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; +- int firsthardlink = -1; +- FD_t firstlinkfile = NULL; +- int skip; +- rpmFileAction action; ++ int firstlinkfile = -1; + char *tid = NULL; +- const char *suffix; +- char *fpath = NULL; +- +- if (fi == NULL) { +- rc = RPMERR_BAD_MAGIC; +- goto exit; +- } ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); ++ struct filedata_s *firstlink = NULL; ++ struct diriter_s di = { -1, -1 }; + + /* transaction id used for temporary path suffix while installing */ + rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); + +- /* Detect and create directories not explicitly in package. */ +- rc = fsmMkdirs(files, fs, plugins); ++ /* Collect state data for the whole operation */ ++ fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ if (rpmfiFFlags(fi) & RPMFILE_GHOST) ++ fp->action = FA_SKIP; ++ else ++ fp->action = rpmfsGetAction(fs, fx); ++ fp->skip = XFA_SKIPPING(fp->action); ++ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) ++ fp->suffix = tid; ++ fp->fpath = fsmFsPath(fi, fp->suffix); + +- while (!rc) { +- /* Read next payload header. */ +- rc = rpmfiNext(fi); ++ /* Remap file perms, owner, and group. */ ++ rc = rpmfiStat(fi, 1, &fp->sb); + +- if (rc < 0) { +- if (rc == RPMERR_ITER_END) +- rc = 0; +- break; +- } ++ /* Hardlinks are tricky and handled elsewhere for install */ ++ fp->setmeta = (fp->skip == 0) && ++ (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH); + +- action = rpmfsGetAction(fs, rpmfiFX(fi)); +- skip = XFA_SKIPPING(action); +- if (action != FA_TOUCH) { +- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; +- } else { +- suffix = NULL; +- } +- fpath = fsmFsPath(fi, suffix); ++ setFileState(fs, fx); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + +- /* Remap file perms, owner, and group. */ +- rc = rpmfiStat(fi, 1, &sb); ++ fp->stage = FILE_PRE; ++ } ++ fi = rpmfiFree(fi); + +- fsmDebug(fpath, action, &sb); ++ if (rc) ++ goto exit; + +- /* Exit on error. */ +- if (rc) +- break; ++ fi = fsmIter(payload, files, ++ payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); + +- /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); +- if (rc) { +- skip = 1; +- } else { +- setFileState(fs, rpmfiFX(fi)); +- } ++ if (fi == NULL) { ++ rc = RPMERR_BAD_MAGIC; ++ goto exit; ++ } + +- if (!skip) { +- int setmeta = 1; ++ /* Process the payload */ ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* ++ * Tricksy case: this file is a being skipped, but it's part of ++ * a hardlinked set and has the actual content linked with it. ++ * Write the content to the first non-skipped file of the set ++ * instead. ++ */ ++ if (fp->skip && firstlink && rpmfiArchiveHasContent(fi)) ++ fp = firstlink; ++ ++ if (!fp->skip) { ++ int mayopen = 0; ++ int fd = -1; ++ rc = ensureDir(plugins, rpmfiDN(fi), 0, ++ (fp->action == FA_CREATE), 0, &di.dirfd); + + /* Directories replacing something need early backup */ +- if (!suffix) { +- rc = fsmBackup(fi, action); ++ if (!rc && !fp->suffix && fp != firstlink) { ++ rc = fsmBackup(di.dirfd, fi, fp->action); + } ++ ++ /* Run fsm file pre hook for all plugins */ ++ if (!rc) ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); ++ if (rc) ++ goto setmeta; /* for error notification */ ++ + /* Assume file does't exist when tmp suffix is in use */ +- if (!suffix) { +- rc = fsmVerify(fpath, fi); ++ if (!fp->suffix) { ++ if (fp->action == FA_TOUCH) { ++ struct stat sb; ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &sb); ++ } else { ++ rc = fsmVerify(di.dirfd, fp->fpath, fi); ++ } + } else { + rc = RPMERR_ENOENT; + } + + /* See if the file was removed while our attention was elsewhere */ +- if (rc == RPMERR_ENOENT && action == FA_TOUCH) { +- rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); +- action = FA_CREATE; +- fsmDebug(fpath, action, &sb); ++ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { ++ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", ++ fp->fpath); ++ fp->action = FA_CREATE; ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + } + + /* When touching we don't need any of this... */ +- if (action == FA_TOUCH) +- goto touch; ++ if (fp->action == FA_TOUCH) ++ goto setmeta; + +- if (S_ISREG(sb.st_mode)) { ++ if (S_ISREG(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfile(fi, fpath, files, psm, nodigest, +- &setmeta, &firsthardlink, &firstlinkfile); ++ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile, &di.firstdir, ++ &fd); + } +- } else if (S_ISDIR(sb.st_mode)) { ++ } else if (S_ISDIR(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- mode_t mode = sb.st_mode; ++ mode_t mode = fp->sb.st_mode; + mode &= ~07777; + mode |= 00700; +- rc = fsmMkdir(fpath, mode); ++ rc = fsmMkdir(di.dirfd, fp->fpath, mode); + } +- } else if (S_ISLNK(sb.st_mode)) { ++ } else if (S_ISLNK(fp->sb.st_mode)) { + if (rc == RPMERR_ENOENT) { +- rc = fsmSymlink(rpmfiFLink(fi), fpath); ++ rc = fsmSymlink(rpmfiFLink(fi), di.dirfd, fp->fpath); + } +- } else if (S_ISFIFO(sb.st_mode)) { ++ } else if (S_ISFIFO(fp->sb.st_mode)) { + /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ + if (rc == RPMERR_ENOENT) { +- rc = fsmMkfifo(fpath, 0000); ++ rc = fsmMkfifo(di.dirfd, fp->fpath, 0000); + } +- } else if (S_ISCHR(sb.st_mode) || +- S_ISBLK(sb.st_mode) || +- S_ISSOCK(sb.st_mode)) ++ } else if (S_ISCHR(fp->sb.st_mode) || ++ S_ISBLK(fp->sb.st_mode) || ++ S_ISSOCK(fp->sb.st_mode)) + { + if (rc == RPMERR_ENOENT) { +- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); ++ rc = fsmMknod(di.dirfd, fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); + } + } else { + /* XXX Special case /dev/log, which shouldn't be packaged anyways */ +- if (!IS_DEV_LOG(fpath)) ++ if (!IS_DEV_LOG(fp->fpath)) + rc = RPMERR_UNKNOWN_FILETYPE; + } + +-touch: +- /* Set permissions, timestamps etc for non-hardlink entries */ +- if (!rc && setmeta) { +- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); ++setmeta: ++ /* Special files require path-based ops */ ++ mayopen = S_ISREG(fp->sb.st_mode) || S_ISDIR(fp->sb.st_mode); ++ if (!rc && fd == -1 && mayopen) { ++ int flags = O_RDONLY; ++ /* Only follow safe symlinks, and never on temporary files */ ++ if (fp->suffix) ++ flags |= AT_SYMLINK_NOFOLLOW; ++ fd = fsmOpenat(di.dirfd, fp->fpath, flags, ++ S_ISDIR(fp->sb.st_mode)); ++ if (fd < 0) ++ rc = RPMERR_OPEN_FAILED; + } +- } 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); +- rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); +- wfd_close(&firstlinkfile); +- firsthardlink = -1; +- free(fn); +- } +- +- if (rc) { +- if (!skip) { +- /* XXX only erase if temp fn w suffix is in use */ +- if (suffix) { +- (void) fsmRemove(fpath, sb.st_mode); +- } +- errno = saveerrno; +- } +- } else { +- /* Notify on success. */ +- rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); + +- if (!skip) { +- /* Backup file if needed. Directories are handled earlier */ +- if (suffix) +- rc = fsmBackup(fi, action); +- +- if (!rc) +- rc = fsmCommit(&fpath, fi, action, suffix); ++ if (!rc && fp->setmeta) { ++ rc = fsmSetmeta(fd, di.dirfd, fp->fpath, ++ fi, plugins, fp->action, ++ &fp->sb, nofcaps); + } ++ ++ if (fd != firstlinkfile) ++ fsmClose(&fd); + } + ++ /* Notify on success. */ + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ else ++ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); ++ fp->stage = FILE_UNPACK; ++ } ++ fi = fsmIterFini(fi, &di); + +- /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); +- fpath = _free(fpath); ++ if (!rc && fx < 0 && fx != RPMERR_ITER_END) ++ rc = fx; ++ ++ /* If all went well, commit files to final destination */ ++ fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ if (!fp->skip) { ++ if (!rc) ++ rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd); ++ ++ /* Backup file if needed. Directories are handled earlier */ ++ if (!rc && fp->suffix) ++ rc = fsmBackup(di.dirfd, fi, fp->action); ++ ++ if (!rc) ++ rc = fsmCommit(di.dirfd, &fp->fpath, fi, fp->action, fp->suffix); ++ ++ if (!rc) ++ fp->stage = FILE_COMMIT; ++ else ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); ++ ++ /* Run fsm file post hook for all plugins for all processed files */ ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); ++ } ++ } ++ fi = fsmIterFini(fi, &di); ++ ++ /* On failure, walk backwards and erase non-committed files */ ++ if (rc) { ++ fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); ++ while ((fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ if (fp->stage > FILE_NONE && !fp->skip) { ++ (void) fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); ++ } ++ } + } + + rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); + rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); + + exit: +- +- /* No need to bother with close errors on read */ +- rpmfiArchiveClose(fi); +- rpmfiFree(fi); ++ fi = fsmIterFini(fi, &di); + Fclose(payload); + free(tid); +- free(fpath); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); + + return rc; + } +@@ -1024,32 +1114,42 @@ + int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { +- rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); ++ struct diriter_s di = { -1, -1 }; ++ rpmfi fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di); + rpmfs fs = rpmteGetFileStates(te); + rpmPlugins plugins = rpmtsPlugins(ts); +- struct stat sb; ++ int fc = rpmfilesFC(files); ++ int fx = -1; ++ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); + int rc = 0; +- char *fpath = NULL; + +- while (!rc && rpmfiNext(fi) >= 0) { +- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); +- fpath = fsmFsPath(fi, NULL); +- rc = fsmStat(fpath, 1, &sb); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { ++ struct filedata_s *fp = &fdata[fx]; ++ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); ++ ++ if (XFA_SKIPPING(fp->action)) ++ continue; ++ ++ fp->fpath = fsmFsPath(fi, NULL); ++ /* If the directory doesn't exist there's nothing to clean up */ ++ if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd)) ++ continue; ++ ++ rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb); + +- fsmDebug(fpath, action, &sb); ++ fsmDebug(fp->fpath, fp->action, &fp->sb); + + /* Run fsm file pre hook for all plugins */ +- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, +- sb.st_mode, action); ++ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action); + +- if (!XFA_SKIPPING(action)) +- rc = fsmBackup(fi, action); ++ rc = fsmBackup(di.dirfd, fi, fp->action); + + /* Remove erased files. */ +- if (action == FA_ERASE) { ++ if (fp->action == FA_ERASE) { + int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); + +- rc = fsmRemove(fpath, sb.st_mode); ++ rc = fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode); + + /* + * Missing %ghost or %missingok entries are not errors. +@@ -1074,20 +1174,20 @@ + if (rc) { + int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING; + rpmlog(lvl, _("%s %s: remove failed: %s\n"), +- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), +- fpath, strerror(errno)); ++ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), ++ fp->fpath, strerror(errno)); + } + } + + /* Run fsm file post hook for all plugins */ +- rpmpluginsCallFsmFilePost(plugins, fi, fpath, +- sb.st_mode, action, rc); ++ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, ++ fp->sb.st_mode, fp->action, rc); + + /* XXX Failure to remove is not (yet) cause for failure. */ + if (!strict_erasures) rc = 0; + + if (rc) +- *failedFile = xstrdup(fpath); ++ *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL); + + if (rc == 0) { + /* Notify on success. */ +@@ -1095,11 +1195,12 @@ + rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); + rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); + } +- fpath = _free(fpath); + } + +- free(fpath); +- rpmfiFree(fi); ++ for (int i = 0; i < fc; i++) ++ free(fdata[i].fpath); ++ free(fdata); ++ fsmIterFini(fi, &di); + + return rc; + } diff --git a/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch b/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch new file mode 100644 index 0000000..f66545b --- /dev/null +++ b/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch @@ -0,0 +1,32 @@ +From 97aa64d8281974fb369c66d5aef8650515b89c52 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 24 Jan 2024 12:03:39 +0200 +Subject: [PATCH] Use unsigned integers for buildtime too for Y2K38 safety + +This little patch buys us 68 extra years to move to 64bit time tags +in rpm. That seems achievable. + +Fixes: #1228 +--- + build/build.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/build/build.c b/build/build.c +index e4081c673..0ac8bf6c9 100644 +--- a/build/build.c ++++ b/build/build.c +@@ -36,9 +36,9 @@ static rpm_time_t getBuildTime(void) + if (srcdate == endptr || *endptr || errno != 0) + rpmlog(RPMLOG_ERR, _("unable to parse SOURCE_DATE_EPOCH\n")); + else +- buildTime = (int32_t) epoch; ++ buildTime = (uint32_t) epoch; + } else +- buildTime = (int32_t) time(NULL); ++ buildTime = (uint32_t) time(NULL); + + return buildTime; + } +-- +2.45.1 + diff --git a/0002-Remove-use-of-bool-type-for-consistency.patch b/0002-Remove-use-of-bool-type-for-consistency.patch index 5867127..5b1e7ad 100644 --- a/0002-Remove-use-of-bool-type-for-consistency.patch +++ b/0002-Remove-use-of-bool-type-for-consistency.patch @@ -4,23 +4,32 @@ Date: Sun, 31 Jan 2021 12:30:33 -0800 Subject: [PATCH 02/30] Remove use of bool type for consistency --- - lib/fsm.c | 9 ++++----- - 1 file changed, 4 insertions(+), 5 deletions(-) + lib/fsm.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/fsm.c b/lib/fsm.c index 90193c749..feda3750c 100644 --- a/lib/fsm.c +++ b/lib/fsm.c @@ -8,7 +8,6 @@ - + #include #include #include -#include - #if WITH_CAP + #include + #ifdef WITH_CAP #include - #endif -@@ -896,10 +895,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - +@@ -56,7 +55,7 @@ struct filedata_s { + int stage; + int setmeta; + int skip; +- bool plugin_contents; ++ int plugin_contents; + rpmFileAction action; + const char *suffix; + char *fpath; +@@ -890,10 +889,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + struct diriter_s di = { -1, -1 }; Header h = rpmteHeader(te); const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT); - bool cpio = true; @@ -32,14 +41,7 @@ index 90193c749..feda3750c 100644 } /* transaction id used for temporary path suffix while installing */ -@@ -927,13 +926,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Run fsm file pre hook for all plugins */ - rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, - fp->sb.st_mode, fp->action); -- fp->plugin_contents = false; -+ fp->plugin_contents = 0; - switch (rc) { - case RPMRC_OK: +@@ -924,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, setFileState(fs, fx); break; case RPMRC_PLUGIN_CONTENTS: @@ -48,6 +50,15 @@ index 90193c749..feda3750c 100644 // reduce reads on cpio to this value. Could be zero if // this is from a hard link. rc = RPMRC_OK; +@@ -986,7 +985,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, + fp->sb.st_mode, fp->action); + if (rc == RPMRC_PLUGIN_CONTENTS) { +- fp->plugin_contents = true; ++ fp->plugin_contents = 1; + rc = RPMRC_OK; + } + } -- 2.35.1 diff --git a/0003-Match-formatting-style-of-existing-code.patch b/0003-Match-formatting-style-of-existing-code.patch index aae1035..f827cd0 100644 --- a/0003-Match-formatting-style-of-existing-code.patch +++ b/0003-Match-formatting-style-of-existing-code.patch @@ -15,28 +15,10 @@ this reformat here and now, and future changes will be after this. I'm keen to fold the patches together, but for now, I'm trying to keep the history of #1470 linear so everyone can follow along. --- - lib/rpmplugins.c | 6 +- plugins/reflink.c | 407 ++++++++++++++++++--------------- rpm2extents.c | 562 ++++++++++++++++++++-------------------------- - 3 files changed, 462 insertions(+), 513 deletions(-) + 2 files changed, 459 insertions(+), 510 deletions(-) -diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index c5084d398..3da3097af 100644 ---- a/lib/rpmplugins.c -+++ b/lib/rpmplugins.c -@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, - rc = RPMRC_FAIL; - } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) { - if (rc == RPMRC_PLUGIN_CONTENTS) { -- /* -- Another plugin already said it'd handle contents. It's undefined how -- these would combine, so treat this as a failure condition. -+ /* Another plugin already said it'd handle contents. It's -+ * undefined how these would combine, so treat this as a -+ * failure condition. - */ - rc = RPMRC_FAIL; - } else { diff --git a/plugins/reflink.c b/plugins/reflink.c index d7f19acd9..9eaa87094 100644 --- a/plugins/reflink.c diff --git a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch index ff335d7..d41aeb3 100644 --- a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch +++ b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch @@ -63,7 +63,7 @@ diff --git a/tests/rpmtests.at b/tests/rpmtests.at index a1adab8e0..205fed6a3 100644 --- a/tests/rpmtests.at +++ b/tests/rpmtests.at -@@ -21,3 +21,4 @@ m4_include([rpmreplace.at]) +@@ -22,3 +22,4 @@ m4_include([rpmreplace.at]) m4_include([rpmconfig.at]) m4_include([rpmconfig2.at]) m4_include([rpmconfig3.at]) diff --git a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch index a0e9757..150ba8a 100644 --- a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch +++ b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch @@ -15,7 +15,7 @@ diff --git a/Makefile.am b/Makefile.am index 288668819..96542c8c8 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -185,7 +185,7 @@ bin_PROGRAMS += rpmgraph +@@ -203,7 +203,7 @@ bin_PROGRAMS += rpmgraph rpmgraph_SOURCES = tools/rpmgraph.c rpmgraph_LDADD = lib/librpm.la rpmio/librpmio.la @WITH_POPT_LIB@ diff --git a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch index e7b7804..9d19938 100644 --- a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch +++ b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch @@ -19,7 +19,7 @@ diff --git a/lib/Makefile.am b/lib/Makefile.am index 5a1b6ca9b..2f1b3597f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am -@@ -40,7 +40,8 @@ librpm_la_SOURCES = \ +@@ -41,7 +41,8 @@ librpm_la_SOURCES = \ rpmscript.h rpmscript.c \ rpmchroot.c rpmchroot.h \ rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \ diff --git a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch index 56bb554..392e534 100644 --- a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch +++ b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch @@ -5,17 +5,122 @@ Subject: [PATCH 13/30] [plugin] add `plugin_fsm_file_install_func` plugin hook This hook is to be called when installing individual files from the RPM. --- + lib/Makefile.in | 51 ++++++++++++++++++++++++++---------------------- lib/rpmplugin.h | 5 +++++ - lib/rpmplugins.c | 37 +++++++++++++++++++++++++++++++++++++ - lib/rpmplugins.h | 15 +++++++++++++++ - 3 files changed, 57 insertions(+) + lib/rpmplugins.c | 37 +++++++++++++++++++++++++++++++++++ + lib/rpmplugins.h | 15 ++++++++++++++ + 4 files changed, 85 insertions(+), 23 deletions(-) +diff --git a/lib/Makefile.in b/lib/Makefile.in +index e1965d8..c4bba25 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -173,10 +173,11 @@ am__librpm_la_SOURCES_DIST = backend/dbi.c backend/dbi.h \ + rpmlock.c rpmlock.h misc.h relocation.c rpmscript.h \ + rpmscript.c rpmchroot.c rpmchroot.h rpmplugins.c rpmplugins.h \ + rpmplugin.h rpmug.c rpmug.h rpmtriggers.h rpmtriggers.c \ +- rpmvs.c rpmvs.h backend/db3.c backend/bdb_ro.c \ +- backend/ndb/glue.c backend/ndb/rpmpkg.c backend/ndb/rpmpkg.h \ +- backend/ndb/rpmidx.c backend/ndb/rpmidx.h backend/ndb/rpmxdb.c \ +- backend/ndb/rpmxdb.h backend/sqlite.c ++ rpmvs.c rpmvs.h rpmextents.c rpmextents_internal.h \ ++ backend/db3.c backend/bdb_ro.c backend/ndb/glue.c \ ++ backend/ndb/rpmpkg.c backend/ndb/rpmpkg.h backend/ndb/rpmidx.c \ ++ backend/ndb/rpmidx.h backend/ndb/rpmxdb.c backend/ndb/rpmxdb.h \ ++ backend/sqlite.c + am__dirstamp = $(am__leading_dot)dirstamp + @BDB_TRUE@am__objects_1 = backend/db3.lo + @BDB_RO_TRUE@am__objects_2 = backend/bdb_ro.lo +@@ -192,8 +193,8 @@ am_librpm_la_OBJECTS = backend/dbi.lo backend/dummydb.lo \ + rpmlead.lo rpmps.lo rpmprob.lo rpmrc.lo rpmte.lo rpmts.lo \ + rpmfs.lo signature.lo transaction.lo verify.lo rpmlock.lo \ + relocation.lo rpmscript.lo rpmchroot.lo rpmplugins.lo rpmug.lo \ +- rpmtriggers.lo rpmvs.lo $(am__objects_1) $(am__objects_2) \ +- $(am__objects_3) $(am__objects_4) ++ rpmtriggers.lo rpmvs.lo rpmextents.lo $(am__objects_1) \ ++ $(am__objects_2) $(am__objects_3) $(am__objects_4) + librpm_la_OBJECTS = $(am_librpm_la_OBJECTS) + AM_V_lt = $(am__v_lt_@AM_V@) + am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +@@ -228,21 +229,21 @@ am__depfiles_remade = ./$(DEPDIR)/cpio.Plo ./$(DEPDIR)/depends.Plo \ + ./$(DEPDIR)/relocation.Plo ./$(DEPDIR)/rpmal.Plo \ + ./$(DEPDIR)/rpmchecksig.Plo ./$(DEPDIR)/rpmchroot.Plo \ + ./$(DEPDIR)/rpmdb.Plo ./$(DEPDIR)/rpmds.Plo \ +- ./$(DEPDIR)/rpmfi.Plo ./$(DEPDIR)/rpmfs.Plo \ +- ./$(DEPDIR)/rpmgi.Plo ./$(DEPDIR)/rpminstall.Plo \ +- ./$(DEPDIR)/rpmlead.Plo ./$(DEPDIR)/rpmlock.Plo \ +- ./$(DEPDIR)/rpmplugins.Plo ./$(DEPDIR)/rpmprob.Plo \ +- ./$(DEPDIR)/rpmps.Plo ./$(DEPDIR)/rpmrc.Plo \ +- ./$(DEPDIR)/rpmscript.Plo ./$(DEPDIR)/rpmtd.Plo \ +- ./$(DEPDIR)/rpmte.Plo ./$(DEPDIR)/rpmtriggers.Plo \ +- ./$(DEPDIR)/rpmts.Plo ./$(DEPDIR)/rpmug.Plo \ +- ./$(DEPDIR)/rpmvs.Plo ./$(DEPDIR)/signature.Plo \ +- ./$(DEPDIR)/tagexts.Plo ./$(DEPDIR)/tagname.Plo \ +- ./$(DEPDIR)/transaction.Plo ./$(DEPDIR)/verify.Plo \ +- backend/$(DEPDIR)/bdb_ro.Plo backend/$(DEPDIR)/db3.Plo \ +- backend/$(DEPDIR)/dbi.Plo backend/$(DEPDIR)/dbiset.Plo \ +- backend/$(DEPDIR)/dummydb.Plo backend/$(DEPDIR)/sqlite.Plo \ +- backend/ndb/$(DEPDIR)/glue.Plo \ ++ ./$(DEPDIR)/rpmextents.Plo ./$(DEPDIR)/rpmfi.Plo \ ++ ./$(DEPDIR)/rpmfs.Plo ./$(DEPDIR)/rpmgi.Plo \ ++ ./$(DEPDIR)/rpminstall.Plo ./$(DEPDIR)/rpmlead.Plo \ ++ ./$(DEPDIR)/rpmlock.Plo ./$(DEPDIR)/rpmplugins.Plo \ ++ ./$(DEPDIR)/rpmprob.Plo ./$(DEPDIR)/rpmps.Plo \ ++ ./$(DEPDIR)/rpmrc.Plo ./$(DEPDIR)/rpmscript.Plo \ ++ ./$(DEPDIR)/rpmtd.Plo ./$(DEPDIR)/rpmte.Plo \ ++ ./$(DEPDIR)/rpmtriggers.Plo ./$(DEPDIR)/rpmts.Plo \ ++ ./$(DEPDIR)/rpmug.Plo ./$(DEPDIR)/rpmvs.Plo \ ++ ./$(DEPDIR)/signature.Plo ./$(DEPDIR)/tagexts.Plo \ ++ ./$(DEPDIR)/tagname.Plo ./$(DEPDIR)/transaction.Plo \ ++ ./$(DEPDIR)/verify.Plo backend/$(DEPDIR)/bdb_ro.Plo \ ++ backend/$(DEPDIR)/db3.Plo backend/$(DEPDIR)/dbi.Plo \ ++ backend/$(DEPDIR)/dbiset.Plo backend/$(DEPDIR)/dummydb.Plo \ ++ backend/$(DEPDIR)/sqlite.Plo backend/ndb/$(DEPDIR)/glue.Plo \ + backend/ndb/$(DEPDIR)/rpmidx.Plo \ + backend/ndb/$(DEPDIR)/rpmpkg.Plo \ + backend/ndb/$(DEPDIR)/rpmxdb.Plo +@@ -589,8 +590,9 @@ librpm_la_SOURCES = backend/dbi.c backend/dbi.h backend/dummydb.c \ + signature.h transaction.c verify.c rpmlock.c rpmlock.h misc.h \ + relocation.c rpmscript.h rpmscript.c rpmchroot.c rpmchroot.h \ + rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \ +- rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h $(am__append_1) \ +- $(am__append_4) $(am__append_5) $(am__append_8) ++ rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h rpmextents.c \ ++ rpmextents_internal.h $(am__append_1) $(am__append_4) \ ++ $(am__append_5) $(am__append_8) + librpm_la_LDFLAGS = -version-info $(rpm_version_info) + librpm_la_LIBADD = $(top_builddir)/rpmio/librpmio.la @WITH_POPT_LIB@ \ + @WITH_CAP_LIB@ @WITH_ACL_LIB@ @LIBINTL@ $(am__append_2) \ +@@ -751,6 +753,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmchroot.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmdb.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmds.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmextents.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmfi.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmfs.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmgi.Plo@am__quote@ # am--include-marker +@@ -981,6 +984,7 @@ distclean: distclean-am + -rm -f ./$(DEPDIR)/rpmchroot.Plo + -rm -f ./$(DEPDIR)/rpmdb.Plo + -rm -f ./$(DEPDIR)/rpmds.Plo ++ -rm -f ./$(DEPDIR)/rpmextents.Plo + -rm -f ./$(DEPDIR)/rpmfi.Plo + -rm -f ./$(DEPDIR)/rpmfs.Plo + -rm -f ./$(DEPDIR)/rpmgi.Plo +@@ -1080,6 +1084,7 @@ maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/rpmchroot.Plo + -rm -f ./$(DEPDIR)/rpmdb.Plo + -rm -f ./$(DEPDIR)/rpmds.Plo ++ -rm -f ./$(DEPDIR)/rpmextents.Plo + -rm -f ./$(DEPDIR)/rpmfi.Plo + -rm -f ./$(DEPDIR)/rpmfs.Plo + -rm -f ./$(DEPDIR)/rpmgi.Plo diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h index fd81aec8d..877db81f3 100644 --- a/lib/rpmplugin.h +++ b/lib/rpmplugin.h @@ -60,6 +60,10 @@ 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); +typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi, @@ -37,7 +142,7 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c index 3da3097af..850a025a0 100644 --- a/lib/rpmplugins.c +++ b/lib/rpmplugins.c -@@ -421,3 +421,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, +@@ -435,3 +435,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, return rc; } @@ -82,8 +187,8 @@ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h index 39762c376..5365cf698 100644 --- a/lib/rpmplugins.h +++ b/lib/rpmplugins.h -@@ -167,6 +167,21 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, - const char *path, const char *dest, +@@ -168,6 +168,21 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, + int fd, const char *path, const char *dest, mode_t mode, rpmFsmOp op); +/** \ingroup rpmplugins diff --git a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch index 737368d..a904670 100644 --- a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch +++ b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch @@ -11,14 +11,14 @@ been created. If this was done in `rpmpluginsCallFsmFilePre`, the directories may be missing, which makes file installation fail. --- - lib/fsm.c | 29 +++++++++-------------------- - 1 file changed, 9 insertions(+), 20 deletions(-) + lib/fsm.c | 37 ++++++++++--------------------------- + 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/lib/fsm.c b/lib/fsm.c index feda3750c..711f553d3 100644 --- a/lib/fsm.c +++ b/lib/fsm.c -@@ -53,7 +53,6 @@ struct filedata_s { +@@ -55,7 +55,6 @@ struct filedata_s { int stage; int setmeta; int skip; @@ -26,17 +26,10 @@ index feda3750c..711f553d3 100644 rpmFileAction action; const char *suffix; char *fpath; -@@ -921,23 +920,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Remap file perms, owner, and group. */ - rc = rpmfiStat(fi, 1, &fp->sb); +@@ -918,20 +917,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + fp->setmeta = (fp->skip == 0) && + (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH); -+ setFileState(fs, fx); - fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Run fsm file pre hook for all plugins */ - rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, - fp->sb.st_mode, fp->action); -- fp->plugin_contents = 0; - switch (rc) { - case RPMRC_OK: - setFileState(fs, fx); @@ -47,30 +40,47 @@ index feda3750c..711f553d3 100644 - // this is from a hard link. - rc = RPMRC_OK; - break; +- default: +- fp->action = FA_SKIP; +- fp->skip = XFA_SKIPPING(fp->action); - } ++ setFileState(fs, fx); + fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb); + fp->stage = FILE_PRE; - } - fi = rpmfiFree(fi); -@@ -992,14 +980,15 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -984,10 +970,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (!rc) { + rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, + fp->sb.st_mode, fp->action); +- if (rc == RPMRC_PLUGIN_CONTENTS) { +- fp->plugin_contents = 1; +- rc = RPMRC_OK; +- } + } + if (rc) + goto setmeta; /* for error notification */ +@@ -1016,15 +998,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (fp->action == FA_TOUCH) - continue; + goto setmeta; - if (S_ISREG(fp->sb.st_mode)) { + rpmRC plugin_rc = rpmpluginsCallFsmFileInstall(plugins, fi, fp->fpath, fp->sb.st_mode, fp->action); -+ if(!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){ ++ if (!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){ + rc = plugin_rc; + } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){ + rc = RPMRC_OK; + } else if (S_ISREG(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { -- if(fp->plugin_contents) { +- if (fp->plugin_contents) { - rc = RPMRC_OK; -- }else { -- rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firstlink, &firstlinkfile); +- } else { +- rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, +- &firstlink, &firstlinkfile, +- &di.firstdir, &fd); - } -+ rc = fsmMkfile(fi, fp, files, psm, nodigest, -+ &firstlink, &firstlinkfile); ++ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, ++ &firstlink, &firstlinkfile, ++ &di.firstdir, &fd); } } else if (S_ISDIR(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { diff --git a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch deleted file mode 100644 index e6dae81..0000000 --- a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 20 Apr 2020 11:22:15 -0400 -Subject: [PATCH 15/33] rpmsign: RPMSIGN_FLAG_IMA is already set - -There is no need to set RPMSIGN_FLAG_IMA since it was already set to -get here. - -Signed-off-by: Jes Sorensen ---- - rpmsign.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/rpmsign.c b/rpmsign.c -index a74948ba8..e1d207da5 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -130,7 +130,6 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - free(fileSigningKeyPassword); - } - -- sargs->signflags |= RPMSIGN_FLAG_IMA; - free(key); - } - #endif --- -2.27.0 - diff --git a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch deleted file mode 100644 index 89845cb..0000000 --- a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch +++ /dev/null @@ -1,136 +0,0 @@ -From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Fri, 27 Mar 2020 18:31:36 -0400 -Subject: [PATCH 16/33] Add basic autoconf and framework for fsverity support - -Use the same signing key argument as is used for IMA file signing. - -Signed-off-by: Jes Sorensen ---- - configure.ac | 19 +++++++++++++++++++ - rpmsign.c | 20 ++++++++++++++------ - sign/Makefile.am | 5 +++++ - sign/rpmsign.h | 1 + - 4 files changed, 39 insertions(+), 6 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 3c102d5eb..cc7144440 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -919,6 +919,25 @@ fi - AM_CONDITIONAL(WITH_IMAEVM,[test "$with_imaevm" = yes]) - AC_SUBST(WITH_IMAEVM_LIB) - -+# fsverity -+AC_ARG_WITH([fsverity], [AS_HELP_STRING([--with-fsverity],[build with fsverity support])],[],[with_fsverity=no]) -+if test "$with_fsverity" = yes ; then -+ AC_MSG_CHECKING([libfsverity]) -+ AC_COMPILE_IFELSE( -+ [AC_LANG_PROGRAM( -+ [[#include ]], -+ [[return libfsverity_sign_digest(NULL, NULL, NULL, NULL);]] -+ )], -+ [AC_MSG_RESULT(yes) -+ AC_DEFINE(WITH_FSVERITY, 1, [Build with fsverity support?]) -+ WITH_FSVERITY_LIB="-lfsverity" -+ ], -+ [AC_MSG_ERROR([--with-fsverity given, libfsverity or libfsverity.h missing])] -+ ) -+fi -+AM_CONDITIONAL(WITH_FSVERITY,[test "$with_fsverity" = yes]) -+AC_SUBST(WITH_FSVERITY_LIB) -+ - # libcap - WITH_CAP_LIB= - AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])], -diff --git a/rpmsign.c b/rpmsign.c -index e1d207da5..8861c2c59 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -18,7 +18,7 @@ enum modes { - - static int mode = MODE_NONE; - --#ifdef WITH_IMAEVM -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - static int fskpass = 0; - static char * fileSigningKey = NULL; - #endif -@@ -39,6 +39,13 @@ static struct poptOption signOptsTable[] = { - { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), - &sargs.signflags, RPMSIGN_FLAG_IMA, - N_("sign package(s) files"), NULL}, -+#endif -+#ifdef WITH_FSVERITY -+ { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), -+ &sargs.signflags, RPMSIGN_FLAG_FSVERITY, -+ N_("generate fsverity signatures for package(s) files"), NULL}, -+#endif -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, - N_("use file signing key "), - N_("") }, -@@ -59,7 +66,7 @@ static struct poptOption optionsTable[] = { - POPT_TABLEEND - }; - --#ifdef WITH_IMAEVM -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - static char *get_fskpass(void) - { - struct termios flags, tmp_flags; -@@ -106,12 +113,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - goto exit; - } - --#ifdef WITH_IMAEVM -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - if (fileSigningKey) { - rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); - } - -- if (sargs->signflags & RPMSIGN_FLAG_IMA) { -+ if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) { - char *fileSigningKeyPassword = NULL; - char *key = rpmExpand("%{?_file_signing_key}", NULL); - if (rstreq(key, "")) { -@@ -165,8 +172,9 @@ int main(int argc, char *argv[]) - argerror(_("no arguments given")); - } - --#ifdef WITH_IMAEVM -- if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) { -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) -+ if (fileSigningKey && -+ !(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) { - argerror(_("--fskpath may only be specified when signing files")); - } - #endif -diff --git a/sign/Makefile.am b/sign/Makefile.am -index db774de0e..8d372915a 100644 ---- a/sign/Makefile.am -+++ b/sign/Makefile.am -@@ -24,3 +24,8 @@ if WITH_IMAEVM - librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h - librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@ - endif -+ -+if WITH_FSVERITY -+librpmsign_la_SOURCES += rpmsignverity.c rpmsignverity.h -+librpmsign_la_LIBADD += @WITH_FSVERITY_LIB@ -+endif -diff --git a/sign/rpmsign.h b/sign/rpmsign.h -index 7a770d879..2b8a10a1a 100644 ---- a/sign/rpmsign.h -+++ b/sign/rpmsign.h -@@ -17,6 +17,7 @@ enum rpmSignFlags_e { - RPMSIGN_FLAG_NONE = 0, - RPMSIGN_FLAG_IMA = (1 << 0), - RPMSIGN_FLAG_RPMV3 = (1 << 1), -+ RPMSIGN_FLAG_FSVERITY = (1 << 2), - }; - typedef rpmFlags rpmSignFlags; - --- -2.27.0 - diff --git a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch deleted file mode 100644 index ae64146..0000000 --- a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch +++ /dev/null @@ -1,51 +0,0 @@ -From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Wed, 27 May 2020 16:49:03 -0400 -Subject: [PATCH 17/33] rpmsign: Add helper to indicate file signing enabled - -Helper function returning true if either IMA or VERITY signatures are -to be applied. This simplifies the code and makes it easier to read. - -Signed-off-by: Jes Sorensen ---- - rpmsign.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/rpmsign.c b/rpmsign.c -index 8861c2c59..94cbf1d1a 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -67,6 +67,11 @@ static struct poptOption optionsTable[] = { - }; - - #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) -+static int flags_sign_files(int flags) -+{ -+ return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0); -+} -+ - static char *get_fskpass(void) - { - struct termios flags, tmp_flags; -@@ -118,7 +123,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); - } - -- if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) { -+ if (flags_sign_files(sargs->signflags)) { - char *fileSigningKeyPassword = NULL; - char *key = rpmExpand("%{?_file_signing_key}", NULL); - if (rstreq(key, "")) { -@@ -173,8 +178,7 @@ int main(int argc, char *argv[]) - } - - #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) -- if (fileSigningKey && -- !(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) { -+ if (fileSigningKey && !(flags_sign_files(sargs.signflags))) { - argerror(_("--fskpath may only be specified when signing files")); - } - #endif --- -2.27.0 - diff --git a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch index 7a5c5fd..e5b6ab4 100644 --- a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch +++ b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch @@ -38,7 +38,7 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c index 850a025a0..901af1ac5 100644 --- a/lib/rpmplugins.c +++ b/lib/rpmplugins.c -@@ -457,4 +457,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, +@@ -471,4 +471,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, return rc; } @@ -81,7 +81,7 @@ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h index 5365cf698..88807c53c 100644 --- a/lib/rpmplugins.h +++ b/lib/rpmplugins.h -@@ -181,7 +181,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, +@@ -182,7 +182,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op); diff --git a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch deleted file mode 100644 index 77a8b31..0000000 --- a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Fri, 3 Apr 2020 16:26:06 -0400 -Subject: [PATCH 18/33] rpmsign: Handle --certpath for signing certificate - -fsverirty needs a certificate for signing, in addition to the signing key. - -Signed-off-by: Jes Sorensen ---- - rpmsign.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/rpmsign.c b/rpmsign.c -index 94cbf1d1a..074dd8b13 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -22,6 +22,9 @@ static int mode = MODE_NONE; - static int fskpass = 0; - static char * fileSigningKey = NULL; - #endif -+#ifdef WITH_FSVERITY -+static char * fileSigningCert = NULL; -+#endif - - static struct rpmSignArgs sargs = {NULL, 0, 0}; - -@@ -44,6 +47,9 @@ static struct poptOption signOptsTable[] = { - { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), - &sargs.signflags, RPMSIGN_FLAG_FSVERITY, - N_("generate fsverity signatures for package(s) files"), NULL}, -+ { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, -+ N_("use file signing cert "), -+ N_("") }, - #endif - #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, -@@ -123,6 +129,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); - } - -+#ifdef WITH_FSVERITY -+ if (fileSigningCert) { -+ rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); -+ } -+#endif -+ - if (flags_sign_files(sargs->signflags)) { - char *fileSigningKeyPassword = NULL; - char *key = rpmExpand("%{?_file_signing_key}", NULL); --- -2.27.0 - diff --git a/0019-Implement-rpmSignVerity.patch b/0019-Implement-rpmSignVerity.patch deleted file mode 100644 index 70e873a..0000000 --- a/0019-Implement-rpmSignVerity.patch +++ /dev/null @@ -1,243 +0,0 @@ -From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Fri, 3 Apr 2020 16:38:08 -0400 -Subject: [PATCH 19/33] Implement rpmSignVerity() - -This generates the root Merkle tree hash and signs it using the -specified key and certificate. - -Signed-off-by: Jes Sorensen ---- - sign/rpmgensig.c | 36 +++++++++++++ - sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++ - sign/rpmsignverity.h | 29 +++++++++++ - 3 files changed, 186 insertions(+) - create mode 100644 sign/rpmsignverity.c - create mode 100644 sign/rpmsignverity.h - -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index a6e37e71b..8d5c5858f 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -22,6 +22,7 @@ - #include "lib/signature.h" - #include "lib/rpmvs.h" - #include "sign/rpmsignfiles.h" -+#include "sign/rpmsignverity.h" - - #include "debug.h" - -@@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) - #endif - } - -+static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) -+{ -+#ifdef WITH_FSVERITY -+ rpmRC rc; -+ char *key = rpmExpand("%{?_file_signing_key}", NULL); -+ char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL); -+ char *cert = rpmExpand("%{?_file_signing_cert}", NULL); -+ -+ if (rstreq(keypass, "")) { -+ free(keypass); -+ keypass = NULL; -+ } -+ -+ if (key && cert) { -+ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert); -+ } else { -+ rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n")); -+ rc = RPMRC_FAIL; -+ } -+ -+ free(keypass); -+ free(key); -+ free(cert); -+ return rc; -+#else -+ rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n")); -+ return RPMRC_FAIL; -+#endif -+} -+ - static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata) - { - char **msg = cbdata; -@@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags) - goto exit; - } - -+ if (flags & RPMSIGN_FLAG_FSVERITY) { -+ if (includeVeritySignatures(fd, &sigh, &h)) -+ goto exit; -+ } -+ - if (deleting) { /* Nuke all the signature tags. */ - deleteSigs(sigh); - } else { -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -new file mode 100644 -index 000000000..5346c3bc8 ---- /dev/null -+++ b/sign/rpmsignverity.c -@@ -0,0 +1,121 @@ -+/** -+ * Copyright (C) 2020 Facebook -+ * -+ * Author: Jes Sorensen -+ */ -+ -+#include "system.h" -+ -+#include /* RPMSIGTAG & related */ -+#include /* rpmlog */ -+#include -+#include /* rpmDigestLength */ -+#include "lib/header.h" /* HEADERGET_MINMEM */ -+#include "lib/header_internal.h" -+#include "lib/rpmtypes.h" /* rpmRC */ -+#include -+#include "rpmio/rpmio_internal.h" -+#include "lib/rpmvs.h" -+ -+#include "sign/rpmsignverity.h" -+ -+#define MAX_SIGNATURE_LENGTH 1024 -+ -+static int rpmVerityRead(void *opaque, void *buf, size_t size) -+{ -+ int retval; -+ rpmfi fi = (rpmfi)opaque; -+ -+ retval = rpmfiArchiveRead(fi, buf, size); -+ -+ if (retval > 0) -+ retval = 0; -+ return retval; -+} -+ -+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -+ char *keypass, char *cert) -+{ -+ int rc, status; -+ FD_t gzdi; -+ rpmfiles files = NULL; -+ rpmfi fi = NULL; -+ rpmts ts = rpmtsCreate(); -+ struct libfsverity_digest *digest = NULL; -+ struct libfsverity_merkle_tree_params params; -+ struct libfsverity_signature_params sig_params; -+ rpm_loff_t file_size; -+ off_t offset = Ftell(fd); -+ const char *compr; -+ char *rpmio_flags = NULL; -+ char *digest_hex; -+ uint8_t *sig; -+ size_t sig_size; -+ -+ Fseek(fd, 0, SEEK_SET); -+ rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES | -+ RPMVSF_NOHDRCHK); -+ rc = rpmReadPackageFile(ts, fd, "fsverity", &h); -+ if (rc != RPMRC_OK) { -+ rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"), -+ __func__, rc); -+ goto out; -+ } -+ -+ rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key); -+ rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert); -+ -+ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); -+ -+ gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags); -+ free(rpmio_flags); -+ -+ files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); -+ fi = rpmfiNewArchiveReader(gzdi, files, -+ RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS); -+ -+ while (rpmfiNext(fi) >= 0) { -+ if (!S_ISREG(rpmfiFMode(fi))) -+ continue; -+ file_size = rpmfiFSize(fi); -+ rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"), -+ rpmfiFN(fi), file_size); -+ -+ memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); -+ params.version = 1; -+ params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -+ params.block_size = sysconf(_SC_PAGESIZE); -+ params.salt_size = 0 /* salt_size */; -+ params.salt = NULL /* salt */; -+ params.file_size = file_size; -+ status = libfsverity_compute_digest(fi, rpmVerityRead, -+ ¶ms, &digest); -+ if (!status) { -+ digest_hex = pgpHexStr(digest->digest, digest->digest_size); -+ rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), -+ digest->digest_size, digest_hex); -+ free(digest_hex); -+ } -+ memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); -+ sig_params.keyfile = key; -+ sig_params.certfile = cert; -+ if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) { -+ rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); -+ rc = RPMRC_FAIL; -+ goto out; -+ } -+ rpmlog(RPMLOG_DEBUG, _("digest signing success\n")); -+ -+ free(digest); -+ free(sig); -+ } -+ -+out: -+ Fseek(fd, offset, SEEK_SET); -+ -+ rpmfilesFree(files); -+ rpmfiFree(fi); -+ rpmtsFree(ts); -+ return rc; -+} -diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h -new file mode 100644 -index 000000000..f3ad3bb18 ---- /dev/null -+++ b/sign/rpmsignverity.h -@@ -0,0 +1,29 @@ -+#ifndef H_RPMSIGNVERITY -+#define H_RPMSIGNVERITY -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * Sign file digests in header into signature header -+ * @param fd file descriptor of RPM -+ * @param sigh package signature header -+ * @param h package header -+ * @param key signing key -+ * @param keypass signing key password -+ * @param cert signing cert -+ * @return RPMRC_OK on success -+ */ -+RPM_GNUC_INTERNAL -+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -+ char *keypass, char *cert); -+ -+#ifdef _cplusplus -+} -+#endif -+ -+#endif /* H_RPMSIGNVERITY */ --- -2.27.0 - diff --git a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch index 1e98fd1..211772f 100644 --- a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch +++ b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch @@ -9,15 +9,15 @@ As the plugin can now be responsible to provide an Archive Reader to `RPMTAG_PAYLOADFORMAT` header in memory, removing some special-casing. --- lib/depends.c | 2 -- - lib/fsm.c | 38 +++++++++++++++++++------------------- + lib/fsm.c | 48 ++++++++++++++++++++++++++--------------------- plugins/reflink.c | 18 +++++++++++++----- - 3 files changed, 32 insertions(+), 26 deletions(-) + 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/lib/depends.c b/lib/depends.c index 8998afcd3..30234df3d 100644 --- a/lib/depends.c +++ b/lib/depends.c -@@ -81,8 +81,6 @@ static rpmRC headerCheckPayloadFormat(Header h) { +@@ -80,8 +80,6 @@ static rpmRC headerCheckPayloadFormat(Header h) { */ if (!payloadfmt) return rc; @@ -30,18 +30,43 @@ diff --git a/lib/fsm.c b/lib/fsm.c index 711f553d3..6972602e0 100644 --- a/lib/fsm.c +++ b/lib/fsm.c -@@ -19,7 +19,6 @@ +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ - #include "lib/fsm.h" --#include "lib/rpmlib.h" - #include "lib/rpmte_internal.h" /* XXX rpmfs */ - #include "lib/rpmplugins.h" /* rpm plugins hooks */ - #include "lib/rpmug.h" -@@ -892,14 +891,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + #include "fsm.h" +@@ -869,6 +868,24 @@ static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di) + return rpmfiFree(fi); + } + ++static int fiIterator(rpmPlugins plugins, FD_t payload, rpmfiles files, rpmfi *fi) ++{ ++ rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, fi); ++ switch (plugin_rc) { ++ case RPMRC_PLUGIN_CONTENTS: ++ if (*fi == NULL) ++ return RPMERR_BAD_MAGIC; ++ return RPMRC_OK; ++ case RPMRC_OK: ++ *fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); ++ if (*fi == NULL) ++ return RPMERR_BAD_MAGIC; ++ return RPMRC_OK; ++ default: ++ return RPMRC_FAIL; ++ } ++} ++ + int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { +@@ -886,13 +903,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); struct filedata_s *firstlink = NULL; - + struct diriter_s di = { -1, -1 }; - Header h = rpmteHeader(te); - const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT); - int cpio = 1; @@ -49,60 +74,54 @@ index 711f553d3..6972602e0 100644 - if (payloadfmt && rstreq(payloadfmt, "clon")) { - cpio = 0; - } -- + /* transaction id used for temporary path suffix while installing */ rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); - -@@ -933,14 +924,24 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -927,12 +937,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (rc) goto exit; - if (cpio) { -- fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -- if (fi == NULL) { -- rc = RPMERR_BAD_MAGIC; -- goto exit; -- } +- fi = fsmIter(payload, files, +- payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); - } else { - fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, &fi); -+ switch(plugin_rc) { -+ case RPMRC_PLUGIN_CONTENTS: -+ if(fi == NULL) { -+ rc = RPMERR_BAD_MAGIC; -+ goto exit; -+ } -+ rc = RPMRC_OK; -+ break; -+ case RPMRC_OK: -+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ if (fi == NULL) { -+ rc = RPMERR_BAD_MAGIC; -+ goto exit; -+ } -+ break; -+ default: -+ rc = RPMRC_FAIL; - } +- } ++ rc = fiIterator(plugins, payload, files, &fi); ++ if (rc) ++ goto exit; + + if (fi == NULL) { + rc = RPMERR_BAD_MAGIC; +@@ -956,7 +963,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + int mayopen = 0; + int fd = -1; - /* Detect and create directories not explicitly in package. */ -@@ -988,7 +989,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - } else if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { - rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firstlink, &firstlinkfile); -+ &firstlink, &firstlinkfile); - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -1096,7 +1097,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); +- if (!cpio && di.dirfd >= 0) ++ if (di.dirfd >= 0) + fsmClose(&di.dirfd); + rc = ensureDir(plugins, rpmfiDN(fi), 0, + (fp->action == FA_CREATE), 0, &di.dirfd); +@@ -1075,16 +1082,13 @@ setmeta: + rc = fx; + + /* If all went well, commit files to final destination */ +- if (cpio) { +- fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); +- } else { +- fi = rpmfilesIter(files, RPMFI_ITER_FWD); +- } ++ fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ + while (!rc && (fx = rpmfiNext(fi)) >= 0) { + struct filedata_s *fp = &fdata[fx]; - exit: -- h = headerFree(h); - fi = rpmfiFree(fi); - Fclose(payload); - free(tid); + if (!fp->skip) { +- if (!cpio && di.dirfd >= 0) ++ if (di.dirfd >= 0) + fsmClose(&di.dirfd); + if (!rc) + rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd); diff --git a/plugins/reflink.c b/plugins/reflink.c index 7dda06d8e..d5e6db27a 100644 --- a/plugins/reflink.c diff --git a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch deleted file mode 100644 index b099eaf..0000000 --- a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch +++ /dev/null @@ -1,95 +0,0 @@ -From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Thu, 28 May 2020 17:48:23 -0400 -Subject: [PATCH 20/33] Introduce base2bin() - a helper to convert tag array of - base64 strings - -This will convert a tag of base64 strings to a binary array, similar -to how hex2bin() works. It supports variable sized strings, and will -determine the maximum string length and build the output array based -on that. - -Signed-off-by: Jes Sorensen ---- - lib/rpmfi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 58 insertions(+) - -diff --git a/lib/rpmfi.c b/lib/rpmfi.c -index 689ead2c5..8c69d3e40 100644 ---- a/lib/rpmfi.c -+++ b/lib/rpmfi.c -@@ -19,6 +19,7 @@ - #include "lib/fsm.h" /* rpmpsm stuff for now */ - #include "lib/rpmug.h" - #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ -+#include "rpmio/rpmbase64.h" - - #include "debug.h" - -@@ -1520,6 +1521,63 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len) - return bin; - } - -+/* -+ * Convert a tag of base64 strings to binary presentation. -+ * This handles variable length strings by finding the longest string -+ * before building the output array. Dummy strings in the tag should be -+ * added as '\0' -+ */ -+static uint8_t *base2bin(Header h, rpmTagVal tag, rpm_count_t num, int *len) -+{ -+ struct rpmtd_s td; -+ uint8_t *bin = NULL, *t = NULL; -+ size_t maxlen = 0; -+ int status, i= 0; -+ void **arr = xmalloc(num * sizeof(void *)); -+ size_t *lengths = xcalloc(num, sizeof(size_t)); -+ const char *s; -+ -+ if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) != num) -+ goto out; -+ -+ while ((s = rpmtdNextString(&td))) { -+ /* Insert a dummy entry for empty strings */ -+ if (*s == '\0') { -+ arr[i++] = NULL; -+ continue; -+ } -+ status = rpmBase64Decode(s, &arr[i], &lengths[i]); -+ if (lengths[i] > maxlen) -+ maxlen = lengths[i]; -+ if (status) { -+ rpmlog(RPMLOG_DEBUG, _("%s: base64 decode failed, len %li\n"), -+ __func__, lengths[i]); -+ goto out; -+ } -+ i++; -+ } -+ -+ if (maxlen) { -+ rpmlog(RPMLOG_DEBUG, _("%s: base64 decode success, len %li\n"), -+ __func__, maxlen); -+ -+ t = bin = xcalloc(num, maxlen); -+ -+ for (i = 0; i < num; i++) { -+ memcpy(t, arr[i], lengths[i]); -+ free(arr[i]); -+ t += maxlen; -+ } -+ *len = maxlen; -+ } -+ out: -+ free(arr); -+ free(lengths); -+ rpmtdFreeData(&td); -+ -+ return bin; -+} -+ - static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) - { - headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ? --- -2.27.0 - diff --git a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch deleted file mode 100644 index 051c0bc..0000000 --- a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch +++ /dev/null @@ -1,206 +0,0 @@ -From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Thu, 9 Apr 2020 12:58:17 -0400 -Subject: [PATCH 21/33] rpmsignverity: Add verity signature headers to the - package - -This adds the array of verity signatures, and a signature length -header. We use 4K block for the Merkle tree, and rely on the kernel -doing the right thing. - -Signed-off-by: Jes Sorensen ---- - lib/rpmtag.h | 6 ++- - sign/rpmsignverity.c | 112 +++++++++++++++++++++++++++++-------------- - sign/rpmsignverity.h | 7 +++ - 3 files changed, 87 insertions(+), 38 deletions(-) - -diff --git a/lib/rpmtag.h b/lib/rpmtag.h -index 40ff5fa5d..478457ecb 100644 ---- a/lib/rpmtag.h -+++ b/lib/rpmtag.h -@@ -67,6 +67,7 @@ typedef enum rpmTag_e { - RPMTAG_SHA256HEADER = RPMTAG_SIG_BASE+17, /* s */ - /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */ - /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */ -+ RPMTAG_VERITYSIGNATURES = RPMTAG_SIG_BASE+20, /* s[] */ - - RPMTAG_NAME = 1000, /* s */ - #define RPMTAG_N RPMTAG_NAME /* s */ -@@ -427,6 +428,7 @@ typedef enum rpmSigTag_e { - RPMSIGTAG_SHA256 = RPMTAG_SHA256HEADER, - RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 18, - RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, -+ RPMSIGTAG_VERITYSIGNATURES = RPMTAG_VERITYSIGNATURES, - } rpmSigTag; - - -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 5346c3bc8..a9818bd08 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -33,23 +33,66 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size) - return retval; - } - -+static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, -+ char *keypass, char *cert) -+{ -+ struct libfsverity_merkle_tree_params params; -+ struct libfsverity_signature_params sig_params; -+ struct libfsverity_digest *digest = NULL; -+ rpm_loff_t file_size; -+ char *digest_hex, *sig_hex = NULL; -+ uint8_t *sig; -+ int status; -+ -+ file_size = rpmfiFSize(fi); -+ -+ memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); -+ params.version = 1; -+ params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -+ params.block_size = RPM_FSVERITY_BLKSZ; -+ params.salt_size = 0 /* salt_size */; -+ params.salt = NULL /* salt */; -+ params.file_size = file_size; -+ status = libfsverity_compute_digest(fi, rpmVerityRead, ¶ms, &digest); -+ if (status) { -+ rpmlog(RPMLOG_DEBUG, _("failed to compute digest\n")); -+ goto out; -+ } -+ -+ digest_hex = pgpHexStr(digest->digest, digest->digest_size); -+ rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), -+ digest->digest_size, digest_hex); -+ free(digest_hex); -+ -+ memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); -+ sig_params.keyfile = key; -+ sig_params.certfile = cert; -+ if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) { -+ rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); -+ goto out; -+ } -+ -+ sig_hex = pgpHexStr(sig, *sig_size + 1); -+ out: -+ free(digest); -+ free(sig); -+ return sig_hex; -+} -+ - rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - char *keypass, char *cert) - { -- int rc, status; -+ int rc; - FD_t gzdi; - rpmfiles files = NULL; - rpmfi fi = NULL; - rpmts ts = rpmtsCreate(); -- struct libfsverity_digest *digest = NULL; -- struct libfsverity_merkle_tree_params params; -- struct libfsverity_signature_params sig_params; -+ struct rpmtd_s td; - rpm_loff_t file_size; - off_t offset = Ftell(fd); - const char *compr; - char *rpmio_flags = NULL; -- char *digest_hex; -- uint8_t *sig; -+ char *sig_hex; - size_t sig_size; - - Fseek(fd, 0, SEEK_SET); -@@ -75,43 +118,40 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - fi = rpmfiNewArchiveReader(gzdi, files, - RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS); - -+ /* -+ * Should this be sigh from the cloned fd or the sigh we received? -+ */ -+ headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); -+ -+ rpmtdReset(&td); -+ td.tag = RPMSIGTAG_VERITYSIGNATURES; -+ td.type = RPM_STRING_ARRAY_TYPE; -+ td.count = 1; -+ - while (rpmfiNext(fi) >= 0) { -- if (!S_ISREG(rpmfiFMode(fi))) -- continue; - file_size = rpmfiFSize(fi); -- rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"), -- rpmfiFN(fi), file_size); -- -- memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); -- params.version = 1; -- params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -- params.block_size = sysconf(_SC_PAGESIZE); -- params.salt_size = 0 /* salt_size */; -- params.salt = NULL /* salt */; -- params.file_size = file_size; -- status = libfsverity_compute_digest(fi, rpmVerityRead, -- ¶ms, &digest); -- if (!status) { -- digest_hex = pgpHexStr(digest->digest, digest->digest_size); -- rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), -- digest->digest_size, digest_hex); -- free(digest_hex); -- } -- memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); -- sig_params.keyfile = key; -- sig_params.certfile = cert; -- if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) { -- rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); -+ -+ rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"), -+ rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi)); -+ -+ sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); -+ td.data = &sig_hex; -+ rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size); -+#if 0 -+ rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex); -+#endif -+ if (!headerPut(sigh, &td, HEADERPUT_APPEND)) { -+ rpmlog(RPMLOG_ERR, _("headerPutString failed\n")); - rc = RPMRC_FAIL; - goto out; - } -- rpmlog(RPMLOG_DEBUG, _("digest signing success\n")); -- -- free(digest); -- free(sig); -+ free(sig_hex); - } - --out: -+ rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0)); -+ -+ rc = RPMRC_OK; -+ out: - Fseek(fd, offset, SEEK_SET); - - rpmfilesFree(files); -diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h -index f3ad3bb18..69bbaf7f7 100644 ---- a/sign/rpmsignverity.h -+++ b/sign/rpmsignverity.h -@@ -8,6 +8,13 @@ - extern "C" { - #endif - -+/* -+ * Block size used to generate the Merkle tree for fsverity. For now -+ * we only support 4K blocks, if we ever decide to support different -+ * block sizes, we will need a tag to indicate this. -+ */ -+#define RPM_FSVERITY_BLKSZ 4096 -+ - /** - * Sign file digests in header into signature header - * @param fd file descriptor of RPM --- -2.27.0 - diff --git a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch deleted file mode 100644 index dba0ca6..0000000 --- a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 13 Apr 2020 18:14:15 -0400 -Subject: [PATCH 22/33] rpmSignVerity: Generate signatures for files not - present in archive - -This generates signatures for all files in the archive, then picks up -ghost files from the header metadata and generates signatures for them -as well. It finally submits them to RPMTAG_VERITYSIGNATURES in header -file order as we cannot rely on archive order and header order being -the same. - -Signed-off-by: Jes Sorensen ---- - lib/package.c | 1 + - sign/rpmsignverity.c | 55 ++++++++++++++++++++++++++++++++++---------- - 2 files changed, 44 insertions(+), 12 deletions(-) - -diff --git a/lib/package.c b/lib/package.c -index b7d996a12..c6108f686 100644 ---- a/lib/package.c -+++ b/lib/package.c -@@ -45,6 +45,7 @@ struct taglate_s { - { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 }, - { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 }, - { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 }, -+ { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 }, - { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, - { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, - { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index a9818bd08..3bb23a18d 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -41,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - struct libfsverity_digest *digest = NULL; - rpm_loff_t file_size; - char *digest_hex, *sig_hex = NULL; -- uint8_t *sig; -+ uint8_t *sig = NULL; - int status; - - file_size = rpmfiFSize(fi); -@@ -72,7 +72,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - goto out; - } - -- sig_hex = pgpHexStr(sig, *sig_size + 1); -+ sig_hex = pgpHexStr(sig, *sig_size); - out: - free(digest); - free(sig); -@@ -86,6 +86,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - FD_t gzdi; - rpmfiles files = NULL; - rpmfi fi = NULL; -+ rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); - rpmts ts = rpmtsCreate(); - struct rpmtd_s td; - rpm_loff_t file_size; -@@ -93,11 +94,14 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - const char *compr; - char *rpmio_flags = NULL; - char *sig_hex; -+ char **signatures = NULL; - size_t sig_size; -+ int nr_files, idx; - - Fseek(fd, 0, SEEK_SET); - rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES | - RPMVSF_NOHDRCHK); -+ - rc = rpmReadPackageFile(ts, fd, "fsverity", &h); - if (rc != RPMRC_OK) { - rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"), -@@ -113,6 +117,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - - gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags); - free(rpmio_flags); -+ if (!gzdi) -+ rpmlog(RPMLOG_DEBUG, _("Fdopen() failed\n")); - - files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); - fi = rpmfiNewArchiveReader(gzdi, files, -@@ -123,39 +129,64 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - */ - headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); - -- rpmtdReset(&td); -- td.tag = RPMSIGTAG_VERITYSIGNATURES; -- td.type = RPM_STRING_ARRAY_TYPE; -- td.count = 1; -+ /* -+ * The payload doesn't include special files, like ghost files, and -+ * we cannot rely on the file order in the payload to match that of -+ * the header. Instead we allocate an array of pointers and populate -+ * it as we go along. Then walk the header fi and account for the -+ * special files. Last we walk the array and populate the header. -+ */ -+ nr_files = rpmfiFC(hfi); -+ signatures = xcalloc(nr_files, sizeof(char *)); -+ -+ rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"), -+ nr_files, rpmfiFC(fi)); - - while (rpmfiNext(fi) >= 0) { - file_size = rpmfiFSize(fi); -+ idx = rpmfiFX(fi); - - rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"), - rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi)); - -- sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); -+ signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); -+ } -+ -+ while (rpmfiNext(hfi) >= 0) { -+ idx = rpmfiFX(hfi); -+ if (signatures[idx]) -+ continue; -+ signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert); -+ } -+ -+ rpmtdReset(&td); -+ td.tag = RPMSIGTAG_VERITYSIGNATURES; -+ td.type = RPM_STRING_ARRAY_TYPE; -+ td.count = 1; -+ for (idx = 0; idx < nr_files; idx++) { -+ sig_hex = signatures[idx]; - td.data = &sig_hex; -- rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size); --#if 0 -- rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex); --#endif - if (!headerPut(sigh, &td, HEADERPUT_APPEND)) { - rpmlog(RPMLOG_ERR, _("headerPutString failed\n")); - rc = RPMRC_FAIL; - goto out; - } -- free(sig_hex); -+ rpmlog(RPMLOG_DEBUG, _("signature: %s\n"), signatures[idx]); -+ rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size); -+ free(signatures[idx]); -+ signatures[idx] = NULL; - } - - rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0)); - - rc = RPMRC_OK; - out: -+ signatures = _free(signatures); - Fseek(fd, offset, SEEK_SET); - - rpmfilesFree(files); - rpmfiFree(fi); -+ rpmfiFree(hfi); - rpmtsFree(ts); - return rc; - } --- -2.27.0 - diff --git a/0023-Process-verity-tag-on-package-read.patch b/0023-Process-verity-tag-on-package-read.patch deleted file mode 100644 index c0b6b74..0000000 --- a/0023-Process-verity-tag-on-package-read.patch +++ /dev/null @@ -1,189 +0,0 @@ -From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 13 Apr 2020 18:21:36 -0400 -Subject: [PATCH 23/33] Process verity tag on package read - -This processes verity signature tags on package read, and provides -accessor functions to access them. - -Signed-off-by: Jes Sorensen ---- - lib/rpmfi.c | 27 +++++++++++++++++++++++++++ - lib/rpmfi.h | 8 ++++++++ - lib/rpmfiles.h | 10 ++++++++++ - sign/rpmsignverity.c | 20 ++++++++++++++++---- - 4 files changed, 61 insertions(+), 4 deletions(-) - -diff --git a/lib/rpmfi.c b/lib/rpmfi.c -index 8c69d3e40..5fdbe02a2 100644 ---- a/lib/rpmfi.c -+++ b/lib/rpmfi.c -@@ -116,8 +116,10 @@ struct rpmfiles_s { - - int digestalgo; /*!< File digest algorithm */ - uint32_t *signatureoffs; /*!< File signature offsets */ -+ int veritysiglength; /*!< Verity signature length */ - unsigned char * digests; /*!< File digests in binary. */ - unsigned char * signatures; /*!< File signatures in binary. */ -+ unsigned char * veritysigs; /*!< Verity signatures in binary. */ - - struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */ - rpm_off_t * replacedSizes; /*!< (TR_ADDED) */ -@@ -582,6 +584,19 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len) - return signature; - } - -+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) -+{ -+ const unsigned char *vsignature = NULL; -+ -+ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) { -+ if (fi->veritysigs != NULL) -+ vsignature = fi->veritysigs + (fi->veritysiglength * ix); -+ if (len) -+ *len = fi->veritysiglength; -+ } -+ return vsignature; -+} -+ - const char * rpmfilesFLink(rpmfiles fi, int ix) - { - const char * flink = NULL; -@@ -1268,6 +1283,7 @@ rpmfiles rpmfilesFree(rpmfiles fi) - fi->digests = _free(fi->digests); - fi->signatures = _free(fi->signatures); - fi->signatureoffs = _free(fi->signatureoffs); -+ fi->veritysigs = _free(fi->veritysigs); - fi->fcaps = _free(fi->fcaps); - - fi->cdict = _free(fi->cdict); -@@ -1649,6 +1665,12 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) - totalfc, &fi->signatureoffs); - } - -+ fi->veritysigs = NULL; -+ if (!(flags & RPMFI_NOVERITYSIGNATURES)) { -+ fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES, -+ totalfc, &fi->veritysiglength); -+ } -+ - /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */ - if (!(flags & RPMFI_NOFILEMTIMES)) - _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes); -@@ -1939,6 +1961,11 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len) - return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len); - } - -+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len) -+{ -+ return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len); -+} -+ - uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp) - { - return rpmfilesFDepends(fi->files, fi ? fi->i : -1, fddictp); -diff --git a/lib/rpmfi.h b/lib/rpmfi.h -index 6ef70cd28..fcb9d3acd 100644 ---- a/lib/rpmfi.h -+++ b/lib/rpmfi.h -@@ -190,6 +190,14 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo); - */ - const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen); - -+/** \ingroup rpmfi -+ * Return current verity (binary) signature of file info set iterator. -+ * @param fi file info set iterator -+ * @retval siglen signature length (pass NULL to ignore) -+ * @return current verity signature, NULL on invalid -+ */ -+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen); -+ - /** \ingroup rpmfi - * Return current file linkto (i.e. symlink(2) target) from file info set iterator. - * @param fi file info set iterator -diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h -index daf572cf4..81b3d01a1 100644 ---- a/lib/rpmfiles.h -+++ b/lib/rpmfiles.h -@@ -119,6 +119,7 @@ enum rpmfiFlags_e { - RPMFI_NOFILEVERIFYFLAGS = (1 << 16), - RPMFI_NOFILEFLAGS = (1 << 17), - RPMFI_NOFILESIGNATURES = (1 << 18), -+ RPMFI_NOVERITYSIGNATURES = (1 << 19), - }; - - typedef rpmFlags rpmfiFlags; -@@ -442,6 +443,15 @@ const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *le - */ - const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len); - -+/** \ingroup rpmfiles -+ * Return file verity signature (binary) -+ * @param fi file info set -+ * @param ix file index -+ * @retval len signature length (pass NULL to ignore) -+ * @return verity signature, NULL on invalid -+ */ -+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len); -+ - /** \ingroup rpmfiles - * Return file rdev from file info set. - * @param fi file info set -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 3bb23a18d..177561957 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -15,6 +15,7 @@ - #include "lib/rpmtypes.h" /* rpmRC */ - #include - #include "rpmio/rpmio_internal.h" -+#include "rpmio/rpmbase64.h" - #include "lib/rpmvs.h" - - #include "sign/rpmsignverity.h" -@@ -40,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - struct libfsverity_signature_params sig_params; - struct libfsverity_digest *digest = NULL; - rpm_loff_t file_size; -- char *digest_hex, *sig_hex = NULL; -+ char *digest_hex, *digest_base64, *sig_base64 = NULL, *sig_hex = NULL; - uint8_t *sig = NULL; - int status; - -@@ -60,8 +61,14 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - } - - digest_hex = pgpHexStr(digest->digest, digest->digest_size); -- rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), -- digest->digest_size, digest_hex); -+ digest_base64 = rpmBase64Encode(digest->digest, digest->digest_size, -1); -+ rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest(%i): %s, idx %i\n"), -+ file_size, rpmfiFN(fi), digest->digest_size, digest_hex, -+ rpmfiFX(fi)); -+ rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest sz (%i): base64 sz (%li), %s, idx %i\n"), -+ file_size, rpmfiFN(fi), digest->digest_size, strlen(digest_base64), -+ digest_base64, rpmfiFX(fi)); -+ - free(digest_hex); - - memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); -@@ -73,10 +80,15 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - } - - sig_hex = pgpHexStr(sig, *sig_size); -+ sig_base64 = rpmBase64Encode(sig, *sig_size, -1); -+ rpmlog(RPMLOG_DEBUG, _("%s: sig_size(%li), base64_size(%li), idx %i: signature:\n%s\n"), -+ rpmfiFN(fi), *sig_size, strlen(sig_base64), rpmfiFX(fi), sig_hex); - out: -+ free(sig_hex); -+ - free(digest); - free(sig); -- return sig_hex; -+ return sig_base64; - } - - rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, --- -2.27.0 - diff --git a/0024-Generate-a-zero-length-signature-for-symlinks.patch b/0024-Generate-a-zero-length-signature-for-symlinks.patch deleted file mode 100644 index 2fc3f5a..0000000 --- a/0024-Generate-a-zero-length-signature-for-symlinks.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Tue, 14 Apr 2020 10:33:32 -0400 -Subject: [PATCH 24/33] Generate a zero-length signature for symlinks - -The fsverity utility follows the symlink when generating a signature. -Since we don't want to sign the same file twice, we need to skip these -links, and instead just generate a dummy zero-length signature here. - -Signed-off-by: Jes Sorensen ---- - sign/rpmsignverity.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 177561957..2c7d21620 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -45,7 +45,10 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - uint8_t *sig = NULL; - int status; - -- file_size = rpmfiFSize(fi); -+ if (S_ISLNK(rpmfiFMode(fi))) -+ file_size = 0; -+ else -+ file_size = rpmfiFSize(fi); - - memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); - params.version = 1; --- -2.27.0 - diff --git a/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/0025-rpmsignverity.c-Clean-up-debug-logging.patch deleted file mode 100644 index bb6e4f3..0000000 --- a/0025-rpmsignverity.c-Clean-up-debug-logging.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Tue, 14 Apr 2020 12:08:09 -0400 -Subject: [PATCH 25/33] rpmsignverity.c: Clean up debug logging - -Put most logging in one place and avoid printing the same info twice. - -Signed-off-by: Jes Sorensen ---- - sign/rpmsignverity.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 2c7d21620..445e1197c 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -104,7 +104,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); - rpmts ts = rpmtsCreate(); - struct rpmtd_s td; -- rpm_loff_t file_size; - off_t offset = Ftell(fd); - const char *compr; - char *rpmio_flags = NULL; -@@ -158,12 +157,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - nr_files, rpmfiFC(fi)); - - while (rpmfiNext(fi) >= 0) { -- file_size = rpmfiFSize(fi); - idx = rpmfiFX(fi); - -- rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"), -- rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi)); -- - signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); - } - --- -2.27.0 - diff --git a/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/0026-fsverity-add-tag-for-fsverity-algorithm.patch deleted file mode 100644 index 74b2fc1..0000000 --- a/0026-fsverity-add-tag-for-fsverity-algorithm.patch +++ /dev/null @@ -1,161 +0,0 @@ -From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 20 Apr 2020 13:40:26 -0400 -Subject: [PATCH 26/33] fsverity - add tag for fsverity algorithm - -The default algorith is SHA256, but fsverity allows for other -algorithms, so add a tag to handle this. - -Signed-off-by: Jes Sorensen ---- - lib/package.c | 1 + - lib/rpmfi.c | 2 ++ - lib/rpmtag.h | 2 ++ - sign/rpmsignverity.c | 32 ++++++++++++++++++++++++++++---- - 4 files changed, 33 insertions(+), 4 deletions(-) - -diff --git a/lib/package.c b/lib/package.c -index c6108f686..3c761d365 100644 ---- a/lib/package.c -+++ b/lib/package.c -@@ -46,6 +46,7 @@ struct taglate_s { - { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 }, - { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 }, - { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 }, -+ { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 }, - { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, - { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, - { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, -diff --git a/lib/rpmfi.c b/lib/rpmfi.c -index 5fdbe02a2..70f05f509 100644 ---- a/lib/rpmfi.c -+++ b/lib/rpmfi.c -@@ -118,6 +118,7 @@ struct rpmfiles_s { - int digestalgo; /*!< File digest algorithm */ - uint32_t *signatureoffs; /*!< File signature offsets */ - int veritysiglength; /*!< Verity signature length */ -+ uint16_t verityalgo; /*!< Verity algorithm */ - unsigned char * digests; /*!< File digests in binary. */ - unsigned char * signatures; /*!< File signatures in binary. */ - unsigned char * veritysigs; /*!< Verity signatures in binary. */ -@@ -1667,6 +1668,7 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) - - fi->veritysigs = NULL; - if (!(flags & RPMFI_NOVERITYSIGNATURES)) { -+ fi->verityalgo = headerGetNumber(h, RPMTAG_VERITYSIGNATUREALGO); - fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES, - totalfc, &fi->veritysiglength); - } -diff --git a/lib/rpmtag.h b/lib/rpmtag.h -index 478457ecb..8d1efcc79 100644 ---- a/lib/rpmtag.h -+++ b/lib/rpmtag.h -@@ -68,6 +68,7 @@ typedef enum rpmTag_e { - /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */ - /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */ - RPMTAG_VERITYSIGNATURES = RPMTAG_SIG_BASE+20, /* s[] */ -+ RPMTAG_VERITYSIGNATUREALGO = RPMTAG_SIG_BASE+21, /* i */ - - RPMTAG_NAME = 1000, /* s */ - #define RPMTAG_N RPMTAG_NAME /* s */ -@@ -431,6 +432,7 @@ typedef enum rpmSigTag_e { - RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 18, - RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, - RPMSIGTAG_VERITYSIGNATURES = RPMTAG_VERITYSIGNATURES, -+ RPMSIGTAG_VERITYSIGNATUREALGO = RPMTAG_VERITYSIGNATUREALGO, - } rpmSigTag; - - -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 445e1197c..55096e732 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -35,7 +35,7 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size) - } - - static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, -- char *keypass, char *cert) -+ char *keypass, char *cert, uint16_t algo) - { - struct libfsverity_merkle_tree_params params; - struct libfsverity_signature_params sig_params; -@@ -52,7 +52,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - - memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); - params.version = 1; -- params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -+ params.hash_algorithm = algo; - params.block_size = RPM_FSVERITY_BLKSZ; - params.salt_size = 0 /* salt_size */; - params.salt = NULL /* salt */; -@@ -111,6 +111,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - char **signatures = NULL; - size_t sig_size; - int nr_files, idx; -+ uint16_t algo; -+ uint32_t algo32; - - Fseek(fd, 0, SEEK_SET); - rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES | -@@ -142,6 +144,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - * Should this be sigh from the cloned fd or the sigh we received? - */ - headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); -+ headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO); - - /* - * The payload doesn't include special files, like ghost files, and -@@ -153,20 +156,24 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - nr_files = rpmfiFC(hfi); - signatures = xcalloc(nr_files, sizeof(char *)); - -+ algo = FS_VERITY_HASH_ALG_SHA256; -+ - rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"), - nr_files, rpmfiFC(fi)); - - while (rpmfiNext(fi) >= 0) { - idx = rpmfiFX(fi); - -- signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); -+ signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert, -+ algo); - } - - while (rpmfiNext(hfi) >= 0) { - idx = rpmfiFX(hfi); - if (signatures[idx]) - continue; -- signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert); -+ signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert, -+ algo); - } - - rpmtdReset(&td); -@@ -187,6 +194,23 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - signatures[idx] = NULL; - } - -+ if (sig_size == 0) { -+ rpmlog(RPMLOG_ERR, _("Zero length fsverity signature\n")); -+ rc = RPMRC_FAIL; -+ goto out; -+ } -+ -+ rpmtdReset(&td); -+ -+ /* RPM doesn't like new 16 bit types, so use a 32 bit tag */ -+ algo32 = algo; -+ rpmtdReset(&td); -+ td.tag = RPMSIGTAG_VERITYSIGNATUREALGO; -+ td.type = RPM_INT32_TYPE; -+ td.data = &algo32; -+ td.count = 1; -+ headerPut(sigh, &td, HEADERPUT_DEFAULT); -+ - rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0)); - - rc = RPMRC_OK; --- -2.27.0 - diff --git a/0027-plugins-fsverity-Install-fsverity-signatures.patch b/0027-plugins-fsverity-Install-fsverity-signatures.patch deleted file mode 100644 index c302c97..0000000 --- a/0027-plugins-fsverity-Install-fsverity-signatures.patch +++ /dev/null @@ -1,257 +0,0 @@ -From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 20 Apr 2020 11:11:25 -0400 -Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures - -This plugin installs fsverity signatures for regular files, when a signature -is found in the RPM. It tries to enable them unconditionally, but fails -gracefully if fsverity isn't supported or enabled. - -Signed-off-by: Jes Sorensen ---- - configure.ac | 29 ++++++++ - macros.in | 4 + - plugins/Makefile.am | 7 ++ - plugins/fsverity.c | 177 ++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 217 insertions(+) - create mode 100644 plugins/fsverity.c - -diff --git a/configure.ac b/configure.ac -index cc7144440..7d3c31831 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1049,6 +1049,11 @@ AS_IF([test "$enable_plugins" != no],[ - ]) - AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes]) - -+AS_IF([test "$enable_plugins" != no],[ -+AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"]) -+]) -+AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes]) -+ - #================= - # Check for fapolicyd support - AC_ARG_WITH(fapolicyd, -diff --git a/macros.in b/macros.in -index fe8862903..3c722146b 100644 ---- a/macros.in -+++ b/macros.in -@@ -767,6 +767,9 @@ package or when debugging this package.\ - # a wrong or missing signature. - #%_ima_sign_config_files 0 - -+# Set to 1 to have fsverity signatures written for %config files. -+#%_fsverity_sign_config_files 0 -+ - # - # Default output format string for rpm -qa - # -@@ -1185,6 +1188,7 @@ package or when debugging this package.\ - %__transaction_syslog %{__plugindir}/syslog.so - %__transaction_ima %{__plugindir}/ima.so - %__transaction_fapolicyd %{__plugindir}/fapolicyd.so -+%__transaction_fsverity %{__plugindir}/fsverity.so - %__transaction_prioreset %{__plugindir}/prioreset.so - %__transaction_audit %{__plugindir}/audit.so - -diff --git a/plugins/Makefile.am b/plugins/Makefile.am -index cbfb81e19..e51b71f62 100644 ---- a/plugins/Makefile.am -+++ b/plugins/Makefile.am -@@ -48,3 +48,10 @@ audit_la_sources = audit.c - audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@ - plugins_LTLIBRARIES += audit.la - endif -+ -+if FSVERITY_IOCTL -+fsverity_la_sources = fsverity.c -+fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la -+plugins_LTLIBRARIES += fsverity.la -+endif -+ -diff --git a/plugins/fsverity.c b/plugins/fsverity.c -new file mode 100644 -index 000000000..15ddcf33e ---- /dev/null -+++ b/plugins/fsverity.c -@@ -0,0 +1,177 @@ -+/** -+ * Copyright (C) 2020 Facebook -+ * -+ * Author: Jes Sorensen -+ */ -+ -+#include "system.h" -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lib/rpmfs.h" -+#include "lib/rpmplugin.h" -+#include "lib/rpmte_internal.h" -+ -+#include "sign/rpmsignverity.h" -+ -+static int sign_config_files = 0; -+ -+/* -+ * This unconditionally tries to apply the fsverity signature to a file, -+ * but fails gracefully if the file system doesn't support it or the -+ * verity feature flag isn't enabled in the file system (ext4). -+ */ -+static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, -+ const char *path, const char *dest, -+ mode_t file_mode, rpmFsmOp op) -+{ -+ struct fsverity_enable_arg arg; -+ const unsigned char * signature = NULL; -+ size_t len; -+ int rc = RPMRC_OK; -+ int fd; -+ rpmFileAction action = XFO_ACTION(op); -+ char *buffer; -+ -+ /* Ignore skipped files and unowned directories */ -+ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) { -+ rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n", -+ path, dest); -+ goto exit; -+ } -+ -+ /* -+ * Do not install signatures for config files unless the -+ * user explicitly asks for it. -+ */ -+ if (rpmfiFFlags(fi) & RPMFILE_CONFIG) { -+ if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) && -+ !sign_config_files) { -+ rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n", -+ path, dest); -+ -+ goto exit; -+ } -+ } -+ -+ /* -+ * Right now fsverity doesn't deal with symlinks or directories, so do -+ * not try to install signatures for non regular files. -+ */ -+ if (!S_ISREG(rpmfiFMode(fi))) { -+ rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n", -+ path, dest); -+ goto exit; -+ } -+ -+ signature = rpmfiVSignature(fi, &len); -+ if (!signature || !len) { -+ rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n", -+ path, dest); -+ goto exit; -+ } -+ -+ memset(&arg, 0, sizeof(arg)); -+ arg.version = 1; -+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -+ arg.block_size = RPM_FSVERITY_BLKSZ; -+ arg.sig_ptr = (uintptr_t)signature; -+ arg.sig_size = len; -+ -+ buffer = pgpHexStr(signature, arg.sig_size); -+ rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer); -+ free(buffer); -+ -+ fd = open(path, O_RDONLY); -+ if (fd < 0) { -+ rpmlog(RPMLOG_ERR, "failed to open path %s\n", path); -+ goto exit; -+ } -+ -+ /* -+ * Enable fsverity on the file. -+ * fsverity not supported by file system (ENOTTY) and fsverity not -+ * enabled on file system are expected and not considered -+ * errors. Every other non-zero error code will result in the -+ * installation failing. -+ */ -+ if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) { -+ switch(errno) { -+ case EBADMSG: -+ rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path); -+ rc = RPMRC_FAIL; -+ break; -+ case EEXIST: -+ rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n", -+ path); -+ rc = RPMRC_FAIL; -+ break; -+ case EINVAL: -+ rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path); -+ rc = RPMRC_FAIL; -+ break; -+ case EKEYREJECTED: -+ rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path); -+ rc = RPMRC_FAIL; -+ break; -+ case EMSGSIZE: -+ rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path); -+ rc = RPMRC_FAIL; -+ break; -+ case ENOPKG: -+ rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n", -+ arg.hash_algorithm, path); -+ rc = RPMRC_FAIL; -+ break; -+ case ETXTBSY: -+ rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n", -+ path); -+ rc = RPMRC_FAIL; -+ break; -+ case ENOTTY: -+ rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n", -+ path); -+ break; -+ case EOPNOTSUPP: -+ rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n", -+ path); -+ break; -+ default: -+ rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n", -+ errno, path); -+ rc = RPMRC_FAIL; -+ break; -+ } -+ } -+ -+ rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n", -+ path, dest); -+ close(fd); -+exit: -+ return rc; -+} -+ -+static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts) -+{ -+ sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}"); -+ -+ rpmlog(RPMLOG_DEBUG, "fsverity_init\n"); -+ -+ return RPMRC_OK; -+} -+ -+struct rpmPluginHooks_s fsverity_hooks = { -+ .init = fsverity_init, -+ .fsm_file_prepare = fsverity_fsm_file_prepare, -+}; --- -2.27.0 - diff --git a/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/0028-fsverity-plugin-Use-tag-for-algorithm.patch deleted file mode 100644 index 0b9bb41..0000000 --- a/0028-fsverity-plugin-Use-tag-for-algorithm.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 20 Apr 2020 14:13:51 -0400 -Subject: [PATCH 28/33] fsverity plugin: Use tag for algorithm - -This uses the algorithm from the tag, if available. Fallback is SHA256. - -Signed-off-by: Jes Sorensen ---- - lib/rpmfi.c | 9 ++++++--- - lib/rpmfi.h | 3 ++- - lib/rpmfiles.h | 3 ++- - plugins/fsverity.c | 8 ++++++-- - 4 files changed, 16 insertions(+), 7 deletions(-) - -diff --git a/lib/rpmfi.c b/lib/rpmfi.c -index 70f05f509..3e2b4e676 100644 ---- a/lib/rpmfi.c -+++ b/lib/rpmfi.c -@@ -585,7 +585,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len) - return signature; - } - --const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) -+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len, -+ uint16_t *algo) - { - const unsigned char *vsignature = NULL; - -@@ -594,6 +595,8 @@ const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) - vsignature = fi->veritysigs + (fi->veritysiglength * ix); - if (len) - *len = fi->veritysiglength; -+ if (algo) -+ *algo = fi->verityalgo; - } - return vsignature; - } -@@ -1963,9 +1966,9 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len) - return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len); - } - --const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len) -+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len, uint16_t *algo) - { -- return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len); -+ return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len, algo); - } - - uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp) -diff --git a/lib/rpmfi.h b/lib/rpmfi.h -index fcb9d3acd..6fd2747d6 100644 ---- a/lib/rpmfi.h -+++ b/lib/rpmfi.h -@@ -194,9 +194,10 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen); - * Return current verity (binary) signature of file info set iterator. - * @param fi file info set iterator - * @retval siglen signature length (pass NULL to ignore) -+ * @retval algo fsverity algorithm - * @return current verity signature, NULL on invalid - */ --const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen); -+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen, uint16_t *algo); - - /** \ingroup rpmfi - * Return current file linkto (i.e. symlink(2) target) from file info set iterator. -diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h -index 81b3d01a1..64b33281a 100644 ---- a/lib/rpmfiles.h -+++ b/lib/rpmfiles.h -@@ -450,7 +450,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len); - * @retval len signature length (pass NULL to ignore) - * @return verity signature, NULL on invalid - */ --const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len); -+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len, -+ uint16_t *algo); - - /** \ingroup rpmfiles - * Return file rdev from file info set. -diff --git a/plugins/fsverity.c b/plugins/fsverity.c -index 15ddcf33e..1e7f38b38 100644 ---- a/plugins/fsverity.c -+++ b/plugins/fsverity.c -@@ -39,6 +39,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, - struct fsverity_enable_arg arg; - const unsigned char * signature = NULL; - size_t len; -+ uint16_t algo = 0; - int rc = RPMRC_OK; - int fd; - rpmFileAction action = XFO_ACTION(op); -@@ -75,7 +76,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, - goto exit; - } - -- signature = rpmfiVSignature(fi, &len); -+ signature = rpmfiVSignature(fi, &len, &algo); - if (!signature || !len) { - rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n", - path, dest); -@@ -84,7 +85,10 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, - - memset(&arg, 0, sizeof(arg)); - arg.version = 1; -- arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; -+ if (algo) -+ arg.hash_algorithm = algo; -+ else -+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; - arg.block_size = RPM_FSVERITY_BLKSZ; - arg.sig_ptr = (uintptr_t)signature; - arg.sig_size = len; --- -2.27.0 - diff --git a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch deleted file mode 100644 index 6575b99..0000000 --- a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 20 Apr 2020 18:52:08 -0400 -Subject: [PATCH 29/33] Add fsverity tags to rpmgeneral.at - -Make sure we pass the checks with the new tags in place. - -Signed-off-by: Jes Sorensen ---- - tests/rpmgeneral.at | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at -index 45d38698b..8a7dc827f 100644 ---- a/tests/rpmgeneral.at -+++ b/tests/rpmgeneral.at -@@ -291,6 +291,8 @@ VERBOSE - VERIFYSCRIPT - VERIFYSCRIPTFLAGS - VERIFYSCRIPTPROG -+VERITYSIGNATUREALGO -+VERITYSIGNATURES - VERSION - XPM - ]) --- -2.27.0 - diff --git a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch deleted file mode 100644 index d872d5e..0000000 --- a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Mon, 13 Apr 2020 18:24:31 -0400 -Subject: [PATCH 30/33] Add --delfilesign flag to delete IMA and fsverity file - signatures - -This allows a user to remove both types of file signatures from the -package. Previously there was no way to delete IMA signatures, only -replace them by first removing the package signature and then -resigning the package and the files. - -Signed-off-by: Jes Sorensen ---- - rpmsign.c | 12 ++++++++++++ - sign/rpmgensig.c | 17 ++++++++++++++++- - sign/rpmsign.h | 9 +++++++++ - 3 files changed, 37 insertions(+), 1 deletion(-) - -diff --git a/rpmsign.c b/rpmsign.c -index 074dd8b13..e43811e9f 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -14,6 +14,7 @@ enum modes { - MODE_ADDSIGN = (1 << 0), - MODE_RESIGN = (1 << 1), - MODE_DELSIGN = (1 << 2), -+ MODE_DELFILESIGN = (1 << 3), - }; - - static int mode = MODE_NONE; -@@ -35,6 +36,10 @@ static struct poptOption signOptsTable[] = { - N_("sign package(s) (identical to --addsign)"), NULL }, - { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN, - N_("delete package signatures"), NULL }, -+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) -+ { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, -+ MODE_DELFILESIGN, N_("delete IMA and fsverity file signatures"), NULL }, -+#endif - { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), - &sargs.signflags, RPMSIGN_FLAG_RPMV3, - N_("create rpm v3 header+payload signatures") }, -@@ -207,6 +212,13 @@ int main(int argc, char *argv[]) - ec++; - } - break; -+ case MODE_DELFILESIGN: -+ ec = 0; -+ while ((arg = poptGetArg(optCon)) != NULL) { -+ if (rpmPkgDelFileSign(arg, &sargs) < 0) -+ ec++; -+ } -+ break; - case MODE_NONE: - printUsage(optCon, stderr, 0); - break; -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index 8d5c5858f..02cf0bc62 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -336,6 +336,14 @@ static void deleteSigs(Header sigh) - headerDel(sigh, RPMSIGTAG_PGP5); - } - -+static void deleteFileSigs(Header sigh) -+{ -+ headerDel(sigh, RPMSIGTAG_FILESIGNATURELENGTH); -+ headerDel(sigh, RPMSIGTAG_FILESIGNATURES); -+ headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); -+ headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO); -+} -+ - static int haveSignature(rpmtd sigtd, Header h) - { - pgpDigParams sig1 = NULL; -@@ -580,7 +588,9 @@ static int rpmSign(const char *rpm, int deleting, int flags) - goto exit; - } - -- if (deleting) { /* Nuke all the signature tags. */ -+ if (deleting == 2) { /* Nuke IMA + fsverity file signature tags. */ -+ deleteFileSigs(sigh); -+ } else if (deleting) { /* Nuke all the signature tags. */ - deleteSigs(sigh); - } else { - /* Signature target containing header + payload */ -@@ -745,3 +755,8 @@ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args) - { - return rpmSign(path, 1, 0); - } -+ -+int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args) -+{ -+ return rpmSign(path, 2, 0); -+} -diff --git a/sign/rpmsign.h b/sign/rpmsign.h -index 2b8a10a1a..5169741dd 100644 ---- a/sign/rpmsign.h -+++ b/sign/rpmsign.h -@@ -44,6 +44,15 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args); - */ - int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args); - -+ -+/** \ingroup rpmsign -+ * Delete file signature(s) from a package -+ * @param path path to package -+ * @param args signing parameters (or NULL for defaults) -+ * @return 0 on success -+ */ -+int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args); -+ - #ifdef __cplusplus - } - #endif --- -2.27.0 - diff --git a/0031-Update-man-page-for-rpmsign.patch b/0031-Update-man-page-for-rpmsign.patch deleted file mode 100644 index 938e0f1..0000000 --- a/0031-Update-man-page-for-rpmsign.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Tue, 12 May 2020 13:42:34 -0400 -Subject: [PATCH 31/33] Update man page for rpmsign - -This documents the new arguments --signverity and --certpath required -to sign a package with fsverity signatures. - -Signed-off-by: Jes Sorensen ---- - doc/rpmsign.8 | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 -index f7ceae89b..a212746fe 100644 ---- a/doc/rpmsign.8 -+++ b/doc/rpmsign.8 -@@ -9,6 +9,8 @@ rpmsign \- RPM Package Signing - - \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR - -+\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR -+ - .SS "rpmsign-options" - .PP - [\fb--rpmv3\fR] -@@ -30,6 +32,12 @@ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode. - .PP - Delete all signatures from each package \fIPACKAGE_FILE\fR given. - -+\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR -+ -+.PP -+Delete all IMA and fsverity file signatures from each package -+\fIPACKAGE_FILE\fR given. -+ - .SS "SIGN OPTIONS" - .PP - .TP -@@ -44,12 +52,23 @@ signature verifiable with rpm < 4.14 or other interoperability reasons. - \fB--fskpath \fIKEY\fB\fR - Used with \fB--signfiles\fR, use file signing key \fIKey\fR. - .TP -+\fB--certpath \fICERT\fB\fR -+Used with \fB--signverity\fR, use file signing certificate \fICert\fR. -+.TP - \fB--signfiles\fR - Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must - be set to a supported algorithm before building the package. The - supported algorithms are SHA1, SHA256, SHA384, and SHA512, which are - represented as 2, 8, 9, and 10 respectively. The file signing key (RSA - private key) must be set before signing the package, it can be configured on the command line with \fB--fskpath\fR or the macro %_file_signing_key. -+.TP -+\fB--signverity\fR -+Sign package files with fsverity signatures. The file signing key (RSA -+private key) and the signing certificate must be set before signing -+the package. The key can be configured on the command line with -+\fB--fskpath\fR or the macro %_file_signing_key, and the cert can be -+configured on the command line with \fB--certpath\fR or the macro -+%_file_signing_cert. - - .SS "USING GPG TO SIGN PACKAGES" - .PP -@@ -110,4 +129,5 @@ Jeff Johnson - Erik Troan - Panu Matilainen - Fionnuala Gunter -+Jes Sorensen - .fi --- -2.27.0 - diff --git a/0031-rpmcow-denylist.patch b/0031-rpmcow-denylist.patch index da7aee3..676d8be 100644 --- a/0031-rpmcow-denylist.patch +++ b/0031-rpmcow-denylist.patch @@ -13,6 +13,15 @@ Date: Wed Oct 19 23:05:17 2022 +0200 specific packages. Signed-off-by: Richard Phibel +--- + build/pack.c | 2 +- + lib/package.c | 6 +-- + lib/rpmlead.c | 43 +++++++++--------- + lib/rpmlead.h | 37 +++++++++++++++- + rpm2extents.c | 102 ++++++++++++++++++++++++++++++++----------- + sign/rpmgensig.c | 2 +- + tests/rpm2extents.at | 11 +++++ + 7 files changed, 148 insertions(+), 55 deletions(-) diff --git a/build/pack.c b/build/pack.c index 8d6f74935ebb8a4d65aa2bcb666825a99162be9c..e2f05b6412d3e0d814a1160a0dcdfad5c323a8f8 100644 @@ -31,7 +40,7 @@ diff --git a/lib/package.c b/lib/package.c index 90bd0d8a719353e8965c140b40e2dceef80a2ed1..fd41abbf6b4df07afa2caf1c47d9724765ee84e8 100644 --- a/lib/package.c +++ b/lib/package.c -@@ -412,11 +412,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp) +@@ -410,11 +410,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp) Header h = NULL; Header sigh = NULL; @@ -353,7 +362,7 @@ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c index b4897f1de444080c8dc6c4913b5f33de20796822..d54e254ff41a0441d04fbcf27f26e4809f563b79 100644 --- a/sign/rpmgensig.c +++ b/sign/rpmgensig.c -@@ -672,7 +672,7 @@ static int rpmSign(const char *rpm, int deleting, int flags) +@@ -610,7 +610,7 @@ static int rpmSign(const char *rpm, int deleting, int flags) } /* Write the lead/signature of the output rpm */ diff --git a/0032-rpmcow-workaround.patch b/0032-rpmcow-workaround.patch index 69d5178..57e9f44 100644 --- a/0032-rpmcow-workaround.patch +++ b/0032-rpmcow-workaround.patch @@ -1,7 +1,5 @@ From: Richard Phibel -Subject: RPM with Copy on Write: workaround for corrupt signature header - commit 7976c921f60ec5d20c50c4c702ec5636b39210ba Author: Richard Phibel Date: Wed Oct 26 18:57:19 2022 +0200 @@ -14,6 +12,9 @@ Date: Wed Oct 26 18:57:19 2022 +0200 unloadImmutableRegion. Signed-off-by: Richard Phibel +--- + rpm2extents.c | 281 +++++++++++++++++++++++++++----------------------- + 1 file changed, 153 insertions(+), 128 deletions(-) diff --git a/rpm2extents.c b/rpm2extents.c index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644 diff --git a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch deleted file mode 100644 index 6a20363..0000000 --- a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Wed, 10 Jun 2020 12:30:54 -0400 -Subject: [PATCH 32/33] rpmsign: Add argument to specify algorithm for fsverity - signatures - -The argument --verity-algo can be used to specify the algorithm for -the fsverity signatures. If nothing is specified, this will default to -sha256. The available algorithms depend on libfsverity, currently -sha256 and sha512 are supported. - -Signed-off-by: Jes Sorensen ---- - doc/rpmsign.8 | 3 +++ - rpmsign.c | 7 +++++++ - sign/rpmgensig.c | 22 ++++++++++++++++++++-- - sign/rpmsignverity.c | 6 +++--- - sign/rpmsignverity.h | 2 +- - 5 files changed, 34 insertions(+), 6 deletions(-) - -diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 -index a212746fe..5165e39f9 100644 ---- a/doc/rpmsign.8 -+++ b/doc/rpmsign.8 -@@ -55,6 +55,9 @@ Used with \fB--signfiles\fR, use file signing key \fIKey\fR. - \fB--certpath \fICERT\fB\fR - Used with \fB--signverity\fR, use file signing certificate \fICert\fR. - .TP -+\fB--verityalgo \fIALG\fB\fR -+Used with \fB--signverity\fR, to specify the signing algorithm. sha256 and sha512 are supported, with sha256 being the default if this argument is not specified. This can also be specified with the macro %_verity_algorithm -+.TP - \fB--signfiles\fR - Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must - be set to a supported algorithm before building the package. The -diff --git a/rpmsign.c b/rpmsign.c -index e43811e9f..12299379c 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -25,6 +25,7 @@ static char * fileSigningKey = NULL; - #endif - #ifdef WITH_FSVERITY - static char * fileSigningCert = NULL; -+static char * verityAlgorithm = NULL; - #endif - - static struct rpmSignArgs sargs = {NULL, 0, 0}; -@@ -52,6 +53,9 @@ static struct poptOption signOptsTable[] = { - { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), - &sargs.signflags, RPMSIGN_FLAG_FSVERITY, - N_("generate fsverity signatures for package(s) files"), NULL}, -+ { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0, -+ N_("algorithm to use for verity signatures, default sha256"), -+ N_("") }, - { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, - N_("use file signing cert "), - N_("") }, -@@ -138,6 +142,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - if (fileSigningCert) { - rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); - } -+ if (verityAlgorithm) { -+ rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL); -+ } - #endif - - if (flags_sign_files(sargs->signflags)) { -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index 02cf0bc62..b3b02828a 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -8,6 +8,10 @@ - #include - #include - #include -+#include -+#ifdef WITH_FSVERITY -+#include -+#endif - - #include /* RPMSIGTAG & related */ - #include -@@ -458,23 +462,37 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) - static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) - { - #ifdef WITH_FSVERITY -- rpmRC rc; -+ rpmRC rc = RPMRC_OK; - char *key = rpmExpand("%{?_file_signing_key}", NULL); - char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL); - char *cert = rpmExpand("%{?_file_signing_cert}", NULL); -+ char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL); -+ uint16_t algo = 0; - - if (rstreq(keypass, "")) { - free(keypass); - keypass = NULL; - } - -+ if (algorithm && strlen(algorithm) > 0) { -+ algo = libfsverity_find_hash_alg_by_name(algorithm); -+ rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"), -+ algorithm, algo); -+ if (!algo) { -+ rpmlog(RPMLOG_ERR, _("Unsupported fsverity algorithm %s\n"), -+ algorithm); -+ rc = RPMRC_FAIL; -+ goto out; -+ } -+ } - if (key && cert) { -- rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert); -+ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo); - } else { - rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n")); - rc = RPMRC_FAIL; - } - -+ out: - free(keypass); - free(key); - free(cert); -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index 55096e732..e6c830cdc 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -95,7 +95,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - } - - rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -- char *keypass, char *cert) -+ char *keypass, char *cert, uint16_t algo) - { - int rc; - FD_t gzdi; -@@ -111,7 +111,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - char **signatures = NULL; - size_t sig_size; - int nr_files, idx; -- uint16_t algo; - uint32_t algo32; - - Fseek(fd, 0, SEEK_SET); -@@ -156,7 +155,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - nr_files = rpmfiFC(hfi); - signatures = xcalloc(nr_files, sizeof(char *)); - -- algo = FS_VERITY_HASH_ALG_SHA256; -+ if (!algo) -+ algo = FS_VERITY_HASH_ALG_SHA256; - - rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"), - nr_files, rpmfiFC(fi)); -diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h -index 69bbaf7f7..d869e8d8e 100644 ---- a/sign/rpmsignverity.h -+++ b/sign/rpmsignverity.h -@@ -27,7 +27,7 @@ extern "C" { - */ - RPM_GNUC_INTERNAL - rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -- char *keypass, char *cert); -+ char *keypass, char *cert, uint16_t algo); - - #ifdef _cplusplus - } --- -2.27.0 - diff --git a/0033-Enable-fsverity-in-CI.patch b/0033-Enable-fsverity-in-CI.patch deleted file mode 100644 index 0fc6fde..0000000 --- a/0033-Enable-fsverity-in-CI.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001 -From: Jes Sorensen -Date: Fri, 28 Aug 2020 11:10:41 -0400 -Subject: [PATCH 33/33] Enable fsverity in CI - -Add fsverity-utils and fsverity-utils-devel as dependencies. - -Signed-off-by: Jes Sorensen ---- - Makefile.am | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Makefile.am b/Makefile.am -index 8e92f0cde..3c1451049 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -17,6 +17,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ - --with-selinux \ - --with-imaevm \ - --with-fapolicyd \ -+ --with-fsverity \ - --disable-dependency-tracking - - include $(top_srcdir)/rpm.am --- -2.27.0 - diff --git a/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch b/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch deleted file mode 100644 index 692ab33..0000000 --- a/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch +++ /dev/null @@ -1,257 +0,0 @@ -From aee5af8e4fe7908df90649eb699c3a1decf06b0c Mon Sep 17 00:00:00 2001 -From: Yu Wu -Date: Wed, 3 Nov 2021 23:13:15 -0700 -Subject: [PATCH 1/2] rpmsign: Adopting PKCS#11 opaque keys support in - libfsverity for fsverity signatures - ---- - rpmsign.c | 29 ++++++++++++++++++++---- - sign/rpmgensig.c | 53 +++++++++++++++++++++++++++++++++++++++----- - sign/rpmsignverity.c | 24 +++++++++++++------- - sign/rpmsignverity.h | 9 +++++--- - 4 files changed, 94 insertions(+), 21 deletions(-) - -diff --git a/rpmsign.c b/rpmsign.c -index 12299379ce..63b8616382 100644 ---- a/rpmsign.c -+++ b/rpmsign.c -@@ -24,6 +24,9 @@ static int fskpass = 0; - static char * fileSigningKey = NULL; - #endif - #ifdef WITH_FSVERITY -+static char * pkcs11Engine = NULL; -+static char * pkcs11Module = NULL; -+static char * pkcs11KeyId = NULL; - static char * fileSigningCert = NULL; - static char * verityAlgorithm = NULL; - #endif -@@ -59,6 +62,15 @@ static struct poptOption signOptsTable[] = { - { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, - N_("use file signing cert "), - N_("") }, -+ { "pkcs11_engine", '\0', POPT_ARG_STRING, &pkcs11Engine, 0, -+ N_("use pkcs#11 token for fsverity signing key with openssl engine "), -+ N_("") }, -+ { "pkcs11_module", '\0', POPT_ARG_STRING, &pkcs11Module, 0, -+ N_("use pkcs#11 token for fsverity signing key with openssl module "), -+ N_("") }, -+ { "pkcs11_keyid", '\0', POPT_ARG_STRING, &pkcs11KeyId, 0, -+ N_("use pkcs#11 token for fsverity signing key with keyid "), -+ N_("") }, - #endif - #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) - { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, -@@ -139,6 +151,15 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - } - - #ifdef WITH_FSVERITY -+ if (pkcs11Engine) { -+ rpmPushMacro(NULL, "_pkcs11_engine", NULL, pkcs11Engine, RMIL_GLOBAL); -+ } -+ if (pkcs11Module) { -+ rpmPushMacro(NULL, "_pkcs11_module", NULL, pkcs11Module, RMIL_GLOBAL); -+ } -+ if (pkcs11KeyId) { -+ rpmPushMacro(NULL, "_pkcs11_keyid", NULL, pkcs11KeyId, RMIL_GLOBAL); -+ } - if (fileSigningCert) { - rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); - } -@@ -149,9 +170,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - - if (flags_sign_files(sargs->signflags)) { - char *fileSigningKeyPassword = NULL; -- char *key = rpmExpand("%{?_file_signing_key}", NULL); -- if (rstreq(key, "")) { -- fprintf(stderr, _("You must set \"%%_file_signing_key\" in your macro file or on the command line with --fskpath\n")); -+ char *cert = rpmExpand("%{?_file_signing_cert}", NULL); -+ if (rstreq(cert, "")) { -+ fprintf(stderr, _("You must set \"%%_file_signing_cert\" in your macro file or on the command line with --certpath\n")); - goto exit; - } - -@@ -166,7 +187,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) - free(fileSigningKeyPassword); - } - -- free(key); -+ free(cert); - } - #endif - -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index d8c84e9377..cb264679b6 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -461,15 +461,56 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) - rpmRC rc = RPMRC_OK; - char *key = rpmExpand("%{?_file_signing_key}", NULL); - char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL); -+ char *pkcs11_engine = rpmExpand("%{?_pkcs11_engine}", NULL); -+ char *pkcs11_module = rpmExpand("%{?_pkcs11_module}", NULL); -+ char *pkcs11_keyid = rpmExpand("%{?_pkcs11_keyid}", NULL); - char *cert = rpmExpand("%{?_file_signing_cert}", NULL); - char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL); - uint16_t algo = 0; - -+ if (rstreq(key, "")) { -+ free(key); -+ key = NULL; -+ } -+ -+ if (rstreq(pkcs11_engine, "")) { -+ free(pkcs11_engine); -+ pkcs11_engine = NULL; -+ } -+ -+ if (rstreq(pkcs11_module, "")) { -+ free(pkcs11_module); -+ pkcs11_module = NULL; -+ } -+ -+ if (rstreq(pkcs11_keyid, "")) { -+ free(pkcs11_keyid); -+ pkcs11_keyid = NULL; -+ } -+ - if (rstreq(keypass, "")) { - free(keypass); - keypass = NULL; - } - -+ if (key) { -+ if (pkcs11_engine || pkcs11_module || pkcs11_keyid) { -+ rpmlog( -+ RPMLOG_ERR, -+ _("fsverity signatures require a key specified either by file or by PKCS#11 token, not both\n")); -+ rc = RPMRC_FAIL; -+ goto out; -+ } -+ } else { -+ if (!pkcs11_engine || !pkcs11_module) { -+ rpmlog( -+ RPMLOG_ERR, -+ _("fsverity signatures require both PKCS#11 engine and module to use PKCS#11 token\n")); -+ rc = RPMRC_FAIL; -+ goto out; -+ } -+ } -+ - if (algorithm && strlen(algorithm) > 0) { - algo = libfsverity_find_hash_alg_by_name(algorithm); - rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"), -@@ -481,16 +522,16 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) - goto out; - } - } -- if (key && cert) { -- rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo); -- } else { -- rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n")); -- rc = RPMRC_FAIL; -- } -+ -+ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, -+ pkcs11_engine, pkcs11_module, pkcs11_keyid, cert, algo); - - out: - free(keypass); - free(key); -+ free(pkcs11_engine); -+ free(pkcs11_module); -+ free(pkcs11_keyid); - free(cert); - return rc; - #else -diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c -index e6c830cdcb..b7924e7ad1 100644 ---- a/sign/rpmsignverity.c -+++ b/sign/rpmsignverity.c -@@ -34,8 +34,9 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size) - return retval; - } - --static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, -- char *keypass, char *cert, uint16_t algo) -+static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, char *keypass, -+ char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid, -+ char *cert, uint16_t algo) - { - struct libfsverity_merkle_tree_params params; - struct libfsverity_signature_params sig_params; -@@ -76,6 +77,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - - memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); - sig_params.keyfile = key; -+ sig_params.pkcs11_engine = pkcs11_engine; -+ sig_params.pkcs11_module = pkcs11_module; -+ sig_params.pkcs11_keyid = pkcs11_keyid; - sig_params.certfile = cert; - if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) { - rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); -@@ -94,8 +98,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, - return sig_base64; - } - --rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -- char *keypass, char *cert, uint16_t algo) -+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass, -+ char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid, -+ char *cert, uint16_t algo) - { - int rc; - FD_t gzdi; -@@ -125,6 +130,9 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - } - - rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key); -+ rpmlog(RPMLOG_DEBUG, _("pkcs11_engine: %s\n"), pkcs11_engine); -+ rpmlog(RPMLOG_DEBUG, _("pkcs11_module: %s\n"), pkcs11_module); -+ rpmlog(RPMLOG_DEBUG, _("pkcs11_keyid: %s\n"), pkcs11_keyid); - rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert); - - compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -@@ -164,16 +172,16 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, - while (rpmfiNext(fi) >= 0) { - idx = rpmfiFX(fi); - -- signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert, -- algo); -+ signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine, -+ pkcs11_module, pkcs11_keyid, cert, algo); - } - - while (rpmfiNext(hfi) >= 0) { - idx = rpmfiFX(hfi); - if (signatures[idx]) - continue; -- signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert, -- algo); -+ signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine, -+ pkcs11_module, pkcs11_keyid, cert, algo); - } - - rpmtdReset(&td); -diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h -index d869e8d8e8..32d2d6359a 100644 ---- a/sign/rpmsignverity.h -+++ b/sign/rpmsignverity.h -@@ -22,12 +22,15 @@ extern "C" { - * @param h package header - * @param key signing key - * @param keypass signing key password -+ * @param pkcs11_engine PKCS#11 engine to use PKCS#11 token support for signing key -+ * @param pkcs11_module PKCS#11 module to use PKCS#11 token support for signing key -+ * @param pkcs11_keyid PKCS#11 key identifier - * @param cert signing cert - * @return RPMRC_OK on success - */ --RPM_GNUC_INTERNAL --rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, -- char *keypass, char *cert, uint16_t algo); -+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass, -+ char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid, -+ char *cert, uint16_t algo); - - #ifdef _cplusplus - } diff --git a/0036-bsearchr_static.patch b/0036-bsearchr_static.patch new file mode 100644 index 0000000..fe8e8fc --- /dev/null +++ b/0036-bsearchr_static.patch @@ -0,0 +1,11 @@ +--- a/plugins/reflink.c ++++ b/plugins/reflink.c +@@ -63,7 +63,7 @@ typedef struct reflink_state_s * reflink_state; + * bsearch_r: implements a re-entrant version of stdlib's bsearch. + * code taken and adapted from /usr/include/bits/stdlib-bsearch.h + */ +-inline void * ++static void * + bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size, + __compar_d_fn_t __compar, void *__arg) + { diff --git a/0037-plugin_path.patch b/0037-plugin_path.patch new file mode 100644 index 0000000..3ba625f --- /dev/null +++ b/0037-plugin_path.patch @@ -0,0 +1,35 @@ +--- a/plugins/reflink.c ++++ b/plugins/reflink.c +@@ -277,13 +277,17 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa + fcr.dest_offset = 0; + if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { + rpm_ino_t inode = rpmfiFInode(fi); ++ char fullpath[PATH_MAX]; ++ ++ snprintf(fullpath, sizeof(fullpath), "%s/%s", rpmfiDN(fi), path); ++ + /* check for hard link entry in table. GetEntry overwrites hlix with + * the address of the first match. + */ + if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target, + NULL, NULL)) { + /* entry is in table, use hard link */ +- if (link(hl_target[0], path) != 0) { ++ if (link(hl_target[0], fullpath) != 0) { + rpmlog(RPMLOG_ERR, + _("reflink: Unable to hard link %s -> %s due to %s\n"), + hl_target[0], path, strerror(errno)); +@@ -296,11 +300,11 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa + */ + if (rpmfiFNlink(fi) > 1) { + /* minor optimization: only store files with more than one link */ +- inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path)); ++ inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(fullpath)); + } + /* derived from wfd_open in fsm.c */ + mode_t old_umask = umask(0577); +- dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); ++ dst = open(fullpath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); + umask(old_umask); + if (dst == -1) { + rpmlog(RPMLOG_ERR, diff --git a/1534.patch b/1534.patch deleted file mode 100644 index e2a7cf6..0000000 --- a/1534.patch +++ /dev/null @@ -1,1162 +0,0 @@ -From 22d18785b2c41f1a8937b712920b4342f7596a7e Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Mon, 8 Feb 2021 10:45:59 +0200 -Subject: [PATCH 1/9] Clean up file unpack iteration logic a bit - -Handle rpmfiNext() in the while-condition directly to make it more like -similar other constructs elsewhere, adjust for the end of iteration -code after the loop. Also take the file index from rpmfiNext() so -we don't need multiple calls to rpmfiFX() later. ---- - lib/fsm.c | 19 +++++++------------ - 1 file changed, 7 insertions(+), 12 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 35dcda081c..7c291adb02 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -841,6 +841,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct stat sb; - int saveerrno = errno; - int rc = 0; -+ int fx = -1; - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; - int firsthardlink = -1; -@@ -862,17 +863,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Detect and create directories not explicitly in package. */ - rc = fsmMkdirs(files, fs, plugins); - -- while (!rc) { -- /* Read next payload header. */ -- rc = rpmfiNext(fi); -- -- if (rc < 0) { -- if (rc == RPMERR_ITER_END) -- rc = 0; -- break; -- } -- -- action = rpmfsGetAction(fs, rpmfiFX(fi)); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ action = rpmfsGetAction(fs, fx); - skip = XFA_SKIPPING(action); - if (action != FA_TOUCH) { - suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -@@ -896,7 +888,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (rc) { - skip = 1; - } else { -- setFileState(fs, rpmfiFX(fi)); -+ setFileState(fs, fx); - } - - if (!skip) { -@@ -1005,6 +997,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - fpath = _free(fpath); - } - -+ if (!rc && fx != RPMERR_ITER_END) -+ rc = fx; -+ - rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); - - -From c0dc57b820791dd76ce8baafac59b9a58ab0f0d3 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 08:25:28 +0200 -Subject: [PATCH 2/9] Drop unused filename variable - ---- - lib/fsm.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 7c291adb02..41b6267ddc 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -959,11 +959,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ - /* write the content to the first used instead */ -- char *fn = rpmfilesFN(files, firsthardlink); - rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); - wfd_close(&firstlinkfile); - firsthardlink = -1; -- free(fn); - } - - if (rc) { - -From dcb5791066afd5caa1003a5d35903a7f5dc79cc2 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 09:57:17 +0200 -Subject: [PATCH 3/9] Don't update path info if rename failed on file commit - ---- - lib/fsm.c | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 41b6267ddc..c581a918a5 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -773,14 +773,16 @@ static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *su - /* Rename temporary to final file name if needed. */ - if (dest != *path) { - rc = fsmRename(*path, dest); -- if (!rc && nsuffix) { -- char * opath = fsmFsPath(fi, NULL); -- rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), -- opath, dest); -- free(opath); -+ if (!rc) { -+ if (nsuffix) { -+ char * opath = fsmFsPath(fi, NULL); -+ rpmlog(RPMLOG_WARNING, _("%s created as %s\n"), -+ opath, dest); -+ free(opath); -+ } -+ free(*path); -+ *path = dest; - } -- free(*path); -- *path = dest; - } - } - - -From 7fdf248e7d29a244b97c46b19be0df64992fdfae Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 09:47:19 +0200 -Subject: [PATCH 4/9] Refactor file install and remove around a common struct - -Collect the common state info into a struct shared by both file install -and remove, update code accordingly. The change looks much more drastic -than it is - it's just adding fp-> prefix to a lot of places. -While we're at it, remember the state data throughout the operation. - -No functional changes here, just paving way for the next steps which -will look clearer with these pre-requisites in place. ---- - lib/fsm.c | 158 +++++++++++++++++++++++++++++------------------------- - 1 file changed, 85 insertions(+), 73 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index c581a918a5..9dba30560f 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -38,6 +38,14 @@ static int strict_erasures = 0; - #define _dirPerms 0755 - #define _filePerms 0644 - -+struct filedata_s { -+ int skip; -+ rpmFileAction action; -+ const char *suffix; -+ char *fpath; -+ struct stat sb; -+}; -+ - /* - * XXX Forward declarations for previously exported functions to avoid moving - * things around needlessly -@@ -840,19 +848,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- struct stat sb; - int saveerrno = errno; - int rc = 0; - int fx = -1; -+ int fc = rpmfilesFC(files); - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; - int firsthardlink = -1; - FD_t firstlinkfile = NULL; -- int skip; -- rpmFileAction action; - char *tid = NULL; -- const char *suffix; -- char *fpath = NULL; -+ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - - if (fi == NULL) { - rc = RPMERR_BAD_MAGIC; -@@ -866,96 +871,99 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = fsmMkdirs(files, fs, plugins); - - while (!rc && (fx = rpmfiNext(fi)) >= 0) { -- action = rpmfsGetAction(fs, fx); -- skip = XFA_SKIPPING(action); -- if (action != FA_TOUCH) { -- suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -+ struct filedata_s *fp = &fdata[fx]; -+ fp->action = rpmfsGetAction(fs, fx); -+ fp->skip = XFA_SKIPPING(fp->action); -+ if (fp->action != FA_TOUCH) { -+ fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - } else { -- suffix = NULL; -+ fp->suffix = NULL; - } -- fpath = fsmFsPath(fi, suffix); -+ fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ -- rc = rpmfiStat(fi, 1, &sb); -+ rc = rpmfiStat(fi, 1, &fp->sb); - -- fsmDebug(fpath, action, &sb); -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Exit on error. */ - if (rc) - break; - - /* Run fsm file pre hook for all plugins */ -- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, -- sb.st_mode, action); -+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action); - if (rc) { -- skip = 1; -+ fp->skip = 1; - } else { - setFileState(fs, fx); - } - -- if (!skip) { -+ if (!fp->skip) { - int setmeta = 1; - - /* Directories replacing something need early backup */ -- if (!suffix) { -- rc = fsmBackup(fi, action); -+ if (!fp->suffix) { -+ rc = fsmBackup(fi, fp->action); - } - /* Assume file does't exist when tmp suffix is in use */ -- if (!suffix) { -- rc = fsmVerify(fpath, fi); -+ if (!fp->suffix) { -+ rc = fsmVerify(fp->fpath, fi); - } else { - rc = RPMERR_ENOENT; - } - - /* See if the file was removed while our attention was elsewhere */ -- if (rc == RPMERR_ENOENT && action == FA_TOUCH) { -- rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); -- action = FA_CREATE; -- fsmDebug(fpath, action, &sb); -+ if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) { -+ rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", -+ fp->fpath); -+ fp->action = FA_CREATE; -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - } - - /* When touching we don't need any of this... */ -- if (action == FA_TOUCH) -+ if (fp->action == FA_TOUCH) - goto touch; - -- if (S_ISREG(sb.st_mode)) { -+ if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fpath, files, psm, nodigest, -+ rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, - &setmeta, &firsthardlink, &firstlinkfile); - } -- } else if (S_ISDIR(sb.st_mode)) { -+ } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- mode_t mode = sb.st_mode; -+ mode_t mode = fp->sb.st_mode; - mode &= ~07777; - mode |= 00700; -- rc = fsmMkdir(fpath, mode); -+ rc = fsmMkdir(fp->fpath, mode); - } -- } else if (S_ISLNK(sb.st_mode)) { -+ } else if (S_ISLNK(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmSymlink(rpmfiFLink(fi), fpath); -+ rc = fsmSymlink(rpmfiFLink(fi), fp->fpath); - } -- } else if (S_ISFIFO(sb.st_mode)) { -+ } else if (S_ISFIFO(fp->sb.st_mode)) { - /* This mimics cpio S_ISSOCK() behavior but probably isn't right */ - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfifo(fpath, 0000); -+ rc = fsmMkfifo(fp->fpath, 0000); - } -- } else if (S_ISCHR(sb.st_mode) || -- S_ISBLK(sb.st_mode) || -- S_ISSOCK(sb.st_mode)) -+ } else if (S_ISCHR(fp->sb.st_mode) || -+ S_ISBLK(fp->sb.st_mode) || -+ S_ISSOCK(fp->sb.st_mode)) - { - if (rc == RPMERR_ENOENT) { -- rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev); -+ rc = fsmMknod(fp->fpath, fp->sb.st_mode, fp->sb.st_rdev); - } - } else { - /* XXX Special case /dev/log, which shouldn't be packaged anyways */ -- if (!IS_DEV_LOG(fpath)) -+ if (!IS_DEV_LOG(fp->fpath)) - rc = RPMERR_UNKNOWN_FILETYPE; - } - - touch: - /* Set permissions, timestamps etc for non-hardlink entries */ - if (!rc && setmeta) { -- rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps); -+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -+ &fp->sb, nofcaps); - } - } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ -@@ -967,10 +975,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - } - - if (rc) { -- if (!skip) { -+ if (!fp->skip) { - /* XXX only erase if temp fn w suffix is in use */ -- if (suffix) { -- (void) fsmRemove(fpath, sb.st_mode); -+ if (fp->suffix) { -+ (void) fsmRemove(fp->fpath, fp->sb.st_mode); - } - errno = saveerrno; - } -@@ -978,23 +986,22 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Notify on success. */ - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); - -- if (!skip) { -+ if (!fp->skip) { - /* Backup file if needed. Directories are handled earlier */ -- if (suffix) -- rc = fsmBackup(fi, action); -+ if (fp->suffix) -+ rc = fsmBackup(fi, fp->action); - - if (!rc) -- rc = fsmCommit(&fpath, fi, action, suffix); -+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); - } - } - - if (rc) -- *failedFile = xstrdup(fpath); -+ *failedFile = xstrdup(fp->fpath); - - /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fpath, -- sb.st_mode, action, rc); -- fpath = _free(fpath); -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); - } - - if (!rc && fx != RPMERR_ITER_END) -@@ -1010,7 +1017,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmfiFree(fi); - Fclose(payload); - free(tid); -- free(fpath); -+ for (int i = 0; i < fc; i++) -+ free(fdata[i].fpath); -+ free(fdata); - - return rc; - } -@@ -1022,29 +1031,31 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, - rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK); - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- struct stat sb; -+ int fc = rpmfilesFC(files); -+ int fx = -1; -+ struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - int rc = 0; -- char *fpath = NULL; - -- while (!rc && rpmfiNext(fi) >= 0) { -- rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi)); -- fpath = fsmFsPath(fi, NULL); -- rc = fsmStat(fpath, 1, &sb); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ fp->action = rpmfsGetAction(fs, rpmfiFX(fi)); -+ fp->fpath = fsmFsPath(fi, NULL); -+ rc = fsmStat(fp->fpath, 1, &fp->sb); - -- fsmDebug(fpath, action, &sb); -+ fsmDebug(fp->fpath, fp->action, &fp->sb); - - /* Run fsm file pre hook for all plugins */ -- rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath, -- sb.st_mode, action); -+ rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action); - -- if (!XFA_SKIPPING(action)) -- rc = fsmBackup(fi, action); -+ if (!XFA_SKIPPING(fp->action)) -+ rc = fsmBackup(fi, fp->action); - - /* Remove erased files. */ -- if (action == FA_ERASE) { -+ if (fp->action == FA_ERASE) { - int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST)); - -- rc = fsmRemove(fpath, sb.st_mode); -+ rc = fsmRemove(fp->fpath, fp->sb.st_mode); - - /* - * Missing %ghost or %missingok entries are not errors. -@@ -1069,20 +1080,20 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, - if (rc) { - int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING; - rpmlog(lvl, _("%s %s: remove failed: %s\n"), -- S_ISDIR(sb.st_mode) ? _("directory") : _("file"), -- fpath, strerror(errno)); -+ S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"), -+ fp->fpath, strerror(errno)); - } - } - - /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fpath, -- sb.st_mode, action, rc); -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); - - /* XXX Failure to remove is not (yet) cause for failure. */ - if (!strict_erasures) rc = 0; - - if (rc) -- *failedFile = xstrdup(fpath); -+ *failedFile = xstrdup(fp->fpath); - - if (rc == 0) { - /* Notify on success. */ -@@ -1090,10 +1101,11 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files, - rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi); - rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount); - } -- fpath = _free(fpath); - } - -- free(fpath); -+ for (int i = 0; i < fc; i++) -+ free(fdata[i].fpath); -+ free(fdata); - rpmfiFree(fi); - - return rc; - -From 202c9e9cd2e199b7e7c9655704a98ab2d4fad69c Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:08:27 +0200 -Subject: [PATCH 5/9] Refactor fsmMkfile() to take advantage of the new state - struct - -Move setmeta into the struct too (we'll want this later anyhow), -and now we only need to pass the struct to fsmMkfile(). One less -argument to pass around, it has way too many still. - -No functional changes. ---- - lib/fsm.c | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 9dba30560f..80ca234b1e 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -39,6 +39,7 @@ static int strict_erasures = 0; - #define _filePerms 0644 - - struct filedata_s { -+ int setmeta; - int skip; - rpmFileAction action; - const char *suffix; -@@ -279,8 +280,8 @@ static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) - return rc; - } - --static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, -- rpmpsm psm, int nodigest, int *setmeta, -+static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, -+ rpmpsm psm, int nodigest, - int * firsthardlink, FD_t *firstlinkfile) - { - int rc = 0; -@@ -290,11 +291,11 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, - /* Create first hardlinked file empty */ - if (*firsthardlink < 0) { - *firsthardlink = rpmfiFX(fi); -- rc = wfd_open(firstlinkfile, dest); -+ rc = wfd_open(firstlinkfile, fp->fpath); - } else { - /* Create hard links for others */ - char *fn = rpmfilesFN(files, *firsthardlink); -- rc = link(fn, dest); -+ rc = link(fn, fp->fpath); - if (rc < 0) { - rc = RPMERR_LINK_FAILED; - } -@@ -305,14 +306,14 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files, - existing) file with content */ - if (numHardlinks<=1) { - if (!rc) -- rc = expandRegular(fi, dest, psm, nodigest); -+ rc = expandRegular(fi, fp->fpath, psm, nodigest); - } else if (rpmfiArchiveHasContent(fi)) { - if (!rc) - rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); - wfd_close(firstlinkfile); - *firsthardlink = -1; - } else { -- *setmeta = 0; -+ fp->setmeta = 0; - } - - return rc; -@@ -874,6 +875,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct filedata_s *fp = &fdata[fx]; - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); -+ fp->setmeta = 1; - if (fp->action != FA_TOUCH) { - fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; - } else { -@@ -900,8 +902,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - } - - if (!fp->skip) { -- int setmeta = 1; -- - /* Directories replacing something need early backup */ - if (!fp->suffix) { - rc = fsmBackup(fi, fp->action); -@@ -927,8 +927,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest, -- &setmeta, &firsthardlink, &firstlinkfile); -+ rc = fsmMkfile(fi, fp, files, psm, nodigest, -+ &firsthardlink, &firstlinkfile); - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -961,7 +961,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - touch: - /* Set permissions, timestamps etc for non-hardlink entries */ -- if (!rc && setmeta) { -+ if (!rc && fp->setmeta) { - rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, - &fp->sb, nofcaps); - } - -From f014fc46325efe92b79841145f8dc0cb40896c64 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:24:22 +0200 -Subject: [PATCH 6/9] Clarify file installation temporary suffix rule - -We only use a temporary suffix for regular files that we are actually -creating, skipped and touched files should not have it. Add XFA_CREATING() -macro to accomppany XFA_SKIPPING() to easily check whether the file -is being created or something else. - -No functional changes but makes the logic clearer. ---- - lib/fsm.c | 5 +---- - lib/rpmfiles.h | 3 +++ - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 80ca234b1e..554ea712f5 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -876,11 +876,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; -- if (fp->action != FA_TOUCH) { -+ if (XFA_CREATING(fp->action)) - fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -- } else { -- fp->suffix = NULL; -- } - fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ -diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h -index 7ce1712323..e0adbd8aff 100644 ---- a/lib/rpmfiles.h -+++ b/lib/rpmfiles.h -@@ -121,6 +121,9 @@ typedef enum rpmFileAction_e { - #define XFA_SKIPPING(_a) \ - ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR) - -+#define XFA_CREATING(_a) \ -+ ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME) -+ - /** - * We pass these around as an array with a sentinel. - */ - -From fc54439f8a10901cd72028cdbdb924e3e7501624 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 10:24:22 +0200 -Subject: [PATCH 7/9] Clarify file installation temporary suffix rule - -We only use a temporary suffix for regular files that we are actually -creating, skipped and touched files should not have it. Add XFA_CREATING() -macro to accomppany XFA_SKIPPING() to easily check whether the file -is being created or something else. - -No functional changes but makes the logic clearer. ---- - lib/fsm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 554ea712f5..094f5e2bb6 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -876,8 +876,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; -- if (XFA_CREATING(fp->action)) -- fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid; -+ if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) -+ fp->suffix = tid; - fp->fpath = fsmFsPath(fi, fp->suffix); - - /* Remap file perms, owner, and group. */ - -From 9294ffa898bc7f1f77ff80c0a3f4f0f70c4dfef2 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 11:25:10 +0200 -Subject: [PATCH 8/9] Handle hardlink tracking with a file state pointer - -No functional changes, just makes it a little cleaner as firstlink now -points to the actual file data instead of a index number somewhere. ---- - lib/fsm.c | 20 +++++++++----------- - 1 file changed, 9 insertions(+), 11 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 094f5e2bb6..f86383a986 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -282,24 +282,22 @@ static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest) - - static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, - rpmpsm psm, int nodigest, -- int * firsthardlink, FD_t *firstlinkfile) -+ struct filedata_s ** firstlink, FD_t *firstlinkfile) - { - int rc = 0; - int numHardlinks = rpmfiFNlink(fi); - - if (numHardlinks > 1) { - /* Create first hardlinked file empty */ -- if (*firsthardlink < 0) { -- *firsthardlink = rpmfiFX(fi); -+ if (*firstlink == NULL) { -+ *firstlink = fp; - rc = wfd_open(firstlinkfile, fp->fpath); - } else { - /* Create hard links for others */ -- char *fn = rpmfilesFN(files, *firsthardlink); -- rc = link(fn, fp->fpath); -+ rc = link((*firstlink)->fpath, fp->fpath); - if (rc < 0) { - rc = RPMERR_LINK_FAILED; - } -- free(fn); - } - } - /* Write normal files or fill the last hardlinked (already -@@ -311,7 +309,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files, - if (!rc) - rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm); - wfd_close(firstlinkfile); -- *firsthardlink = -1; -+ *firstlink = NULL; - } else { - fp->setmeta = 0; - } -@@ -855,10 +853,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - int fc = rpmfilesFC(files); - int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0; - int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0; -- int firsthardlink = -1; - FD_t firstlinkfile = NULL; - char *tid = NULL; - struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); -+ struct filedata_s *firstlink = NULL; - - if (fi == NULL) { - rc = RPMERR_BAD_MAGIC; -@@ -925,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { - rc = fsmMkfile(fi, fp, files, psm, nodigest, -- &firsthardlink, &firstlinkfile); -+ &firstlink, &firstlinkfile); - } - } else if (S_ISDIR(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -962,13 +960,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, - &fp->sb, nofcaps); - } -- } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) { -+ } else if (firstlink && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ - /* write the content to the first used instead */ - rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm); - wfd_close(&firstlinkfile); -- firsthardlink = -1; -+ firstlink = NULL; - } - - if (rc) { - -From d6a9a00396a89d14858c6b6e2548eca2065c1d64 Mon Sep 17 00:00:00 2001 -From: Panu Matilainen -Date: Wed, 10 Feb 2021 14:15:33 +0200 -Subject: [PATCH 9/9] Handle file install failures more gracefully - -Run the file installation in multiple stages: -1) gather intel -2) unpack the archive to temporary files -3) set file metadatas -4) commit files to final location -5) mop up leftovers on failure - -This means we no longer leave behind a trail of untracked, potentially -harmful junk on installation failure. - -If commit step fails the package can still be left in an inconsistent stage, -this could be further improved by first backing up old files to temporary -location to allow undo on failure, but leaving that for some other day. -Also unowned directories will still be left behind. - -And yes, this is a somewhat scary change as it's the biggest ever change -to how rpm lays down files on install. Adopt the hardlink test spec -over to install tests and add some more tests for the new behavior. - -Fixes: #967 (+ multiple reports over the years) ---- - lib/fsm.c | 147 ++++++++++++++++++++------------ - tests/data/SPECS/hlinktest.spec | 4 + - tests/rpmbuild.at | 32 ------- - tests/rpmi.at | 92 ++++++++++++++++++++ - 4 files changed, 189 insertions(+), 86 deletions(-) - -diff --git a/lib/fsm.c b/lib/fsm.c -index f86383a986..6efd25bddd 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -38,7 +38,17 @@ static int strict_erasures = 0; - #define _dirPerms 0755 - #define _filePerms 0644 - -+enum filestage_e { -+ FILE_COMMIT = -1, -+ FILE_NONE = 0, -+ FILE_PRE = 1, -+ FILE_UNPACK = 2, -+ FILE_PREP = 3, -+ FILE_POST = 4, -+}; -+ - struct filedata_s { -+ int stage; - int setmeta; - int skip; - rpmFileAction action; -@@ -844,10 +854,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rpmpsm psm, char ** failedFile) - { - FD_t payload = rpmtePayload(te); -- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ rpmfi fi = NULL; - rpmfs fs = rpmteGetFileStates(te); - rpmPlugins plugins = rpmtsPlugins(ts); -- int saveerrno = errno; - int rc = 0; - int fx = -1; - int fc = rpmfilesFC(files); -@@ -858,20 +867,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata)); - struct filedata_s *firstlink = NULL; - -- if (fi == NULL) { -- rc = RPMERR_BAD_MAGIC; -- goto exit; -- } -- - /* transaction id used for temporary path suffix while installing */ - rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); - -- /* Detect and create directories not explicitly in package. */ -- rc = fsmMkdirs(files, fs, plugins); -- -+ /* Collect state data for the whole operation */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); - while (!rc && (fx = rpmfiNext(fi)) >= 0) { - struct filedata_s *fp = &fdata[fx]; -- fp->action = rpmfsGetAction(fs, fx); -+ if (rpmfiFFlags(fi) & RPMFILE_GHOST) -+ fp->action = FA_SKIP; -+ else -+ fp->action = rpmfsGetAction(fs, fx); - fp->skip = XFA_SKIPPING(fp->action); - fp->setmeta = 1; - if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi))) -@@ -881,20 +887,32 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - /* Remap file perms, owner, and group. */ - rc = rpmfiStat(fi, 1, &fp->sb); - -+ setFileState(fs, fx); - fsmDebug(fp->fpath, fp->action, &fp->sb); - -- /* Exit on error. */ -- if (rc) -- break; -- - /* Run fsm file pre hook for all plugins */ - rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath, - fp->sb.st_mode, fp->action); -- if (rc) { -- fp->skip = 1; -- } else { -- setFileState(fs, fx); -- } -+ fp->stage = FILE_PRE; -+ } -+ fi = rpmfiFree(fi); -+ -+ if (rc) -+ goto exit; -+ -+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE); -+ if (fi == NULL) { -+ rc = RPMERR_BAD_MAGIC; -+ goto exit; -+ } -+ -+ /* Detect and create directories not explicitly in package. */ -+ if (!rc) -+ rc = fsmMkdirs(files, fs, plugins); -+ -+ /* Process the payload */ -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; - - if (!fp->skip) { - /* Directories replacing something need early backup */ -@@ -918,7 +936,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - - /* When touching we don't need any of this... */ - if (fp->action == FA_TOUCH) -- goto touch; -+ continue; - - if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { -@@ -954,12 +972,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = RPMERR_UNKNOWN_FILETYPE; - } - --touch: -- /* Set permissions, timestamps etc for non-hardlink entries */ -- if (!rc && fp->setmeta) { -- rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -- &fp->sb, nofcaps); -- } - } else if (firstlink && rpmfiArchiveHasContent(fi)) { - /* On FA_TOUCH no hardlinks are created thus this is skipped. */ - /* we skip the hard linked file containing the content */ -@@ -969,47 +981,74 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - firstlink = NULL; - } - -- if (rc) { -- if (!fp->skip) { -- /* XXX only erase if temp fn w suffix is in use */ -- if (fp->suffix) { -- (void) fsmRemove(fp->fpath, fp->sb.st_mode); -- } -- errno = saveerrno; -- } -- } else { -- /* Notify on success. */ -+ /* Notify on success. */ -+ if (rc) -+ *failedFile = xstrdup(fp->fpath); -+ else - rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi)); -+ fp->stage = FILE_UNPACK; -+ } -+ fi = rpmfiFree(fi); - -- if (!fp->skip) { -- /* Backup file if needed. Directories are handled earlier */ -- if (fp->suffix) -- rc = fsmBackup(fi, fp->action); -+ if (!rc && fx < 0 && fx != RPMERR_ITER_END) -+ rc = fx; - -- if (!rc) -- rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); -- } -+ /* Set permissions, timestamps etc for non-hardlink entries */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ if (!fp->skip && fp->setmeta) { -+ rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action, -+ &fp->sb, nofcaps); - } -- - if (rc) - *failedFile = xstrdup(fp->fpath); -+ fp->stage = FILE_PREP; -+ } -+ fi = rpmfiFree(fi); - -- /* Run fsm file post hook for all plugins */ -- rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -- fp->sb.st_mode, fp->action, rc); -+ /* If all went well, commit files to final destination */ -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ while (!rc && (fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ -+ if (!fp->skip) { -+ /* Backup file if needed. Directories are handled earlier */ -+ if (!rc && fp->suffix) -+ rc = fsmBackup(fi, fp->action); -+ -+ if (!rc) -+ rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix); -+ -+ if (!rc) -+ fp->stage = FILE_COMMIT; -+ else -+ *failedFile = xstrdup(fp->fpath); -+ } - } -+ fi = rpmfiFree(fi); - -- if (!rc && fx != RPMERR_ITER_END) -- rc = fx; -+ /* Walk backwards in case we need to erase */ -+ fi = rpmfilesIter(files, RPMFI_ITER_BACK); -+ while ((fx = rpmfiNext(fi)) >= 0) { -+ struct filedata_s *fp = &fdata[fx]; -+ /* Run fsm file post hook for all plugins for all processed files */ -+ if (fp->stage) { -+ rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath, -+ fp->sb.st_mode, fp->action, rc); -+ } -+ -+ /* On failure, erase non-committed files */ -+ if (rc && fp->stage > FILE_NONE && !fp->skip) { -+ (void) fsmRemove(fp->fpath, fp->sb.st_mode); -+ } -+ } - - rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); - rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); - - exit: -- -- /* No need to bother with close errors on read */ -- rpmfiArchiveClose(fi); -- rpmfiFree(fi); -+ fi = rpmfiFree(fi); - Fclose(payload); - free(tid); - for (int i = 0; i < fc; i++) -diff --git a/tests/data/SPECS/hlinktest.spec b/tests/data/SPECS/hlinktest.spec -index 753c174cd8..3f1437d89c 100644 ---- a/tests/data/SPECS/hlinktest.spec -+++ b/tests/data/SPECS/hlinktest.spec -@@ -1,5 +1,6 @@ - %bcond_with unpackaged_dirs - %bcond_with unpackaged_files -+%bcond_with owned_dir - - Summary: Testing hard link behavior - Name: hlinktest -@@ -43,4 +44,7 @@ touch $RPM_BUILD_ROOT/teet - - %files - %defattr(-,root,root) -+%if %{with owned_dir} -+%dir /foo -+%endif - /foo/* -diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at -index 1f0e679c44..f0eef4eff0 100644 ---- a/tests/rpmbuild.at -+++ b/tests/rpmbuild.at -@@ -253,38 +253,6 @@ drwxrwxrwx zoot zoot /j/dir - []) - AT_CLEANUP - --# ------------------------------ --# hardlink tests --AT_SETUP([rpmbuild hardlink]) --AT_KEYWORDS([build]) --RPMDB_INIT --AT_CHECK([ --RPMDB_INIT -- --runroot rpmbuild \ -- -bb --quiet /data/SPECS/hlinktest.spec -- --runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm -- --runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest --runroot rpm -V --nouser --nogroup hlinktest --ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l -- --], --[0], --[2 /foo/aaaa --1 /foo/copyllo --4 /foo/hello --4 /foo/hello-bar --4 /foo/hello-foo --4 /foo/hello-world --2 /foo/zzzz --87 --1 --], --[]) --AT_CLEANUP -- - AT_SETUP([rpmbuild unpackaged files]) - AT_KEYWORDS([build]) - RPMDB_INIT -diff --git a/tests/rpmi.at b/tests/rpmi.at -index 42dc52ba35..295fbc230f 100644 ---- a/tests/rpmi.at -+++ b/tests/rpmi.at -@@ -722,3 +722,95 @@ runroot rpm -V --nouser --nogroup suicidal - [], - []) - AT_CLEANUP -+ -+# ------------------------------ -+# hardlink tests -+AT_SETUP([rpm -i hardlinks]) -+AT_KEYWORDS([build install]) -+RPMDB_INIT -+ -+# Need a reproducable test package -+runroot rpmbuild \ -+ --define "%optflags -O2 -g" \ -+ --define "%_target_platform noarch-linux" \ -+ --define "%_binary_payload w.ufdio" \ -+ --define "%_buildhost localhost" \ -+ --define "%use_source_date_epoch_as_buildtime 1" \ -+ --define "%source_date_epoch_from_changelog 1" \ -+ --define "%clamp_mtime_to_source_date_epoch 1" \ -+ --with owned_dir \ -+ -bb --quiet /data/SPECS/hlinktest.spec -+ -+pkg="/build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm" -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/1.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/1.rpm" \ -+ conv=notrunc bs=1 seek=8180 count=6 2> /dev/null -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/2.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/2.rpm" \ -+ conv=notrunc bs=1 seek=8150 count=6 2> /dev/null -+ -+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/3.rpm" -+dd if=/dev/zero of="${RPMTEST}/tmp/3.rpm" \ -+ conv=notrunc bs=1 seek=8050 count=6 2> /dev/null -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/1.rpm -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[], -+[error: unpacking of archive failed: cpio: Archive file not in header -+error: hlinktest-1.0-1.noarch: install failed -+]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/2.rpm -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[], -+[error: unpacking of archive failed: cpio: Bad/unreadable header -+error: hlinktest-1.0-1.noarch: install failed -+]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i --noverify /tmp/3.rpm 2>&1| sed 's/;.*:/:/g' -+# test that nothing of the contents remains after failure -+test -d "${RPMTEST}/foo" -+], -+[1], -+[error: unpacking of archive failed on file /foo/hello-world: Digest mismatch -+error: hlinktest-1.0-1.noarch: install failed -+], -+[]) -+ -+AT_CHECK([ -+RPMDB_INIT -+runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm -+runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest -+ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l -+runroot rpm -e hlinktest -+ -+], -+[0], -+[1 /foo -+2 /foo/aaaa -+1 /foo/copyllo -+4 /foo/hello -+4 /foo/hello-bar -+4 /foo/hello-foo -+4 /foo/hello-world -+2 /foo/zzzz -+87 -+1 -+], -+[]) -+AT_CLEANUP -+ diff --git a/rpm.spec b/rpm.spec index 47e8925..a6d0afa 100644 --- a/rpm.spec +++ b/rpm.spec @@ -15,16 +15,6 @@ %bcond_without libarchive # build with libimaevm.so %bcond_without libimaevm -%ifarch ppc64le -# no fsverity on RHEL based ppc64le -# due to PAGESIZE == 64k -# https://pagure.io/centos-sig-hyperscale/package-bugs/issue/8 -# build without libfsverity.so -%bcond_with libfsverity -%else -# build with libfsverity.so -%bcond_without libfsverity -%endif # build with zstd support? %bcond_without zstd # build with ndb backend? @@ -42,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 25.2 +%global rel 33.1 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -109,6 +99,26 @@ Patch122: rpm-4.16.1.3-Support-long-languages-names-for-QT.patch Patch123: rpm-4.14.3-rpm2archive-parse-popt-options.patch Patch124: rpm-4.14.3-rpm2archive-Don-t-print-usage.patch Patch125: rpm-4.16.1.3-IMA-without-xattr.patch +# Backport fsm to fix CVEs +Patch126: 0001-Eliminate-code-duplication-from-rpmfiNext.patch +Patch127: 0001-Add-optional-callback-on-directory-changes-during-rp.patch +Patch128: 0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch +Patch129: 0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch +Patch130: 0001-Use-file-state-machine-from-rpm-4.19.patch +Patch131: 0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch +Patch132: 0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch +Patch133: 0001-Print-full-path-if-file-removal-fails.patch +Patch134: 0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch + +Patch140: 0001-Fix-short-circuiting-of-version-strings-in-expressio.patch +Patch141: 0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch +Patch142: 0001-Expose-and-document-rpmdb-verifydb-operation.patch +Patch143: 0001-Don-t-segfault-on-missing-priority-tag.patch +Patch144: 0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch +Patch145: 0001-Fix-potential-use-of-uninitialized-pipe-array.patch +Patch146: 0001-Fix-potential-use-of-uninitialized-pgp-struct.patch +Patch147: 0001-Add-SourceLicense-tag-to-spec-syntax.patch +Patch148: 0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch # These are not yet upstream Patch906: rpm-4.7.1-geode-i686.patch @@ -130,36 +140,13 @@ Patch916: 0006-debugedit-Handle-DWARF-5-debug_line-and-debug_line_s.patch Patch1000: rpm-4.16.1.3-hashtab-use-after-free-fix.patch Patch1001: rpm-4.16.1.3-find_debuginfo_vendor_opts.patch Patch1002: 0001-Macroize-find-debuginfo-script-location.patch -%if %{with zstd} -Patch1003: rpm-4.16.1.3-backport-multithreaded-zstd.patch -%endif +Patch1003: 0001-Fix-root-relocation-regression.patch +Patch1004: 0001-Skip-to-hashed-subpacket-data-directly.patch -# fsverity support -%if %{with libfsverity} -Patch1964: 0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch -Patch1965: 0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch -Patch1966: 0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch -Patch1967: 0018-rpmsign-Handle-certpath-for-signing-certificate.patch -Patch1968: 0019-Implement-rpmSignVerity.patch -Patch1969: 0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch -Patch1970: 0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch -Patch1971: 0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch -Patch1972: 0023-Process-verity-tag-on-package-read.patch -Patch1973: 0024-Generate-a-zero-length-signature-for-symlinks.patch -Patch1974: 0025-rpmsignverity.c-Clean-up-debug-logging.patch -Patch1975: 0026-fsverity-add-tag-for-fsverity-algorithm.patch -Patch1976: 0027-plugins-fsverity-Install-fsverity-signatures.patch -Patch1977: 0028-fsverity-plugin-Use-tag-for-algorithm.patch -Patch1978: 0029-Add-fsverity-tags-to-rpmgeneral.at.patch -Patch1979: 0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch -Patch1980: 0031-Update-man-page-for-rpmsign.patch -Patch1981: 0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch -Patch1982: 0033-Enable-fsverity-in-CI.patch -Patch1983: 0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch +%if %{with zstd} +Patch2000: rpm-4.16.1.3-backport-multithreaded-zstd.patch %endif -Patch9800: 1534.patch - # Copy-on-Write Patch9901: 0001-RPM-with-Copy-on-Write.patch Patch9902: 0002-Remove-use-of-bool-type-for-consistency.patch @@ -196,6 +183,8 @@ Patch9932: 0032-rpmcow-workaround.patch Patch9933: 0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch Patch9934: 0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch Patch9935: 0035-rpmcow-fix-segfault-in-rpm2extents.patch +Patch9936: 0036-bsearchr_static.patch +Patch9937: 0037-plugin_path.patch Provides: rpm(pr1470) Provides: rpm(pr1470_1) @@ -262,10 +251,6 @@ BuildRequires: audit-libs-devel BuildRequires: ima-evm-utils-devel >= 1.0 %endif -%if %{with libfsverity} -BuildRequires: fsverity-utils-devel >= 1.4 -%endif - # For the rpmdb migration scriptlet (#2055033) Requires(pre): coreutils Requires(pre): findutils @@ -423,17 +408,6 @@ Requires: rpm-libs%{_isa} = %{version}-%{release} %description plugin-ima %{summary}. -%if %{with libfsverity} -%package plugin-fsverity -Summary: Rpm plugin fsverity file signatures -Group: System Environment/Base -Requires: rpm-libs%{_isa} = %{version}-%{release} - -%description plugin-fsverity -%{summary} - -%endif - %package plugin-fapolicyd Summary: Rpm plugin for fapolicyd functionality Requires: rpm-libs%{_isa} = %{version}-%{release} @@ -521,7 +495,6 @@ done; %{?with_ndb: --enable-ndb} \ %{!?with_libarchive: --without-archive} \ %{?with_libimaevm: --with-imaevm} \ - %{?with_libfsverity: --with-fsverity} \ %{?with_zstd: --enable-zstd} \ %{?with_sqlite: --enable-sqlite} \ %{?with_bdb_ro: --enable-bdb-ro} \ @@ -696,11 +669,6 @@ fi %if %{with plugins} %dir %{_libdir}/rpm-plugins -%if %{with libfsverity} -%files plugin-fsverity -%{_libdir}/rpm-plugins/fsverity.so -%endif - %files plugin-syslog %{_libdir}/rpm-plugins/syslog.so %{_mandir}/man8/rpm-plugin-syslog.8* @@ -795,6 +763,49 @@ fi %doc doc/librpm/html/* %changelog +* Wed Aug 07 2024 Matteo Croce - 4.16.1.3-33.1 +- Port COW over latest Red Hat package +- Drop the fs-verity patches +- Patch 1534.patch contained a backport of upstream PR #1534: + https://github.com/rpm-software-management/rpm/pull/1534 + Since the new file state machine was backported in 4.16.1.3-26, drop it + +* Mon Aug 05 2024 Michal Domonkos - 4.16.1.3-33 +- Fix root relocation regression (RHEL-28967) +- Don't confuse OpenScanHub with false array overrun (RHEL-22607) + +* Fri Jul 12 2024 Michal Domonkos - 4.16.1.3-32 +- Revert incorrect fix for false array overrun (RHEL-22607) + +* Fri Jul 12 2024 Michal Domonkos - 4.16.1.3-31 +- Fix potential use of uninitialized pipe array (RHEL-22604) +- Fix potential use of uninitialized pgp struct (RHEL-22605) +- Don't confuse OpenScanHub with false array overrun (RHEL-22607) +- Add SourceLicense tag to spec syntax (RHEL-28798) +- Talk about rpmsign in the rpmsign(8) man page (RHEL-40895) + +* Mon Jun 03 2024 Michal Domonkos - 4.16.1.3-30 +- Don't segfault on missing priority tag (RHEL-35249) +- Use unsigned integers for buildtime too for Y2K38 safety (RHEL-22602) +- Rebuild against libimaevm.so.4 (RHEL-32505) + +* Wed Dec 13 2023 Florian Festi - 4.16.1.3-29 +- Actually add --verifydb to the man page (RHEL-14591) +- Don't warn about missing user/group on skipped files (RHEL-18037) + +* Mon Dec 11 2023 Florian Festi - 4.16.1.3-28 +- Fix warning if file removal fails + +* Mon Nov 27 2023 Florian Festi - 4.16.1.3-27 +- Fix short circuiting of version strings in expressions (RHEL-15688) +- Fix description of whatconflicts in the man page (RHEL-6303) +- Expose and document rpmdb --verifydb operation (RHEL-14591) +- Fixes to the file handling backport + +* Fri Nov 10 2023 Florian Festi - 4.16.1.3-26 +- Backport file handling code from rpm-4.19 to fix CVE-2021-35937, + CVE-2021-35938 and CVE-2021-35939 + * Wed Jul 3 2024 Michal Grzedzicki - 4.16.1.3-25.2 - Fix segfault in rpm2extents @@ -883,7 +894,6 @@ fi * Fri Feb 25 2022 Manu Bretelle - 4.16.1.3-11.1 - Added fsverity backport - Added measure plugin support -- Apply GH1534 in preparation of RPM cow patch - Add support for RPM CoW * Mon Feb 14 2022 Michal Domonkos - 4.16.1.3-11