From 239748667df22f5c17509891fc0240a602a4365c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 24 2021 22:25:19 +0000 Subject: import dnf-4.7.0-3.el8 --- diff --git a/SOURCES/0003-Pass-the-package-to-rpmkeys-stdin.patch b/SOURCES/0003-Pass-the-package-to-rpmkeys-stdin.patch new file mode 100644 index 0000000..f8de68f --- /dev/null +++ b/SOURCES/0003-Pass-the-package-to-rpmkeys-stdin.patch @@ -0,0 +1,56 @@ +From 134b095b0833956cadfc02a9a1e7ca1344cd5aaa Mon Sep 17 00:00:00 2001 +From: Demi Marie Obenour +Date: Tue, 27 Apr 2021 21:07:19 -0400 +Subject: [PATCH] Pass the package to rpmkeys stdin + +This avoids having to compute the expected stdout value, which will +always be the constant "-: digests signatures OK\n". +--- + dnf/rpm/miscutils.py | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/dnf/rpm/miscutils.py b/dnf/rpm/miscutils.py +index 7e33d4c..5f2621c 100644 +--- a/dnf/rpm/miscutils.py ++++ b/dnf/rpm/miscutils.py +@@ -29,7 +29,8 @@ from shutil import which + logger = logging.getLogger('dnf') + + +-def _verifyPkgUsingRpmkeys(package, installroot): ++def _verifyPkgUsingRpmkeys(package, installroot, fdno): ++ os.lseek(fdno, 0, os.SEEK_SET) + rpmkeys_binary = '/usr/bin/rpmkeys' + if not os.path.isfile(rpmkeys_binary): + rpmkeys_binary = which("rpmkeys") +@@ -40,15 +41,16 @@ def _verifyPkgUsingRpmkeys(package, installroot): + logger.critical(_('Cannot find rpmkeys executable to verify signatures.')) + return 0 + +- args = ('rpmkeys', '--checksig', '--root', installroot, '--define', '_pkgverify_level all', '--', package) ++ args = ('rpmkeys', '--checksig', '--root', installroot, '--define', '_pkgverify_level all', '-') + with subprocess.Popen( + args=args, + executable=rpmkeys_binary, + env={'LC_ALL': 'C'}, ++ stdin=fdno, + stdout=subprocess.PIPE, + cwd='/') as p: + data, err = p.communicate() +- if p.returncode != 0 or data != (package.encode('ascii', 'strict') + b': digests signatures OK\n'): ++ if p.returncode != 0 or data != b'-: digests signatures OK\n': + return 0 + else: + return 1 +@@ -85,7 +87,7 @@ def checkSig(ts, package): + + if siginfo == '(none)': + value = 4 +- elif "Key ID" in siginfo and _verifyPkgUsingRpmkeys(package, ts.ts.rootDir): ++ elif "Key ID" in siginfo and _verifyPkgUsingRpmkeys(package, ts.ts.rootDir, fdno): + value = 0 + else: + raise ValueError('Unexpected return value %r from hdr.sprintf when checking signature.' % siginfo) +-- +libgit2 1.0.1 + diff --git a/SOURCES/0004-Use-rpmkeys-alone-to-verify-signature.patch b/SOURCES/0004-Use-rpmkeys-alone-to-verify-signature.patch new file mode 100644 index 0000000..73daa7e --- /dev/null +++ b/SOURCES/0004-Use-rpmkeys-alone-to-verify-signature.patch @@ -0,0 +1,176 @@ +From a21880fbac479968546304beeeae3ed3bb899373 Mon Sep 17 00:00:00 2001 +From: Demi Marie Obenour +Date: Fri, 9 Apr 2021 13:03:03 -0400 +Subject: [PATCH] Use rpmkeys alone to verify signature + +This avoids having to actually parse the package to check its signature, +which reduces attack surface. If the output of rpmkeys cannot be +parsed, we assume the package is corrupt (the most likely cause). +--- + dnf/rpm/miscutils.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------ + 1 file changed, 66 insertions(+), 60 deletions(-) + +diff --git a/dnf/rpm/miscutils.py b/dnf/rpm/miscutils.py +index 5f2621c..9d5b286 100644 +--- a/dnf/rpm/miscutils.py ++++ b/dnf/rpm/miscutils.py +@@ -13,90 +13,96 @@ + # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + # Copyright 2003 Duke University + +-from __future__ import print_function, absolute_import +-from __future__ import unicode_literals ++from __future__ import print_function, absolute_import, unicode_literals + +-import rpm + import os + import subprocess + import logging +- +-from dnf.i18n import ucd +-from dnf.i18n import _ + from shutil import which + ++from dnf.i18n import _ + +-logger = logging.getLogger('dnf') ++_logger = logging.getLogger('dnf') ++_rpmkeys_binary = None + ++def _find_rpmkeys_binary(): ++ global _rpmkeys_binary ++ if _rpmkeys_binary is None: ++ _rpmkeys_binary = which("rpmkeys") ++ _logger.debug(_('Using rpmkeys executable at %s to verify signatures'), ++ _rpmkeys_binary) ++ return _rpmkeys_binary + +-def _verifyPkgUsingRpmkeys(package, installroot, fdno): +- os.lseek(fdno, 0, os.SEEK_SET) +- rpmkeys_binary = '/usr/bin/rpmkeys' +- if not os.path.isfile(rpmkeys_binary): +- rpmkeys_binary = which("rpmkeys") +- logger.info(_('Using rpmkeys executable from {path} to verify signature for package: {package}.').format( +- path=rpmkeys_binary, package=package)) ++def _process_rpm_output(data): ++ # No signatures or digests = corrupt package. ++ # There is at least one line for -: and another (empty) entry after the ++ # last newline. ++ if len(data) < 3 or data[0] != b'-:' or data[-1]: ++ return 2 ++ seen_sig, missing_key, not_trusted, not_signed = False, False, False, False ++ for i in data[1:-1]: ++ if b': BAD' in i: ++ return 2 ++ elif i.endswith(b': NOKEY'): ++ missing_key = True ++ elif i.endswith(b': NOTTRUSTED'): ++ not_trusted = True ++ elif i.endswith(b': NOTFOUND'): ++ not_signed = True ++ elif not i.endswith(b': OK'): ++ return 2 ++ if not_trusted: ++ return 3 ++ elif missing_key: ++ return 1 ++ elif not_signed: ++ return 4 ++ # we still check return code, so this is safe ++ return 0 + +- if not os.path.isfile(rpmkeys_binary): +- logger.critical(_('Cannot find rpmkeys executable to verify signatures.')) +- return 0 ++def _verifyPackageUsingRpmkeys(package, installroot): ++ rpmkeys_binary = _find_rpmkeys_binary() ++ if rpmkeys_binary is None or not os.path.isfile(rpmkeys_binary): ++ _logger.critical(_('Cannot find rpmkeys executable to verify signatures.')) ++ return 2 + +- args = ('rpmkeys', '--checksig', '--root', installroot, '--define', '_pkgverify_level all', '-') ++ # "--define=_pkgverify_level all" enforces signature checking; ++ # "--define=_pkgverify_flags 0x0" ensures that all signatures and digests ++ # are checked. ++ args = ('rpmkeys', '--checksig', '--root', installroot, '--verbose', ++ '--define=_pkgverify_level all', '--define=_pkgverify_flags 0x0', ++ '-') + with subprocess.Popen( + args=args, + executable=rpmkeys_binary, + env={'LC_ALL': 'C'}, +- stdin=fdno, + stdout=subprocess.PIPE, +- cwd='/') as p: +- data, err = p.communicate() +- if p.returncode != 0 or data != b'-: digests signatures OK\n': +- return 0 +- else: +- return 1 ++ cwd='/', ++ stdin=package) as p: ++ data = p.communicate()[0] ++ returncode = p.returncode ++ if type(returncode) is not int: ++ raise AssertionError('Popen set return code to non-int') ++ # rpmkeys can return something other than 0 or 1 in the case of a ++ # fatal error (OOM, abort() called, SIGSEGV, etc) ++ if returncode >= 2 or returncode < 0: ++ return 2 ++ ret = _process_rpm_output(data.split(b'\n')) ++ if ret: ++ return ret ++ return 2 if returncode else 0 + + def checkSig(ts, package): + """Takes a transaction set and a package, check it's sigs, + return 0 if they are all fine + return 1 if the gpg key can't be found + return 2 if the header is in someway damaged + return 3 if the key is not trusted + return 4 if the pkg is not gpg or pgp signed""" + +- value = 4 +- currentflags = ts.setVSFlags(0) +- fdno = os.open(package, os.O_RDONLY) ++ fdno = os.open(package, os.O_RDONLY|os.O_NOCTTY|os.O_CLOEXEC) + try: +- hdr = ts.hdrFromFdno(fdno) +- except rpm.error as e: +- if str(e) == "public key not available": +- value = 1 +- elif str(e) == "public key not trusted": +- value = 3 +- elif str(e) == "error reading package header": +- value = 2 +- else: +- raise ValueError('Unexpected error value %r from ts.hdrFromFdno when checking signature.' % str(e)) +- else: +- # checks signature from an hdr +- string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:' \ +- '{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|' +- try: +- siginfo = hdr.sprintf(string) +- siginfo = ucd(siginfo) +- +- if siginfo == '(none)': +- value = 4 +- elif "Key ID" in siginfo and _verifyPkgUsingRpmkeys(package, ts.ts.rootDir, fdno): +- value = 0 +- else: +- raise ValueError('Unexpected return value %r from hdr.sprintf when checking signature.' % siginfo) +- except UnicodeDecodeError: +- pass +- +- del hdr +- +- os.close(fdno) +- +- ts.setVSFlags(currentflags) # put things back like they were before ++ value = _verifyPackageUsingRpmkeys(fdno, ts.ts.rootDir) ++ finally: ++ os.close(fdno) + return value +-- +libgit2 1.0.1 + diff --git a/SOURCES/0005-Lower-_pkgverify_level-to-signature-for-signature-checking-with-rpmkeys.patch b/SOURCES/0005-Lower-_pkgverify_level-to-signature-for-signature-checking-with-rpmkeys.patch new file mode 100644 index 0000000..f30ae63 --- /dev/null +++ b/SOURCES/0005-Lower-_pkgverify_level-to-signature-for-signature-checking-with-rpmkeys.patch @@ -0,0 +1,36 @@ +From b05f4589e4afb69240ae2001246a5ffb5d6b1b90 Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Thu, 3 Jun 2021 11:23:31 +0200 +Subject: [PATCH] Lower _pkgverify_level to signature for signature checking with rpmkeys + +We don't want to be veryfing digests as well when checking signatures. +It would break legacy package installation in FIPS mode due to MD5 +digest being unverifiable (see https://access.redhat.com/solutions/5221661) + +Follow up for https://github.com/rpm-software-management/dnf/pull/1753 +--- + dnf/rpm/miscutils.py | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/dnf/rpm/miscutils.py b/dnf/rpm/miscutils.py +index 9d5b286..46ef475 100644 +--- a/dnf/rpm/miscutils.py ++++ b/dnf/rpm/miscutils.py +@@ -66,11 +66,10 @@ def _verifyPackageUsingRpmkeys(package, installroot): + _logger.critical(_('Cannot find rpmkeys executable to verify signatures.')) + return 2 + +- # "--define=_pkgverify_level all" enforces signature checking; +- # "--define=_pkgverify_flags 0x0" ensures that all signatures and digests +- # are checked. ++ # "--define=_pkgverify_level signature" enforces signature checking; ++ # "--define=_pkgverify_flags 0x0" ensures that all signatures are checked. + args = ('rpmkeys', '--checksig', '--root', installroot, '--verbose', +- '--define=_pkgverify_level all', '--define=_pkgverify_flags 0x0', ++ '--define=_pkgverify_level signature', '--define=_pkgverify_flags 0x0', + '-') + with subprocess.Popen( + args=args, +-- +libgit2 1.0.1 + diff --git a/SPECS/dnf.spec b/SPECS/dnf.spec index d8229fc..4820e9d 100644 --- a/SPECS/dnf.spec +++ b/SPECS/dnf.spec @@ -66,7 +66,7 @@ It supports RPMs, modules and comps groups & environments. Name: dnf Version: 4.7.0 -Release: 2%{?dist} +Release: 3%{?dist} Summary: %{pkg_summary} # For a breakdown of the licensing, see PACKAGE-LICENSING License: GPLv2+ @@ -74,6 +74,9 @@ URL: https://github.com/rpm-software-management/dnf Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz Patch1: 0001-Set-top-level-directory-for-unittest.patch Patch2: 0002-dnfrpmmiscutilspy-fix-usage-of-_.patch +Patch3: 0003-Pass-the-package-to-rpmkeys-stdin.patch +Patch4: 0004-Use-rpmkeys-alone-to-verify-signature.patch +Patch5: 0005-Lower-_pkgverify_level-to-signature-for-signature-checking-with-rpmkeys.patch BuildArch: noarch BuildRequires: cmake @@ -373,6 +376,9 @@ popd %{python3_sitelib}/%{name}/automatic/ %changelog +* Mon Aug 16 2021 Pavla Kratochvilova - 4.7.0-3 +- Improve signature checking using rpmkeys (RhBug:1967454) + * Tue Jul 27 2021 Pavla Kratochvilova - 4.7.0-2 - Fix covscan issue: dnf/rpm/miscutils.py: fix usage of _()