From 4180f82f2eb0f5eb6657c42a36f183c1ea889ff1 Mon Sep 17 00:00:00 2001
From: Kyle Walker <kwalker@redhat.com>
Date: Mon, 24 Oct 2022 08:57:34 -0400
Subject: [PATCH 1/2] query-py: Ensure reldep is from the same sack

When using two Base() modules, it is possible that a Reldep is
referenced across sack instances.

Example:

    base1 = dnf.Base()
    base1.read_all_repos()
    base1.fill_sack()

    base2 = dnf.Base()
    base2.read_all_repos()
    base2.fill_sack()

    pkg = base1.sack.query().filter(name='glibc').latest()[0]

    for req in pkg.requires:
        base2.sack.query().filter(provides=req) // Should FAIL

The Reldep object from the "req" is sack-specific. This commit changes
the above into a failure condition by verifying that the Query and
Reldep come from the same sack. In the event that they do not, it raises
the following error:

    "Direct dependency lookups must originate from the same sack."

Signed-off-by: Kyle Walker <kwalker@redhat.com>

Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/pull/1583
---
 libdnf/repo/solvable/Dependency.hpp |  2 ++
 python/hawkey/query-py.cpp          | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/libdnf/repo/solvable/Dependency.hpp b/libdnf/repo/solvable/Dependency.hpp
index 47859e65ab..a5dde3dbd6 100644
--- a/libdnf/repo/solvable/Dependency.hpp
+++ b/libdnf/repo/solvable/Dependency.hpp
@@ -63,6 +63,7 @@ struct Dependency
     const char *getVersion() const;
     const char *toString() const;
     Id getId() const noexcept;
+    DnfSack * getSack() const noexcept;
 
 private:
     friend DependencyContainer;
@@ -92,6 +93,7 @@ struct Dependency
 };
 
 inline Id Dependency::getId() const noexcept { return id; }
+inline DnfSack * Dependency::getSack() const noexcept { return sack; }
 
 }
 
diff --git a/python/hawkey/query-py.cpp b/python/hawkey/query-py.cpp
index 99f71bd5fc..a25a0d6bd2 100644
--- a/python/hawkey/query-py.cpp
+++ b/python/hawkey/query-py.cpp
@@ -345,6 +345,16 @@ filter_add(HyQuery query, key_t keyname, int cmp_type, PyObject *match)
     }
     if (reldepObject_Check(match)) {
         DnfReldep *reldep = reldepFromPyObject(match);
+
+	/* A reldep cannot be used across sack objects. If there is an attempt
+         * to do so, the underlying libsolv structures are incomplete and a SEGFAULT is
+         * likely to occur. */
+
+        if (query->getSack() != reldep->getSack()) {
+            PyErr_SetString(HyExc_Query, "Direct dependency lookups must originate from the same sack.");
+            return 0;
+        }
+
         if (cmp_type != HY_EQ || query->addFilter(keyname, reldep))
             return raise_bad_filter();
         return 1;

From d7723d4bfc623ffc765bac35d6dbc431577b2a7a Mon Sep 17 00:00:00 2001
From: Kyle Walker <kwalker@redhat.com>
Date: Mon, 24 Oct 2022 11:07:20 -0400
Subject: [PATCH 2/2] Hawkey tests: Make the Query test per-sack

Following "query-py: Ensure reldep is from the same sack", it is
necessary to make Reldep use per-sack. This commit alters the Query
tests to create per-sack Query objects.

Signed-off-by: Kyle Walker <kwalker@redhat.com>
---
 python/hawkey/tests/tests/test_query.py | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/python/hawkey/tests/tests/test_query.py b/python/hawkey/tests/tests/test_query.py
index 925584c409..c315be2649 100644
--- a/python/hawkey/tests/tests/test_query.py
+++ b/python/hawkey/tests/tests/test_query.py
@@ -403,13 +403,21 @@ def setUp(self):
         self.sack3.load_test_repo("test_ppc", "ppc.repo")
 
     def test_provides_all_arch_query(self):
-        ppc_pkgs = hawkey.Query(self.sack1)
-        self.assertGreater(len(ppc_pkgs), 0)
-        pkg1 = ppc_pkgs[0]
+        # Reldep objects are per-sack, queries across are disallowed. So
+        # it is necessary to create 3 queries below.
+        #
+        # See "query-py: Ensure reldep is from the same sack" for details
+        ppc_pkgs_1 = hawkey.Query(self.sack1)
+        ppc_pkgs_2 = hawkey.Query(self.sack2)
+        ppc_pkgs_3 = hawkey.Query(self.sack3)
+        self.assertGreater(len(ppc_pkgs_1), 0)
+        pkg1 = ppc_pkgs_1[0]
+        pkg2 = ppc_pkgs_2[0]
+        pkg3 = ppc_pkgs_3[0]
 
         query_ppc = hawkey.Query(self.sack1).filter(provides=pkg1.provides[0])
-        query_x86 = hawkey.Query(self.sack2).filter(provides=pkg1.provides[0])
-        query_all = hawkey.Query(self.sack3).filter(provides=pkg1.provides[0])
+        query_x86 = hawkey.Query(self.sack2).filter(provides=pkg2.provides[0])
+        query_all = hawkey.Query(self.sack3).filter(provides=pkg3.provides[0])
 
         self.assertEqual(len(query_ppc), 1)
         self.assertEqual(len(query_x86), 0)
