diff --git a/0018-conf-Improve-granularity-of-ConfigParser-exceptions.patch b/0018-conf-Improve-granularity-of-ConfigParser-exceptions.patch new file mode 100644 index 0000000..db59943 --- /dev/null +++ b/0018-conf-Improve-granularity-of-ConfigParser-exceptions.patch @@ -0,0 +1,107 @@ +From e00b0a457799281b1227755dab7fa9a77729ff38 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Fri, 7 Feb 2025 09:52:13 +0100 +Subject: [PATCH 18/19] conf: Improve granularity of ConfigParser exceptions + +In some cases, we need to distinguish between a missing config file and +one that exists but is unreadable (e.g., due to insufficient +permissions). + +This patch introduces a new FileDoesNotExist exception class, which is a +more specific subclass of the existing CantOpenFile class. This ensures +that any existing workflows remain unaffected. + +Upstream commit: b5d48a6 +--- + libdnf/conf/ConfigParser.cpp | 2 ++ + libdnf/conf/ConfigParser.hpp | 3 +++ + libdnf/utils/iniparser/iniparser.cpp | 15 ++++++++++++++- + libdnf/utils/iniparser/iniparser.hpp | 4 ++++ + 4 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/libdnf/conf/ConfigParser.cpp b/libdnf/conf/ConfigParser.cpp +index 4a461f02..0755c656 100644 +--- a/libdnf/conf/ConfigParser.cpp ++++ b/libdnf/conf/ConfigParser.cpp +@@ -88,6 +88,8 @@ void ConfigParser::read(const std::string & filePath) + try { + IniParser parser(filePath); + ::libdnf::read(*this, parser); ++ } catch (const IniParser::FileDoesNotExist & e) { ++ throw FileDoesNotExist(e.what()); + } catch (const IniParser::CantOpenFile & e) { + throw CantOpenFile(e.what()); + } catch (const IniParser::Exception & e) { +diff --git a/libdnf/conf/ConfigParser.hpp b/libdnf/conf/ConfigParser.hpp +index f43ea3fa..a0d81837 100644 +--- a/libdnf/conf/ConfigParser.hpp ++++ b/libdnf/conf/ConfigParser.hpp +@@ -55,6 +55,9 @@ public: + struct CantOpenFile : public Exception { + CantOpenFile(const std::string & what) : Exception(what) {} + }; ++ struct FileDoesNotExist : public CantOpenFile { ++ FileDoesNotExist(const std::string & what) : CantOpenFile(what) {} ++ }; + struct ParsingError : public Exception { + ParsingError(const std::string & what) : Exception(what) {} + }; +diff --git a/libdnf/utils/iniparser/iniparser.cpp b/libdnf/utils/iniparser/iniparser.cpp +index 1109c120..3c537826 100644 +--- a/libdnf/utils/iniparser/iniparser.cpp ++++ b/libdnf/utils/iniparser/iniparser.cpp +@@ -20,6 +20,9 @@ + + #include "iniparser.hpp" + ++#include ++#include ++ + constexpr char DELIMITER = '\n'; + + const char * IniParser::CantOpenFile::what() const noexcept +@@ -27,6 +30,11 @@ const char * IniParser::CantOpenFile::what() const noexcept + return "IniParser: Can't open file"; + } + ++const char * IniParser::FileDoesNotExist::what() const noexcept ++{ ++ return "IniParser: File does not exist"; ++} ++ + const char * IniParser::MissingSectionHeader::what() const noexcept + { + return "IniParser: Missing section header"; +@@ -65,8 +73,13 @@ const char * IniParser::MissingEqual::what() const noexcept + IniParser::IniParser(const std::string & filePath) + : is(new std::ifstream(filePath)) + { +- if (!(*is)) ++ if (!(*is)) { ++ struct stat buffer; ++ if (stat(filePath.c_str(), &buffer) != 0 && errno == ENOENT) { ++ throw FileDoesNotExist(); ++ } + throw CantOpenFile(); ++ } + is->exceptions(std::ifstream::badbit); + lineNumber = 0; + lineReady = false; +diff --git a/libdnf/utils/iniparser/iniparser.hpp b/libdnf/utils/iniparser/iniparser.hpp +index a6635c6b..57494a18 100644 +--- a/libdnf/utils/iniparser/iniparser.hpp ++++ b/libdnf/utils/iniparser/iniparser.hpp +@@ -46,6 +46,10 @@ public: + CantOpenFile() {} + const char * what() const noexcept override; + }; ++ struct FileDoesNotExist : public CantOpenFile { ++ FileDoesNotExist() {} ++ const char * what() const noexcept override; ++ }; + struct MissingSectionHeader : public Exception { + MissingSectionHeader(int lineNumber) : Exception(lineNumber) {} + const char * what() const noexcept override; +-- +2.48.1 + diff --git a/0019-module-Warn-if-module-config-file-is-inaccessible.patch b/0019-module-Warn-if-module-config-file-is-inaccessible.patch new file mode 100644 index 0000000..aeb1fdd --- /dev/null +++ b/0019-module-Warn-if-module-config-file-is-inaccessible.patch @@ -0,0 +1,85 @@ +From a7be39947d5c002a3a92fa025e410a62be22219b Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Fri, 7 Feb 2025 10:04:50 +0100 +Subject: [PATCH 19/19] module: Warn if module config file is inaccessible + +If a DNF module configuration file is unreadable, `dnf` may return +unexpected results without warning the user, potentially affecting +command output. + +Steps to reproduce: + +1. Enable the `nginx` module as root with a restrictive `umask`, making + the config file unreadable for normal users: + + # umask 0066 + # dnf module enable nginx:1.24 + # ls -l /etc/dnf/modules.d/nginx.module + -rw-------. 1 root root 55 Oct 16 09:59 /etc/dnf/modules.d/nginx.module + +2. Check available packages as root (CORRECT): + + # dnf list --available nginx + [...] + Available Packages + nginx.x86_64 1:1.24.0-1.module+el9.4.0+21950+8ebc21e2.1 + +3. Check available packages as a normal user (INCORRECT): + + $ dnf list --available nginx + [...] + Available Packages + nginx.x86_64 1:1.20.1-16.el9_4.1 + +This patch introduces a warning when a module config file exists but is +inaccessible, helping users diagnose potential issues: + + $ dnf list --available nginx + [...] + Cannot read "/etc/dnf/modules.d/nginx.module". Modular filtering may be affected. + Available Packages + nginx.x86_64 1:1.20.1-16.el9_4.1 + +Resolves: https://issues.redhat.com/browse/RHEL-62833 +Upstream commit: 28805cd +--- + libdnf/module/ModulePackageContainer.cpp | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/libdnf/module/ModulePackageContainer.cpp b/libdnf/module/ModulePackageContainer.cpp +index e4140748..8fbc6e48 100644 +--- a/libdnf/module/ModulePackageContainer.cpp ++++ b/libdnf/module/ModulePackageContainer.cpp +@@ -1370,10 +1370,10 @@ static inline void + parseConfig(ConfigParser &parser, const std::string &name, const char *path) + { + auto logger(Log::getLogger()); ++ const auto fname = name + ".module"; ++ g_autofree gchar * cfn = g_build_filename(path, fname.c_str(), NULL); + + try { +- const auto fname = name + ".module"; +- g_autofree gchar * cfn = g_build_filename(path, fname.c_str(), NULL); + parser.read(cfn); + + /* FIXME: init empty config or throw error? */ +@@ -1393,10 +1393,15 @@ parseConfig(ConfigParser &parser, const std::string &name, const char *path) + parser.setValue(name, "state", parser.getValue(name, "enabled")); + parser.removeOption(name, "enabled"); + } +- } catch (const ConfigParser::CantOpenFile &) { ++ } catch (const ConfigParser::FileDoesNotExist &) { + /* No module config file present. Fill values in */ + initConfig(parser, name); + return; ++ } catch (const ConfigParser::CantOpenFile &) { ++ /* File exists but is not readable. */ ++ logger->warning(tfm::format("Cannot read \"%s\". Modular filtering may be affected.", cfn)); ++ initConfig(parser, name); ++ return; + } + } + +-- +2.48.1 + diff --git a/libdnf.spec b/libdnf.spec index 40e19cd..c95eaf6 100644 --- a/libdnf.spec +++ b/libdnf.spec @@ -58,7 +58,7 @@ Name: libdnf Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} -Release: 13%{?dist} +Release: 14%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf @@ -80,6 +80,8 @@ 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 Patch17: 0017-Add-persistence-config-option.patch +Patch18: 0018-conf-Improve-granularity-of-ConfigParser-exceptions.patch +Patch19: 0019-module-Warn-if-module-config-file-is-inaccessible.patch BuildRequires: cmake @@ -329,6 +331,9 @@ popd %endif %changelog +* Wed Mar 12 2025 Marek Blaha - 0.69.0-14 +- module: Warn if module config file is inaccessible (RHEL-62833) + * Wed Feb 05 2025 Petr Pisar - 0.69.0-13 - Add persistence configuration option (RHEL-78024)