diff --git a/SOURCES/0009-Replace-assert-by-map_grow.patch b/SOURCES/0009-Replace-assert-by-map_grow.patch new file mode 100644 index 0000000..b61b3bf --- /dev/null +++ b/SOURCES/0009-Replace-assert-by-map_grow.patch @@ -0,0 +1,38 @@ +From 3c5641a9c7c416e387a54eaf7dad7c33db52b0ec Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Wed, 6 Mar 2024 07:46:34 +0100 +Subject: [PATCH] Replace assert by map_grow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: ef8ac7fcedea1ec87dd3149ce1abdf8daeee25b9 + +It will make code prepared for situation when number of solvables +is increased after query is created and applied. + +The issue can be easilly triggered by adding remote RPMs therefore +the patch fixes a standard situation + +Resolves: https://issues.redhat.com/browse/RHEL-27657 +Signed-off-by: Petr Písař +--- + libdnf/sack/query.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libdnf/sack/query.cpp b/libdnf/sack/query.cpp +index 79377703..6eecfa50 100644 +--- a/libdnf/sack/query.cpp ++++ b/libdnf/sack/query.cpp +@@ -2313,7 +2313,7 @@ Query::Impl::apply() + if (!result) + initResult(); + map_init(&m, pool->nsolvables); +- assert(m.size == result->getMap()->size); ++ map_grow(result->getMap(), pool->nsolvables); + for (auto f : filters) { + map_empty(&m); + switch (f.getKeyname()) { +-- +2.44.0 + diff --git a/SOURCES/0010-subject-py-Fix-memory-leak.patch b/SOURCES/0010-subject-py-Fix-memory-leak.patch new file mode 100644 index 0000000..53c47bf --- /dev/null +++ b/SOURCES/0010-subject-py-Fix-memory-leak.patch @@ -0,0 +1,37 @@ +From c91ed331cc9ea6512a7aaad918db1be9bc6d4f69 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Tue, 26 Mar 2024 14:09:47 +0100 +Subject: [PATCH] subject-py: Fix memory leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: fd284bda6f7430b2e939f95c6836c972e22a2eb4 + +Posible memory leak was detected in get_best_solution() method. + +Resolves: https://issues.redhat.com/browse/RHEL-26226 +Signed-off-by: Petr Písař +--- + python/hawkey/subject-py.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/python/hawkey/subject-py.cpp b/python/hawkey/subject-py.cpp +index a88d572a..3e1919e7 100644 +--- a/python/hawkey/subject-py.cpp ++++ b/python/hawkey/subject-py.cpp +@@ -361,8 +361,10 @@ get_best_solution(_SubjectObject *self, PyObject *args, PyObject *kwds) + HyNevra nevra{nullptr}; + + UniquePtrPyObject q(get_solution(self, args, kwds, &nevra)); +- if (!q) ++ if (!q) { ++ delete nevra; + return NULL; ++ } + PyObject *ret_dict = PyDict_New(); + PyDict_SetItem(ret_dict, PyString_FromString("query"), q.get()); + if (nevra) { +-- +2.44.0 + diff --git a/SOURCES/0011-Add-virtual-destructor-to-TransactionItem.patch b/SOURCES/0011-Add-virtual-destructor-to-TransactionItem.patch new file mode 100644 index 0000000..ecd4bbd --- /dev/null +++ b/SOURCES/0011-Add-virtual-destructor-to-TransactionItem.patch @@ -0,0 +1,40 @@ +From 74150bafa1ffb8527e8eef7507da50562bcb9983 Mon Sep 17 00:00:00 2001 +From: Nicola Sella +Date: Tue, 26 Mar 2024 14:35:43 +0100 +Subject: [PATCH] Add virtual destructor to TransactionItem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: e4e90777f789fc45e002b4c0385c0565a76be946 +Resolves: https://issues.redhat.com/browse/RHEL-26240 + +Signed-off-by: Petr Písař +--- + libdnf/transaction/TransactionItem.hpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libdnf/transaction/TransactionItem.hpp b/libdnf/transaction/TransactionItem.hpp +index 72684f73..5addad45 100644 +--- a/libdnf/transaction/TransactionItem.hpp ++++ b/libdnf/transaction/TransactionItem.hpp +@@ -43,6 +43,8 @@ namespace libdnf { + + class TransactionItemBase { + public: ++ virtual ~TransactionItemBase() = default; ++ + ItemPtr getItem() const noexcept { return item; } + void setItem(ItemPtr value) { item = value; } + +@@ -101,6 +103,7 @@ public: + explicit TransactionItem(Transaction *trans); + + TransactionItem(SQLite3Ptr conn, int64_t transID); ++ virtual ~TransactionItem() = default; + + int64_t getId() const noexcept { return id; } + void setId(int64_t value) { id = value; } +-- +2.44.0 + diff --git a/SOURCES/0012-MergedTransaction-Calculate-RPM-difference-between-t.patch b/SOURCES/0012-MergedTransaction-Calculate-RPM-difference-between-t.patch new file mode 100644 index 0000000..7c3775a --- /dev/null +++ b/SOURCES/0012-MergedTransaction-Calculate-RPM-difference-between-t.patch @@ -0,0 +1,180 @@ +From 318b018f031ddb0e36ae771fb5421446d674eec9 Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Mon, 26 Feb 2024 09:58:33 +0000 +Subject: [PATCH 1/2] MergedTransaction: Calculate RPM difference between two + same versions as no-op +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: 54823d82a1369c25ba1a68c18ea2a67c41f4fbe7 + +If a package of a particular version is installed and would still be installed after a list of transactions, it's more user friendly to treat the whole situation as "do nothing". + +Resolves: https://issues.redhat.com/browse/RHEL-17494 +Signed-off-by: Petr Písař +--- + libdnf/transaction/MergedTransaction.cpp | 38 ++++++++++++------- + libdnf/transaction/MergedTransaction.hpp | 6 +-- + .../transaction/MergedTransactionTest.cpp | 7 +--- + 3 files changed, 28 insertions(+), 23 deletions(-) + +diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp +index a8d878cb..8f26882f 100644 +--- a/libdnf/transaction/MergedTransaction.cpp ++++ b/libdnf/transaction/MergedTransaction.cpp +@@ -192,7 +192,7 @@ static bool transaction_item_sort_function(const std::shared_ptr (new action) = (merged action) + * +- * Erase/Obsolete -> Install/Obsoleting = Reinstall/Downgrade/Upgrade ++ * Erase/Obsolete -> Install/Obsoleting = Downgrade/Upgrade + * + * Reinstall/Reason change -> (new action) = (new action) + * +@@ -210,6 +210,9 @@ static bool transaction_item_sort_function(const std::shared_ptr + MergedTransaction::getItems() +@@ -261,13 +264,16 @@ getItemIdentifier(ItemPtr item) + + /** + * Resolve the difference between RPMs in the first and second transaction item +- * and create a ItemPair of Upgrade, Downgrade or reinstall. ++ * and create a ItemPair of Upgrade, Downgrade or drop the item from the merged ++ * transaction set in case of both packages are of the same version. + * Method is called when original package is being removed and than installed again. ++ * \param itemPairMap merged transaction set + * \param previousItemPair original item pair + * \param mTransItem new transaction item + */ + void +-MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair, ++MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap, ++ ItemPair &previousItemPair, + TransactionItemBasePtr mTransItem) + { + auto firstItem = previousItemPair.first->getItem(); +@@ -277,11 +283,10 @@ MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair, + auto secondRPM = std::dynamic_pointer_cast< RPMItem >(secondItem); + + if (firstRPM->getVersion() == secondRPM->getVersion() && +- firstRPM->getEpoch() == secondRPM->getEpoch()) { +- // reinstall +- mTransItem->setAction(TransactionItemAction::REINSTALL); +- previousItemPair.first = mTransItem; +- previousItemPair.second = nullptr; ++ firstRPM->getEpoch() == secondRPM->getEpoch() && ++ firstRPM->getRelease() == secondRPM->getRelease()) { ++ // Drop the item from merged transaction ++ itemPairMap.erase(getItemIdentifier(firstItem)); + return; + } else if ((*firstRPM) < (*secondRPM)) { + // Upgrade to secondRPM +@@ -296,7 +301,9 @@ MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair, + } + + void +-MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem) ++MergedTransaction::resolveErase(ItemPairMap &itemPairMap, ++ ItemPair &previousItemPair, ++ TransactionItemBasePtr mTransItem) + { + /* + * The original item has been removed - it has to be installed now unless the rpmdb +@@ -306,7 +313,7 @@ MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBaseP + if (mTransItem->getAction() == TransactionItemAction::INSTALL) { + if (mTransItem->getItem()->getItemType() == ItemType::RPM) { + // resolve the difference between RPM packages +- resolveRPMDifference(previousItemPair, mTransItem); ++ resolveRPMDifference(itemPairMap, previousItemPair, mTransItem); + } else { + // difference between comps can't be resolved + mTransItem->setAction(TransactionItemAction::REINSTALL); +@@ -323,11 +330,14 @@ MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBaseP + * transaction - new package is used to complete the pair. Items are stored in pairs (Upgrade, + * Upgrade) or (Downgraded, Downgrade). With complete transaction pair we need to get the new + * Upgrade/Downgrade item and compare its version with the original item from the pair. ++ * \param itemPairMap merged transaction set + * \param previousItemPair original item pair + * \param mTransItem new transaction item + */ + void +-MergedTransaction::resolveAltered(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem) ++MergedTransaction::resolveAltered(ItemPairMap &itemPairMap, ++ ItemPair &previousItemPair, ++ TransactionItemBasePtr mTransItem) + { + auto newState = mTransItem->getAction(); + auto firstState = previousItemPair.first->getAction(); +@@ -369,7 +379,7 @@ MergedTransaction::resolveAltered(ItemPair &previousItemPair, TransactionItemBas + } else { + if (mTransItem->getItem()->getItemType() == ItemType::RPM) { + // resolve the difference between RPM packages +- resolveRPMDifference(previousItemPair, mTransItem); ++ resolveRPMDifference(itemPairMap, previousItemPair, mTransItem); + } else { + // difference between comps can't be resolved + previousItemPair.second->setAction(TransactionItemAction::REINSTALL); +@@ -405,7 +415,7 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT + switch (firstState) { + case TransactionItemAction::REMOVE: + case TransactionItemAction::OBSOLETED: +- resolveErase(previousItemPair, mTransItem); ++ resolveErase(itemPairMap, previousItemPair, mTransItem); + break; + case TransactionItemAction::INSTALL: + // the original package has been installed -> it may be either Removed, or altered +@@ -432,7 +442,7 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT + case TransactionItemAction::UPGRADE: + case TransactionItemAction::UPGRADED: + case TransactionItemAction::OBSOLETE: +- resolveAltered(previousItemPair, mTransItem); ++ resolveAltered(itemPairMap, previousItemPair, mTransItem); + break; + case TransactionItemAction::REINSTALLED: + break; +diff --git a/libdnf/transaction/MergedTransaction.hpp b/libdnf/transaction/MergedTransaction.hpp +index dbb8af11..f85b133a 100644 +--- a/libdnf/transaction/MergedTransaction.hpp ++++ b/libdnf/transaction/MergedTransaction.hpp +@@ -76,9 +76,9 @@ protected: + typedef std::map< std::string, ItemPair > ItemPairMap; + + void mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr transItem); +- void resolveRPMDifference(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); +- void resolveErase(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); +- void resolveAltered(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); ++ void resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); ++ void resolveErase(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); ++ void resolveAltered(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); + }; + + } // namespace libdnf +diff --git a/tests/libdnf/transaction/MergedTransactionTest.cpp b/tests/libdnf/transaction/MergedTransactionTest.cpp +index 52507700..35fb4250 100644 +--- a/tests/libdnf/transaction/MergedTransactionTest.cpp ++++ b/tests/libdnf/transaction/MergedTransactionTest.cpp +@@ -822,12 +822,7 @@ MergedTransactionTest::test_downgrade_upgrade_remove() + // test merging trans1, trans2 + merged.merge(trans2); + auto items2 = merged.getItems(); +- CPPUNIT_ASSERT_EQUAL(1, (int)items2.size()); +- auto item2 = items2.at(0); +- CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item2->getItem()->toStr()); +- CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item2->getRepoid()); +- CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item2->getAction()); +- CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason()); ++ CPPUNIT_ASSERT_EQUAL(0, (int)items2.size()); + + // test merging trans1, trans2, trans3 + merged.merge(trans3); +-- +2.44.0 + diff --git a/SOURCES/0013-MergedTransaction-Fix-invalid-memory-access-when-dro.patch b/SOURCES/0013-MergedTransaction-Fix-invalid-memory-access-when-dro.patch new file mode 100644 index 0000000..57a4da4 --- /dev/null +++ b/SOURCES/0013-MergedTransaction-Fix-invalid-memory-access-when-dro.patch @@ -0,0 +1,94 @@ +From 020aab89fd015d8303b0e8f3f84e126dcdd4d4f4 Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Tue, 23 Apr 2024 14:11:19 +0000 +Subject: [PATCH 2/2] MergedTransaction: Fix invalid memory access when + dropping items +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: 90d2ffad964a91a7a798b81e15c16eb1e840f257 + +When an item is dropped from the merged transaction, the `ItemPair` reference becomes invalid and should no longer be used. + +Resolves: https://issues.redhat.com/browse/RHEL-17494 +Signed-off-by: Petr Písař +--- + libdnf/transaction/MergedTransaction.cpp | 18 +++++++++++------- + libdnf/transaction/MergedTransaction.hpp | 2 +- + 2 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp +index 8f26882f..75d2c1e7 100644 +--- a/libdnf/transaction/MergedTransaction.cpp ++++ b/libdnf/transaction/MergedTransaction.cpp +@@ -264,14 +264,15 @@ getItemIdentifier(ItemPtr item) + + /** + * Resolve the difference between RPMs in the first and second transaction item +- * and create a ItemPair of Upgrade, Downgrade or drop the item from the merged +- * transaction set in case of both packages are of the same version. +- * Method is called when original package is being removed and than installed again. ++ * and create a ItemPair of Upgrade, Downgrade or remove the item from the merged ++ * transaction set in case of both packages are the same. ++ * Method is called when original package is being removed and then installed again. + * \param itemPairMap merged transaction set + * \param previousItemPair original item pair + * \param mTransItem new transaction item ++ * \return true if the original and new transaction item differ + */ +-void ++bool + MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap, + ItemPair &previousItemPair, + TransactionItemBasePtr mTransItem) +@@ -287,7 +288,7 @@ MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap, + firstRPM->getRelease() == secondRPM->getRelease()) { + // Drop the item from merged transaction + itemPairMap.erase(getItemIdentifier(firstItem)); +- return; ++ return false; + } else if ((*firstRPM) < (*secondRPM)) { + // Upgrade to secondRPM + previousItemPair.first->setAction(TransactionItemAction::UPGRADED); +@@ -298,6 +299,7 @@ MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap, + mTransItem->setAction(TransactionItemAction::DOWNGRADE); + } + previousItemPair.second = mTransItem; ++ return true; + } + + void +@@ -308,12 +310,14 @@ MergedTransaction::resolveErase(ItemPairMap &itemPairMap, + /* + * The original item has been removed - it has to be installed now unless the rpmdb + * has changed. Resolve the difference between packages and mark it as Upgrade, +- * Reinstall or Downgrade ++ * Downgrade or remove it from the transaction + */ + if (mTransItem->getAction() == TransactionItemAction::INSTALL) { + if (mTransItem->getItem()->getItemType() == ItemType::RPM) { + // resolve the difference between RPM packages +- resolveRPMDifference(itemPairMap, previousItemPair, mTransItem); ++ if (!resolveRPMDifference(itemPairMap, previousItemPair, mTransItem)) { ++ return; ++ } + } else { + // difference between comps can't be resolved + mTransItem->setAction(TransactionItemAction::REINSTALL); +diff --git a/libdnf/transaction/MergedTransaction.hpp b/libdnf/transaction/MergedTransaction.hpp +index f85b133a..50212159 100644 +--- a/libdnf/transaction/MergedTransaction.hpp ++++ b/libdnf/transaction/MergedTransaction.hpp +@@ -76,7 +76,7 @@ protected: + typedef std::map< std::string, ItemPair > ItemPairMap; + + void mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr transItem); +- void resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); ++ bool resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); + void resolveErase(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); + void resolveAltered(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem); + }; +-- +2.44.0 + diff --git a/SOURCES/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch b/SOURCES/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch new file mode 100644 index 0000000..30ab697 --- /dev/null +++ b/SOURCES/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch @@ -0,0 +1,232 @@ +From bb652b9b1a6a1746413ae43e6bbe1e9ec2aa1a90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Mon, 8 Apr 2024 07:32:31 +0200 +Subject: [PATCH 1/2] context: use `rpmtsAddReinstallElement()` when doing a + reinstall +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: 85432dfd048912083897ab687488087038a9ac96 + +`rpmtsAddInstallElement()` doesn't work for all reinstall cases, such as +when a package `Provides` and `Conflicts` with the same capability. + +Fixes: https://github.com/rpm-software-management/microdnf/issues/137 +Resolves: https://issues.redhat.com/browse/RHEL-1454 +Signed-off-by: Petr Písař +--- + libdnf/dnf-rpmts-private.hpp | 6 ++ + libdnf/dnf-rpmts.cpp | 108 +++++++++++++++++++++++------------ + libdnf/dnf-transaction.cpp | 8 ++- + 3 files changed, 85 insertions(+), 37 deletions(-) + +diff --git a/libdnf/dnf-rpmts-private.hpp b/libdnf/dnf-rpmts-private.hpp +index 94ad6b45..7a8f70fb 100644 +--- a/libdnf/dnf-rpmts-private.hpp ++++ b/libdnf/dnf-rpmts-private.hpp +@@ -31,4 +31,10 @@ gboolean dnf_rpmts_add_install_filename2(rpmts ts, + DnfPackage *pkg, + GError **error); + ++gboolean dnf_rpmts_add_reinstall_filename(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ GError **error); ++ ++ + #endif /* __DNF_RPMTS_PRIVATE_HPP */ +diff --git a/libdnf/dnf-rpmts.cpp b/libdnf/dnf-rpmts.cpp +index ec3d3706..9c0152fc 100644 +--- a/libdnf/dnf-rpmts.cpp ++++ b/libdnf/dnf-rpmts.cpp +@@ -88,94 +88,132 @@ test_fail_safe(Header * hdr, DnfPackage * pkg, GError **error) + return ret; + } + +-gboolean +-dnf_rpmts_add_install_filename2(rpmts ts, +- const gchar *filename, +- gboolean allow_untrusted, +- gboolean is_update, +- DnfPackage * pkg, +- GError **error) try +-{ +- gboolean ret = TRUE; +- gint res; +- Header hdr; +- FD_t fd; +- +- /* open this */ +- fd = Fopen(filename, "r.ufdio"); +- res = rpmReadPackageFile(ts, fd, filename, &hdr); +- ++static gboolean ++result_is_accepted(gint result, gboolean allow_untrusted, const gchar *filename, GError **error) { + /* be less strict when we're allowing untrusted transactions */ + if (allow_untrusted) { +- switch(res) { ++ switch(result) { + case RPMRC_NOKEY: + case RPMRC_NOTFOUND: + case RPMRC_NOTTRUSTED: + case RPMRC_OK: +- break; ++ return TRUE; + case RPMRC_FAIL: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature does not verify for %s"), + filename); +- goto out; ++ return FALSE; + default: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to open(generic error): %s"), + filename); +- goto out; ++ return FALSE; + } + } else { +- switch(res) { ++ switch(result) { + case RPMRC_OK: +- break; ++ return TRUE; + case RPMRC_NOTTRUSTED: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to verify key for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_NOKEY: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("public key unavailable for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_NOTFOUND: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature not found for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_FAIL: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature does not verify for %s"), + filename); +- goto out; ++ return FALSE; + default: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to open(generic error): %s"), + filename); +- goto out; ++ return FALSE; + } + } ++} ++ ++gboolean ++dnf_rpmts_add_reinstall_filename(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ GError **error) try ++{ ++ gboolean ret = TRUE; ++ gint res; ++ Header hdr; ++ FD_t fd; ++ ++ /* open this */ ++ fd = Fopen(filename, "r.ufdio"); ++ res = rpmReadPackageFile(ts, fd, filename, &hdr); ++ ++ if (!result_is_accepted(res, allow_untrusted, filename, error)) { ++ ret = FALSE; ++ goto out; ++ } ++ ++ /* add to the transaction */ ++ res = rpmtsAddReinstallElement(ts, hdr, (fnpyKey) filename); ++ if (res != 0) { ++ ret = FALSE; ++ g_set_error(error, ++ DNF_ERROR, ++ DNF_ERROR_INTERNAL_ERROR, ++ _("failed to add reinstall element: %1$s [%2$i]"), ++ filename, res); ++ goto out; ++ } ++out: ++ Fclose(fd); ++ headerFree(hdr); ++ return ret; ++} CATCH_TO_GERROR(FALSE) ++ ++gboolean ++dnf_rpmts_add_install_filename2(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ gboolean is_update, ++ DnfPackage * pkg, ++ GError **error) try ++{ ++ gboolean ret = TRUE; ++ gint res; ++ Header hdr; ++ FD_t fd; ++ ++ /* open this */ ++ fd = Fopen(filename, "r.ufdio"); ++ res = rpmReadPackageFile(ts, fd, filename, &hdr); ++ ++ if (!result_is_accepted(res, allow_untrusted, filename, error)) { ++ ret = FALSE; ++ goto out; ++ } + if (pkg) { + if (!test_fail_safe(&hdr, pkg, error)) { + ret = FALSE; +diff --git a/libdnf/dnf-transaction.cpp b/libdnf/dnf-transaction.cpp +index d93c5ec6..d57e463d 100644 +--- a/libdnf/dnf-transaction.cpp ++++ b/libdnf/dnf-transaction.cpp +@@ -1221,8 +1221,12 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state + filename = dnf_package_get_filename(pkg); + allow_untrusted = (priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) == 0; + is_update = action == DNF_STATE_ACTION_UPDATE || action == DNF_STATE_ACTION_DOWNGRADE; +- ret = dnf_rpmts_add_install_filename2( +- priv->ts, filename, allow_untrusted, is_update, pkg, error); ++ if (action == DNF_STATE_ACTION_REINSTALL) { ++ ret = dnf_rpmts_add_reinstall_filename(priv->ts, filename, allow_untrusted, error); ++ } else { ++ ret = dnf_rpmts_add_install_filename2( ++ priv->ts, filename, allow_untrusted, is_update, pkg, error); ++ } + if (!ret) + goto out; + +-- +2.45.0 + diff --git a/SOURCES/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch b/SOURCES/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch new file mode 100644 index 0000000..53938f8 --- /dev/null +++ b/SOURCES/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch @@ -0,0 +1,81 @@ +From 7a3d4ed40276d2667cf48f83672ef1f142a8f0a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Fri, 3 May 2024 08:55:47 +0200 +Subject: [PATCH 2/2] Since we use rpmtsAddReinstallElement rpm also uninstalls + the package +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: bc371683ab69d51127952b037bde209a56e44105 + +It calls callbacks for `RPMCALLBACK_INST_START` and +`RPMCALLBACK_INST_PROGRESS` just like before when the reinstall was done +through regural install (rpmtsAddInstallElement) but in addition it also +calls `RPMCALLBACK_UNINST_START` and `RPMCALLBACK_UNINST_PROGRESS`. To +ensure they find the `DnfPackage` add it to `remove_helper` array. + +Unfortunaly this means that the reinstall action is reported twice to +the clients (one install and one uninstall). We could try to hide one of +the them but I think a better solution is to report what is actually +happening and report one install and one uninstall. + +This is for the context part of libdnf (microdnf, packagekit, ...) + +Fixes: https://github.com/rpm-software-management/libdnf/issues/1653 +Resolves: https://issues.redhat.com/browse/RHEL-1454 +Signed-off-by: Petr Písař +--- + libdnf/dnf-transaction.cpp | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/libdnf/dnf-transaction.cpp b/libdnf/dnf-transaction.cpp +index d57e463d..8e17ba2d 100644 +--- a/libdnf/dnf-transaction.cpp ++++ b/libdnf/dnf-transaction.cpp +@@ -602,7 +602,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_INSTALL; + + /* set the pkgid if not already set */ +@@ -641,7 +641,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_REMOVE; + + /* remove start */ +@@ -716,7 +716,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_REMOVE; + + dnf_state_set_package_progress( +@@ -1338,6 +1338,15 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state + g_ptr_array_unref(pkglist); + } + ++ /* add reinstalled packages to a helper array which is used to ++ * map removed packages auto-added by rpm to actual DnfPackage's */ ++ pkglist = dnf_goal_get_packages(goal, DNF_PACKAGE_INFO_REINSTALL, -1); ++ for (i = 0; i < pkglist->len; i++) { ++ pkg_tmp = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, i)); ++ g_ptr_array_add(priv->remove_helper, g_object_ref(pkg_tmp)); ++ } ++ g_ptr_array_unref(pkglist); ++ + /* this section done */ + ret = dnf_state_done(state, error); + if (!ret) +-- +2.45.0 + diff --git a/SOURCES/0016-repo-Don-t-try-to-perform-labeling-if-SELinux-is-dis.patch b/SOURCES/0016-repo-Don-t-try-to-perform-labeling-if-SELinux-is-dis.patch new file mode 100644 index 0000000..193aed6 --- /dev/null +++ b/SOURCES/0016-repo-Don-t-try-to-perform-labeling-if-SELinux-is-dis.patch @@ -0,0 +1,93 @@ +From d264065ec0d574b70bf376d5ee3777d7cc03030f Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Tue, 4 Jun 2024 06:57:19 -0400 +Subject: [PATCH] repo: Don't try to perform labeling if SELinux is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The default for container execution is that `/sys/fs/selinux` +is not mounted, and the libselinux library function `is_selinux_enabled` +should be used to dynamically check if the system should attempt to perform SELinux labeling. + +This is how it's done by rpm, ostree, and systemd for example. + +But this code unconditionally tries to label if it finds a policy, +which breaks in an obscure corner case +when executed inside a container that includes policy files (e.g. +fedora/rhel-bootc) but when we're not using overlayfs for the backend +(with BUILDAH_BACKEND=vfs). + +Signed-off-by: Petr Písař +--- + libdnf/repo/Repo.cpp | 50 +++++++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/libdnf/repo/Repo.cpp b/libdnf/repo/Repo.cpp +index 16f15195..10b88813 100644 +--- a/libdnf/repo/Repo.cpp ++++ b/libdnf/repo/Repo.cpp +@@ -679,34 +679,36 @@ static int create_temporary_directory(char *name_template) { + int old_default_context_was_retrieved = 0; + struct selabel_handle *labeling_handle = NULL; + +- /* A purpose of this piece of code is to deal with applications whose +- * security policy overrides a file context for temporary files but don't +- * know that libdnf executes GnuPG which expects a default file context. */ +- if (0 == getfscreatecon(&old_default_context)) { +- old_default_context_was_retrieved = 1; +- } else { +- logger->debug(tfm::format("Failed to retrieve a default SELinux context")); +- } ++ if (is_selinux_enabled()) { ++ /* A purpose of this piece of code is to deal with applications whose ++ * security policy overrides a file context for temporary files but don't ++ * know that libdnf executes GnuPG which expects a default file context. */ ++ if (0 == getfscreatecon(&old_default_context)) { ++ old_default_context_was_retrieved = 1; ++ } else { ++ logger->debug(tfm::format("Failed to retrieve a default SELinux context")); ++ } + +- labeling_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0); +- if (NULL == labeling_handle) { +- logger->debug(tfm::format("Failed to open a SELinux labeling handle: %s", +- strerror(errno))); +- } else { +- if (selabel_lookup(labeling_handle, &new_default_context, name_template, 0700)) { +- /* Here we could hard-code "system_u:object_r:user_tmp_t:s0", but +- * that value should be really defined in default file context +- * SELinux policy. Only log that the policy is incpomplete. */ +- logger->debug(tfm::format("Failed to look up a default SELinux label for \"%s\"", +- name_template)); ++ labeling_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0); ++ if (NULL == labeling_handle) { ++ logger->debug(tfm::format("Failed to open a SELinux labeling handle: %s", ++ strerror(errno))); + } else { +- if (setfscreatecon(new_default_context)) { +- logger->debug(tfm::format("Failed to set default SELinux context to \"%s\"", +- new_default_context)); ++ if (selabel_lookup(labeling_handle, &new_default_context, name_template, 0700)) { ++ /* Here we could hard-code "system_u:object_r:user_tmp_t:s0", but ++ * that value should be really defined in default file context ++ * SELinux policy. Only log that the policy is incpomplete. */ ++ logger->debug(tfm::format("Failed to look up a default SELinux label for \"%s\"", ++ name_template)); ++ } else { ++ if (setfscreatecon(new_default_context)) { ++ logger->debug(tfm::format("Failed to set default SELinux context to \"%s\"", ++ new_default_context)); ++ } ++ freecon(new_default_context); + } +- freecon(new_default_context); ++ selabel_close(labeling_handle); + } +- selabel_close(labeling_handle); + } + #endif + +-- +2.45.2 + diff --git a/SPECS/libdnf.spec b/SPECS/libdnf.spec index f9e0177..72a4e67 100644 --- a/SPECS/libdnf.spec +++ b/SPECS/libdnf.spec @@ -58,7 +58,7 @@ Name: libdnf Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} -Release: 8%{?dist} +Release: 12%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf @@ -71,6 +71,14 @@ Patch5: 0005-filterAdvisory-installed_solvables-sort-RhBug2212838.patch Patch6: 0006-hawkeysubject-get_best_selectors-only-obsol-oflatest.patch Patch7: 0007-Avoid-reinstal-installonly-packages-marked-for-ERASE.patch Patch8: 0008-PGP-Set-a-default-creation-SELinux-labels-on-GnuPG-d.patch +Patch9: 0009-Replace-assert-by-map_grow.patch +Patch10: 0010-subject-py-Fix-memory-leak.patch +Patch11: 0011-Add-virtual-destructor-to-TransactionItem.patch +Patch12: 0012-MergedTransaction-Calculate-RPM-difference-between-t.patch +Patch13: 0013-MergedTransaction-Fix-invalid-memory-access-when-dro.patch +Patch14: 0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch +Patch15: 0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch +Patch16: 0016-repo-Don-t-try-to-perform-labeling-if-SELinux-is-dis.patch BuildRequires: cmake @@ -320,6 +328,24 @@ popd %endif %changelog +* Fri Jun 21 2024 Petr Pisar - 0.69.0-12 +- Do not set a default SELinux creation context if SELinux appears to be + disabled (RHEL-43232) + +* Thu May 16 2024 Petr Pisar - 0.69.0-11 +- Fix reinstalling packages which conflicts with themselves in + dnf_transaction_commit() (RHEL-1454) + +* Tue Apr 23 2024 Petr Pisar - 0.69.0-10 +- Fix calculating a difference between two same-version RPM transacations + (RHEL-17494) + +* Tue Apr 16 2024 Petr Pisar - 0.69.0-9 +- Grow memory if applying a query after increasing a number of available + packages (RHEL-27657) +- Fix a memory leak in get_best_solution() (RHEL-26226) +- Fix destructing libdnf::TransactionItem from a base class (RHEL-26240) + * Wed Oct 25 2023 Petr Pisar - 0.69.0-8 - Set default SELinux labels on GnuPG directories (RHEL-11238)