diff --git a/0001-Refactor-sign-command-expand-and-parse-out-of-runGPG.patch b/0001-Refactor-sign-command-expand-and-parse-out-of-runGPG.patch new file mode 100644 index 0000000..dec7288 --- /dev/null +++ b/0001-Refactor-sign-command-expand-and-parse-out-of-runGPG.patch @@ -0,0 +1,143 @@ +From 3b0a150af79668052bf5842b68341adbde016005 Mon Sep 17 00:00:00 2001 +Message-ID: <3b0a150af79668052bf5842b68341adbde016005.1728896192.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 5 Sep 2024 09:07:26 +0300 +Subject: [PATCH 1/3] Refactor sign command expand and parse out of runGPG() + +We'll need the wider visibility of the executing command for the next +steps. While at it, ensure the parsed signing command is minimally +sufficient for what the code expects, ie has at least two items in +the array. + +We now need two exit points, one for the case where we forked and one +where we didn't. Also the case where waitpid() failed entirely must +not return directly to avoid leaking, so merge it with the rest of +the error handling if instead. + +(cherry picked from commit 2c9ad2bbc1d00010880076cd5c73e97ffcb946ed) +--- + sign/rpmgensig.c | 51 ++++++++++++++++++++++++++++++---------------- + tests/rpmsigdig.at | 8 ++++++++ + 2 files changed, 42 insertions(+), 17 deletions(-) + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index a9c3c3e06..7bbd63216 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -188,6 +188,29 @@ exit: + return sigtd; + } + ++char ** signCmd(const char *sigfile) ++{ ++ int argc = 0; ++ char **argv = NULL; ++ ++ rpmPushMacro(NULL, "__plaintext_filename", NULL, "-", -1); ++ rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1); ++ ++ char *cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); ++ ++ rpmPopMacro(NULL, "__plaintext_filename"); ++ rpmPopMacro(NULL, "__signature_filename"); ++ ++ if (poptParseArgvString(cmd, &argc, (const char ***)&argv) < 0 || argc < 2) { ++ rpmlog(RPMLOG_ERR, _("Invalid sign command: %s\n"), cmd); ++ argv = _free(argv); ++ } ++ ++ free(cmd); ++ ++ return argv; ++} ++ + static int runGPG(sigTarget sigt, const char *sigfile) + { + int pid = 0, status; +@@ -198,18 +221,17 @@ static int runGPG(sigTarget sigt, const char *sigfile) + ssize_t wantCount; + rpm_loff_t size; + int rc = 1; /* assume failure */ ++ char **argv = NULL; ++ ++ if ((argv = signCmd(sigfile)) == NULL) ++ goto exit_nowait; + + if (pipe(pipefd) < 0) { + rpmlog(RPMLOG_ERR, _("Could not create pipe for signing: %m\n")); +- goto exit; ++ goto exit_nowait; + } + +- rpmPushMacro(NULL, "__plaintext_filename", NULL, "-", -1); +- rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1); +- + if (!(pid = fork())) { +- char *const *av; +- char *cmd = NULL; + const char *tty = ttyname(STDIN_FILENO); + const char *gpg_path = NULL; + +@@ -223,19 +245,13 @@ static int runGPG(sigTarget sigt, const char *sigfile) + dup2(pipefd[0], STDIN_FILENO); + close(pipefd[1]); + +- cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); +- rc = poptParseArgvString(cmd, NULL, (const char ***)&av); +- if (!rc) +- rc = execve(av[0], av+1, environ); ++ rc = execve(argv[0], argv+1, environ); + + rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg", + strerror(errno)); + _exit(EXIT_FAILURE); + } + +- rpmPopMacro(NULL, "__plaintext_filename"); +- rpmPopMacro(NULL, "__signature_filename"); +- + close(pipefd[0]); + fpipe = fdopen(pipefd[1], "w"); + if (!fpipe) { +@@ -280,14 +296,15 @@ exit: + + if (reaped == -1) { + rpmlog(RPMLOG_ERR, _("gpg waitpid failed (%s)\n"), strerror(errno)); +- return rc; +- } +- +- if (!WIFEXITED(status) || WEXITSTATUS(status)) { ++ } else if (!WIFEXITED(status) || WEXITSTATUS(status)) { + rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status)); + } else { + rc = 0; + } ++ ++exit_nowait: ++ free(argv); ++ + return rc; + } + +diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at +index b726e79ef..14dffc27a 100644 +--- a/tests/rpmsigdig.at ++++ b/tests/rpmsigdig.at +@@ -1028,6 +1028,14 @@ cmp -s ${ORIG} ${NEW}; echo $? + ], + []) + ++RPMTEST_CHECK([ ++run rpmsign --define "__gpg_sign_cmd mumble" --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null ++], ++[1], ++[], ++[error: Invalid sign command: mumble ++]) ++ + # rpmsign --addsign + RPMTEST_CHECK([ + RPMDB_INIT +-- +2.47.0 + diff --git a/0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch b/0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch new file mode 100644 index 0000000..d943ff6 --- /dev/null +++ b/0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch @@ -0,0 +1,129 @@ +From 3c1055628380d66934578060a4a6c678f1261456 Mon Sep 17 00:00:00 2001 +Message-ID: <3c1055628380d66934578060a4a6c678f1261456.1728896192.git.pmatilai@redhat.com> +In-Reply-To: <3b0a150af79668052bf5842b68341adbde016005.1728896192.git.pmatilai@redhat.com> +References: <3b0a150af79668052bf5842b68341adbde016005.1728896192.git.pmatilai@redhat.com> +From: Panu Matilainen +Date: Thu, 5 Sep 2024 09:44:40 +0300 +Subject: [PATCH 2/3] Eliminate hardcoded GPG references from user visible + messages + +Use the OpenPGP standard name or the configured+parsed signing command +in messages as appropriate. Also detect if we're specifically using +gpg and only set up its environment in that case to avoid bleeding +those messages to innocent bypassers. + +Fixes: #3274 +(backported from commit a3cf4f674dd59c1c80f97780643c184e705518ce) +--- + sign/rpmgensig.c | 42 +++++++++++++++++++++++++----------------- + tests/rpmsigdig.at | 9 +++++++++ + 2 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 7bbd63216..fb7368e14 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -232,23 +232,29 @@ static int runGPG(sigTarget sigt, const char *sigfile) + } + + if (!(pid = fork())) { +- const char *tty = ttyname(STDIN_FILENO); +- const char *gpg_path = NULL; +- +- if (!getenv("GPG_TTY") && (!tty || setenv("GPG_TTY", tty, 0))) +- rpmlog(RPMLOG_WARNING, _("Could not set GPG_TTY to stdin: %m\n")); +- +- gpg_path = rpmExpand("%{?_gpg_path}", NULL); +- if (gpg_path && *gpg_path != '\0') +- (void) setenv("GNUPGHOME", gpg_path, 1); ++ /* GnuPG needs extra setup, try to see if that's what we're running */ ++ char *out = rpmExpand("%(", argv[0], " --version 2> /dev/null)", NULL); ++ int using_gpg = (strstr(out, "GnuPG") != NULL); ++ if (using_gpg) { ++ const char *tty = ttyname(STDIN_FILENO); ++ const char *gpg_path = NULL; ++ ++ if (!getenv("GPG_TTY") && (!tty || setenv("GPG_TTY", tty, 0))) ++ rpmlog(RPMLOG_WARNING, _("Could not set GPG_TTY to stdin: %m\n")); ++ ++ gpg_path = rpmExpand("%{?_gpg_path}", NULL); ++ if (gpg_path && *gpg_path != '\0') ++ (void) setenv("GNUPGHOME", gpg_path, 1); ++ } ++ free(out); + + dup2(pipefd[0], STDIN_FILENO); + close(pipefd[1]); + + rc = execve(argv[0], argv+1, environ); + +- rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg", +- strerror(errno)); ++ rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), argv[0], ++ strerror(errno)); + _exit(EXIT_FAILURE); + } + +@@ -295,9 +301,11 @@ exit: + } while (reaped == -1 && errno == EINTR); + + if (reaped == -1) { +- rpmlog(RPMLOG_ERR, _("gpg waitpid failed (%s)\n"), strerror(errno)); ++ rpmlog(RPMLOG_ERR, _("%s waitpid failed (%s)\n"), argv[0], ++ strerror(errno)); + } else if (!WIFEXITED(status) || WEXITSTATUS(status)) { +- rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status)); ++ rpmlog(RPMLOG_ERR, _("%s exec failed (%d)\n"), argv[0], ++ WEXITSTATUS(status)); + } else { + rc = 0; + } +@@ -328,13 +336,13 @@ static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt) + goto exit; + + if (stat(sigfile, &st)) { +- /* GPG failed to write signature */ +- rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n")); ++ /* External command failed to write signature */ ++ rpmlog(RPMLOG_ERR, _("failed to write signature\n")); + goto exit; + } + + pktlen = st.st_size; +- rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", pktlen); ++ rpmlog(RPMLOG_DEBUG, "OpenPGP sig size: %zd\n", pktlen); + pkt = xmalloc(pktlen); + + { FD_t fd; +@@ -351,7 +359,7 @@ static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt) + } + } + +- rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", pktlen); ++ rpmlog(RPMLOG_DEBUG, "Got %zd bytes of OpenPGP sig\n", pktlen); + + /* Parse the signature, change signature tag as appropriate. */ + sigtd = makeSigTag(sigh, ishdr, pkt, pktlen); +diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at +index 14dffc27a..d19f85d04 100644 +--- a/tests/rpmsigdig.at ++++ b/tests/rpmsigdig.at +@@ -1036,6 +1036,15 @@ run rpmsign --define "__gpg_sign_cmd mumble" --key-id 1964C5FC --addsign "${RPMT + [error: Invalid sign command: mumble + ]) + ++RPMTEST_CHECK([ ++run rpmsign --define "__gpg /gnus/not/here" --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null ++], ++[1], ++[], ++[error: Could not exec /gnus/not/here: No such file or directory ++error: /gnus/not/here exec failed (1) ++]) ++ + # rpmsign --addsign + RPMTEST_CHECK([ + RPMDB_INIT +-- +2.47.0 + diff --git a/0003-Declare-signCmd-static.patch b/0003-Declare-signCmd-static.patch new file mode 100644 index 0000000..609121b --- /dev/null +++ b/0003-Declare-signCmd-static.patch @@ -0,0 +1,35 @@ +From 2029533d7878a58874cda061d13c6188f4b3aed1 Mon Sep 17 00:00:00 2001 +Message-ID: <2029533d7878a58874cda061d13c6188f4b3aed1.1728896192.git.pmatilai@redhat.com> +In-Reply-To: <3b0a150af79668052bf5842b68341adbde016005.1728896192.git.pmatilai@redhat.com> +References: <3b0a150af79668052bf5842b68341adbde016005.1728896192.git.pmatilai@redhat.com> +From: Michal Domonkos +Date: Mon, 9 Sep 2024 15:19:52 +0200 +Subject: [PATCH 3/3] Declare signCmd() static + +Commit 2c9ad2bbc1d00010880076cd5c73e97ffcb946ed added this new helper +function for internal use and depite a missing declaration, the compiler +defaulting to WITH_CXX=ON on master chugged along just fine... only +until porting the same commit to a C-only branch (hello rpm-4.20.x) +where it now produces a warning, oops. + +(cherry picked from commit a7784eccd9de674e97fc9577434334060b3abd23) +--- + sign/rpmgensig.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index fb7368e14..d7d58fd4f 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -188,7 +188,7 @@ exit: + return sigtd; + } + +-char ** signCmd(const char *sigfile) ++static char ** signCmd(const char *sigfile) + { + int argc = 0; + char **argv = NULL; +-- +2.47.0 + diff --git a/macros.rpmsign-gnupg b/macros.rpmsign-gnupg new file mode 100644 index 0000000..110ef26 --- /dev/null +++ b/macros.rpmsign-gnupg @@ -0,0 +1,22 @@ +#============================================================================== +# ---- GPG signature macros. +# The signature to use and the location of configuration files for +# signing packages with GNU gpg. +# +#%_gpg_name +#%_gpg_path + +%__gpg /usr/bin/gpg2 + +# Macro(s) to hold the arguments passed to GPG/PGP for package +# signing. Expansion result is parsed by popt, so be sure to use +# %{shescape} where needed. +# +%__gpg_sign_cmd %{shescape:%{__gpg}} \ + gpg --no-verbose --no-armor --no-secmem-warning \ + %{?_gpg_digest_algo:--digest-algo=%{_gpg_digest_algo}} \ + %{?_gpg_sign_cmd_extra_args} \ + %{?_gpg_name:-u %{shescape:%{_gpg_name}}} \ + -sbo %{shescape:%{?__signature_filename}} \ + %{?__plaintext_filename:-- %{shescape:%{__plaintext_filename}}} + diff --git a/macros.rpmsign-sequoia b/macros.rpmsign-sequoia new file mode 100644 index 0000000..dcb9d55 --- /dev/null +++ b/macros.rpmsign-sequoia @@ -0,0 +1,23 @@ +#============================================================================== +# ---- Sequoia signature macros. +# The signature to use and the location of configuration files for +# signing packages with Sequoia. +# +# Unlike GnuPG, Sequoia doesn't support specifying the signer key by +# email or name match, you need to supply the hex fingerprint (or keyid) +#%_gpg_name +#%_gpg_path + +%__gpg /usr/bin/sq + +# Macro(s) to hold the arguments passed to Sequoia for package +# signing. Expansion result is parsed by popt, so be sure to use +# %{shescape} where needed. +# + +%__gpg_sign_cmd %{__gpg} %{__gpg} sign \ + %{?_gpg_sign_cmd_extra_args} \ + %{?_gpg_name:--signer-key %{_gpg_name}} \ + --detached --output %{shescape:%{?__signature_filename}} \ + %{?__plaintext_filename:-- %{shescape:%{__plaintext_filename}}} + diff --git a/rpm-4.19.1.1-nogpg.patch b/rpm-4.19.1.1-nogpg.patch new file mode 100644 index 0000000..8d21d4a --- /dev/null +++ b/rpm-4.19.1.1-nogpg.patch @@ -0,0 +1,59 @@ +diff -up rpm-4.19.1.1/macros.in.nogpg rpm-4.19.1.1/macros.in +--- rpm-4.19.1.1/macros.in.nogpg 2024-10-14 10:01:22.265773552 +0300 ++++ rpm-4.19.1.1/macros.in 2024-10-14 10:02:32.245317535 +0300 +@@ -30,7 +30,6 @@ + %__chown @__CHOWN@ + %__cp @__CP@ + %__file @__FILE@ +-%__gpg @__GPG@ + %__grep @__GREP@ + %__gzip @__GZIP@ + %__id @__ID@ +@@ -321,12 +320,6 @@ Supplements: (%{name} = %{version}-%{r + # marked as %doc should be installed. + #%_excludedocs + +-# The signature to use and the location of configuration files for +-# signing packages with GNU gpg. +-# +-#%_gpg_name +-#%_gpg_path +- + # The port and machine name of an HTTP proxy host (used for FTP/HTTP). + # + #%_httpport +@@ -595,10 +588,10 @@ Supplements: (%{name} = %{version}-%{r + %_fileattrsdir %{_rpmconfigdir}/fileattrs + + # This macro defines how much space (in bytes) in package should be +-# reserved for gpg signatures during building of a package. If this space is +-# big enough for gpg signatures to fit into it then signing of the packages is ++# reserved for OpenPGP signatures during building of a package. If this space ++# big enough for the signature to fit into it then signing of the packages is + # very quick because it is not necessary to rewrite the whole package to make +-# some space for gpg signatures. ++# some space for the signature. + %__gpg_reserved_space 4096 + + #============================================================================== +@@ -613,20 +606,6 @@ Supplements: (%{name} = %{version}-%{r + %_db_backend @DB_BACKEND@ + + #============================================================================== +-# ---- GPG/PGP/PGP5 signature macros. +-# Macro(s) to hold the arguments passed to GPG/PGP for package +-# signing. Expansion result is parsed by popt, so be sure to use +-# %{shescape} where needed. +-# +-%__gpg_sign_cmd %{shescape:%{__gpg}} \ +- gpg --no-verbose --no-armor --no-secmem-warning \ +- %{?_gpg_digest_algo:--digest-algo=%{_gpg_digest_algo}} \ +- %{?_gpg_sign_cmd_extra_args} \ +- %{?_gpg_name:-u %{shescape:%{_gpg_name}}} \ +- -sbo %{shescape:%{?__signature_filename}} \ +- %{?__plaintext_filename:-- %{shescape:%{__plaintext_filename}}} +- +-#============================================================================== + # ---- Transaction macros. + # Macro(s) used to parameterize transactions. + # diff --git a/rpm.spec b/rpm.spec index 03de2f1..21c9ef0 100644 --- a/rpm.spec +++ b/rpm.spec @@ -27,7 +27,7 @@ %global rpmver 4.19.1.1 #global snapver rc1 -%global baserelease 3 +%global baserelease 4 %global sover 10 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -46,6 +46,9 @@ Source10: rpmdb-rebuild.service Source20: rpmdb-migrate.service Source21: rpmdb_migrate +Source30: macros.rpmsign-sequoia +Source31: macros.rpmsign-gnupg + Requires: coreutils Requires: popt%{_isa} >= 1.10.2.1 Requires: curl @@ -135,11 +138,18 @@ rpm-4.9.90-no-man-dirs.patch rpm-4.18.92-disable-sysusers.patch rpm-4.18.90-weak-user-group.patch +# We supply gpg/sq config separately, remove gpg stuff from main macros +rpm-4.19.1.1-nogpg.patch + # Patches already upstream: 0001-Fix-potential-use-of-uninitialized-pipe-array.patch 0001-Fix-potential-use-of-uninitialized-pgp-struct.patch 0001-Fix-memory-leak-in-rpmsign.patch +0001-Refactor-sign-command-expand-and-parse-out-of-runGPG.patch +0002-Eliminate-hardcoded-GPG-references-from-user-visible.patch +0003-Declare-signCmd-static.patch + # These are not yet upstream rpm-4.7.1-geode-i686.patch @@ -174,11 +184,29 @@ This package contains the RPM shared libraries for building packages. %package sign-libs Summary: Libraries for signing RPM packages Requires: rpm-libs%{_isa} = %{version}-%{release} -Requires: %{_bindir}/gpg2 +Requires(meta): (rpm-sign-gnupg or rpm-sign-sequoia) %description sign-libs This package contains the RPM shared libraries for signing packages. +%package sign-gnupg +Summary: Support for signing RPM packages using GnuPG +Requires: gnupg2 +Requires(meta): rpm-sign-libs%{_isa} >= %{version}-%{release} +Conflicts: sign-sequoia + +%description sign-gnupg +This package provides configuration for signing RPM packages using GnuPG. + +%package sign-sequoia +Summary: Support for signing RPM packages using Sequoia +Requires: sequoia-sq +Requires(meta): rpm-sign-libs%{_isa} >= %{version}-%{release} +Conflicts: sign-gnupg + +%description sign-sequoia +This package provides configuration for signing RPM packages using Sequoia. + %package devel Summary: Development files for manipulating RPM packages License: GPL-2.0-or-later OR LGPL-2.1-or-later @@ -423,6 +451,9 @@ rm -rf $RPM_BUILD_ROOT/var/tmp # workaround for https://github.com/rpm-software-management/rpm/issues/2811 rm $RPM_BUILD_ROOT/%{_defaultdocdir}/rpm/README.md +# Signing macros for Sequoia and GnuPG +install -m 644 %{SOURCE30} %{SOURCE31} $RPM_BUILD_ROOT/%{rpmhome}/macros.d + %pre # Symlink all rpmdb files to the new location if we're still using /var/lib/rpm if [ -d /var/lib/rpm ]; then @@ -485,7 +516,7 @@ fi %attr(0755, root, root) %dir %{rpmhome} %{rpmhome}/macros -%{rpmhome}/macros.d +%dir %{rpmhome}/macros.d %{rpmhome}/lua %{rpmhome}/rpmpopt* %{rpmhome}/rpmrc @@ -560,6 +591,12 @@ fi %{_libdir}/librpmsign.so.%{sover} %{_libdir}/librpmsign.so.%{sover}.* +%files sign-sequoia +%{rpmhome}/macros.d/macros.rpmsign-sequoia + +%files sign-gnupg +%{rpmhome}/macros.d/macros.rpmsign-gnupg + %files build %{_bindir}/rpmbuild %{_bindir}/gendiff @@ -616,6 +653,10 @@ fi %doc %{_defaultdocdir}/rpm/API/ %changelog +* Mon Oct 14 2024 Panu Matilainen - 4.19.1.1-4 +- Remove hardcoded GPG references from signing error messages +- Support switching between GnuPG and Sequoia for package signing (RHEL-56363) + * Tue Aug 13 2024 Michal Domonkos - 4.19.1.1-3 - Fix potential use of uninitialized pipe array (RHEL-54012) - Fix potential use of uninitialized pgp struct (RHEL-54013)