From e0ff81088a479f814a9f07a687c88310b4dce071 Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Jul 11 2024 12:00:47 +0000 Subject: [PATCH 1/9] Fix OpenScanHub findings Resolves: RHEL-22604 Resolves: RHEL-22605 --- 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/rpm.spec b/rpm.spec index 870a971..108e55f 100644 --- a/rpm.spec +++ b/rpm.spec @@ -110,6 +110,8 @@ 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 # These are not yet upstream Patch906: rpm-4.7.1-geode-i686.patch @@ -659,6 +661,10 @@ fi %doc doc/librpm/html/* %changelog +* Thu Jul 11 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) + * 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) From ae9528bbef8b05883ae08ad345e4f945c04ad0ff Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Jul 11 2024 15:49:43 +0000 Subject: [PATCH 2/9] Don't confuse OpenScanHub with false array overrun We are intentionally skipping just past the header here (see RFC 4880 for details) so make that explicit by moving the pointer relative to the header's start as opposed to relative to the pointer itself. This is equivalent to the previous expression but makes OpenScanHub happy. Resolves: RHEL-22607 --- diff --git a/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch b/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch new file mode 100644 index 0000000..217597a --- /dev/null +++ b/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch @@ -0,0 +1,12 @@ +diff -up rpm-4.16.1.3/rpmio/rpmpgp.c.orig rpm-4.16.1.3/rpmio/rpmpgp.c +--- rpm-4.16.1.3/rpmio/rpmpgp.c.orig 2024-07-11 13:20:04.872431485 +0200 ++++ rpm-4.16.1.3/rpmio/rpmpgp.c 2024-07-11 13:20:33.828279453 +0200 +@@ -619,7 +619,7 @@ static int pgpPrtSig(pgpTag tag, const u + 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; diff --git a/rpm.spec b/rpm.spec index 108e55f..8a52d3c 100644 --- a/rpm.spec +++ b/rpm.spec @@ -133,6 +133,7 @@ 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 +Patch1003: rpm-4.16.1.3-pgp-explicit-pointer-increment.patch # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -664,6 +665,7 @@ fi * Thu Jul 11 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) * Mon Jun 03 2024 Michal Domonkos - 4.16.1.3-30 - Don't segfault on missing priority tag (RHEL-35249) From a93a04ca0b266913e521aa9f984e76dd526c2c5e Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Jul 11 2024 15:49:47 +0000 Subject: [PATCH 3/9] Add SourceLicense tag to spec syntax Resolves: RHEL-28798 --- 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/rpm.spec b/rpm.spec index 8a52d3c..dcedae4 100644 --- a/rpm.spec +++ b/rpm.spec @@ -112,6 +112,7 @@ 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 # These are not yet upstream Patch906: rpm-4.7.1-geode-i686.patch @@ -666,6 +667,7 @@ fi - 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) * Mon Jun 03 2024 Michal Domonkos - 4.16.1.3-30 - Don't segfault on missing priority tag (RHEL-35249) From cf0fff170815985ef18a91bf0ebf485bb4a85c49 Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Jul 11 2024 15:51:58 +0000 Subject: [PATCH 4/9] Talk about rpmsign in the rpmsign(8) man page Resolves: RHEL-40895 --- 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/rpm.spec b/rpm.spec index dcedae4..9b8455d 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 30 +%global rel 31 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -113,6 +113,7 @@ 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 @@ -663,11 +664,12 @@ fi %doc doc/librpm/html/* %changelog -* Thu Jul 11 2024 Michal Domonkos - 4.16.1.3-31 +* 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) From b3bd2e82c5edb17859a05e9bc0c37c811fa8412d Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Jul 12 2024 14:50:10 +0000 Subject: [PATCH 5/9] Revert "Don't confuse OpenScanHub with false array overrun" Yikes. This was a rushed "fix" that caused a regression in --verify mode with the following error message: Header RSA signature: BAD (header tag 268: invalid OpenPGP signature) This was immediately caught by the CI (thank god we have it!). Since this patch was downstream-only (no internal OpenPGP parser in rpm upstream anymore), it didn't go through the usual peer review. I should have asked for it in GitLab still, no matter how innocent and tiny the change appears to be (lesson learned). Anyway, it's probably going to be safer to just mark this finding as a false positive (which it really is), as opposed to touching the code. Let's revisit later, for now, just revert. This reverts commit ae9528bbef8b05883ae08ad345e4f945c04ad0ff. Related: RHEL-22607 --- diff --git a/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch b/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch deleted file mode 100644 index 217597a..0000000 --- a/rpm-4.16.1.3-pgp-explicit-pointer-increment.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up rpm-4.16.1.3/rpmio/rpmpgp.c.orig rpm-4.16.1.3/rpmio/rpmpgp.c ---- rpm-4.16.1.3/rpmio/rpmpgp.c.orig 2024-07-11 13:20:04.872431485 +0200 -+++ rpm-4.16.1.3/rpmio/rpmpgp.c 2024-07-11 13:20:33.828279453 +0200 -@@ -619,7 +619,7 @@ static int pgpPrtSig(pgpTag tag, const u - 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; diff --git a/rpm.spec b/rpm.spec index 9b8455d..047b566 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 31 +%global rel 32 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -135,7 +135,6 @@ 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 -Patch1003: rpm-4.16.1.3-pgp-explicit-pointer-increment.patch # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -664,6 +663,9 @@ fi %doc doc/librpm/html/* %changelog +* 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) From 671ef971c9f49135076a63c5a6dfa28de1dca607 Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Aug 05 2024 14:24:55 +0000 Subject: [PATCH 6/9] Fix root relocation regression Resolves: RHEL-28967 --- 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/rpm.spec b/rpm.spec index 047b566..13f3ec5 100644 --- a/rpm.spec +++ b/rpm.spec @@ -135,6 +135,7 @@ 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 +Patch1003: 0001-Fix-root-relocation-regression.patch # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -663,6 +664,9 @@ fi %doc doc/librpm/html/* %changelog +* Mon Aug 05 2024 Michal Domonkos - 4.16.1.3-33 +- Fix root relocation regression (RHEL-28967) + * Fri Jul 12 2024 Michal Domonkos - 4.16.1.3-32 - Revert incorrect fix for false array overrun (RHEL-22607) From b082297b5feb0d7903706aa0417118981f512a59 Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Aug 05 2024 14:26:24 +0000 Subject: [PATCH 7/9] Don't confuse OpenScanHub with false array overrun, take II We are intentionally skipping just past the header here (see RFC 4880 for details) so make that explicit by moving the pointer relative to the header's start as opposed to relative to the pointer itself. This is equivalent to the previous expression but makes OpenScanHub happy. Resolves: RHEL-22607 --- 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/rpm.spec b/rpm.spec index 13f3ec5..97a9cb2 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 32 +%global rel 33 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -136,6 +136,7 @@ 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 Patch1003: 0001-Fix-root-relocation-regression.patch +Patch1004: 0001-Skip-to-hashed-subpacket-data-directly.patch # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD @@ -666,6 +667,7 @@ fi %changelog * 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) From bd9c005be9682e8dcc6b8cc5a9c3c04199945aa6 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Aug 14 2024 18:08:01 +0000 Subject: [PATCH 8/9] 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 From 72e4605321d6a801dae10cdd4f1c2db9097e635e Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Aug 19 2024 22:27:44 +0000 Subject: [PATCH 9/9] Fix discarded const qualifier in previous patch Related: RHEL-22607 --- diff --git a/0001-Skip-to-hashed-subpacket-data-directly.patch b/0001-Skip-to-hashed-subpacket-data-directly.patch index f0eaf1f..ada500e 100644 --- a/0001-Skip-to-hashed-subpacket-data-directly.patch +++ b/0001-Skip-to-hashed-subpacket-data-directly.patch @@ -1,23 +1,39 @@ -From 331afbf2b6b32582b29ceadcd37b43a4f905b7f4 Mon Sep 17 00:00:00 2001 +From f6ffaacbbf7f5aca45139a612c5dd8db3f2094dc 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. +Let OpenScanHub grok the bigger picture instead of producing a spurious +overrun warning for v->hashlen when we're dereferencing p later. + +Casting the v pointer back to uint8_t is unnecessary when we could just +use h directly but it's done this way in the if branch for pgp version 3 +in this function as well as in pgpPrtKey() so copy that, just for the +sake of consistency. + +Along the same lines (consistency), change the p pointer to a const +pointer. No functional change. Resolves: RHEL-22607 --- - rpmio/rpmpgp.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) + rpmio/rpmpgp.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index d0688ebe9..6a7049954 100644 +index d0688ebe9..6f044eb1b 100644 --- a/rpmio/rpmpgp.c +++ b/rpmio/rpmpgp.c +@@ -565,7 +565,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + pgpDigParams _digp) + { + uint8_t version = 0; +- uint8_t * p; ++ const uint8_t * p; + unsigned int plen; + int rc = 1; + @@ -618,10 +618,9 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype); pgpPrtNL(); @@ -26,10 +42,10 @@ index d0688ebe9..6a7049954 100644 if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen)) return 1; - p += sizeof(v->hashlen); -+ p = h + sizeof(*v); ++ p = ((uint8_t *)v) + sizeof(*v); if ((p + plen) > (h + hlen)) return 1; -- -2.45.2 +2.46.0 diff --git a/rpm.spec b/rpm.spec index a6d0afa..388cdf2 100644 --- a/rpm.spec +++ b/rpm.spec @@ -32,7 +32,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 33.1 +%global rel 34.1 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -763,6 +763,12 @@ fi %doc doc/librpm/html/* %changelog +* Tue Aug 20 2024 Matteo Croce - 4.16.1.3-34.1 +- Backport fix from upstream + +* Tue Aug 13 2024 Michal Domonkos - 4.16.1.3-34 +- Fix discarded const qualifier in previous patch (RHEL-22607) + * Wed Aug 07 2024 Matteo Croce - 4.16.1.3-33.1 - Port COW over latest Red Hat package - Drop the fs-verity patches