From 25bc75cbe63289864c09ab25144ee4af232bd8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= Date: Mon, 4 Jul 2022 09:43:25 +0200 Subject: [PATCH] Add only relevant pkgs to upgrade transaction (RhBug:2097757) https://bugzilla.redhat.com/show_bug.cgi?id=2097757 Without this patch dnf can create the following transaction during dnf upgrade --security when there is an advisory for B-2-2: ``` repo @System 0 testtags #>=Pkg: A 1 1 x86_64 #>=Pkg: B 1 1 x86_64 #>=Req: A = 1-1 repo available 0 testtags #>=Pkg: A 2 2 x86_64 #>=Pkg: B 2 2 x86_64 #>=Req: A = 2-2 system x86_64 rpm @System job update oneof A-1-1.x86_64@@System B-2-2.x86_64@available [targeted,setevr,setarch] result transaction,problems ``` Problem is that without forcebest nothing gets upgraded despite the available advisory and --security switch. This can also be seen in CI test case: rpm-software-management/ci-dnf-stack#1130 --- dnf/base.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dnf/base.py b/dnf/base.py index 852fcdd8..82466831 100644 --- a/dnf/base.py +++ b/dnf/base.py @@ -2135,7 +2135,24 @@ class Base(object): query.filterm(reponame=reponame) query = self._merge_update_filters(query, pkg_spec=pkg_spec, upgrade=True) if query: - query = query.union(installed_query.latest()) + # Given that we use libsolv's targeted transactions, we need to ensure that the transaction contains both + # the new targeted version and also the current installed version (for the upgraded package). This is + # because if it only contained the new version, libsolv would decide to reinstall the package even if it + # had just a different buildtime or vendor but the same version + # (https://github.com/openSUSE/libsolv/issues/287) + # - In general, the query already contains both the new and installed versions but not always. + # If repository-packages command is used, the installed packages are filtered out because they are from + # the @system repo. We need to add them back in. + # - However we need to add installed versions of just the packages that are being upgraded. We don't want + # to add all installed packages because it could increase the number of solutions for the transaction + # (especially without --best) and since libsolv prefers the smallest possible upgrade it could result + # in no upgrade even if there is one available. This is a problem in general but its critical with + # --security transactions (https://bugzilla.redhat.com/show_bug.cgi?id=2097757) + # - We want to add only the latest versions of installed packages, this is specifically for installonly + # packages. Otherwise if for example kernel-1 and kernel-3 were installed and present in the + # transaction libsolv could decide to install kernel-2 because it is an upgrade for kernel-1 even + # though we don't want it because there already is a newer version present. + query = query.union(installed_query.latest().filter(name=[pkg.name for pkg in query])) sltr = dnf.selector.Selector(self.sack) sltr.set(pkg=query) self._goal.upgrade(select=sltr) -- 2.36.1