module: Warn if module config file is inaccessible

Resolves: RHEL-62833
This commit is contained in:
Marek Blaha 2025-03-12 16:35:36 +01:00
parent 7139d16e26
commit 2b8596722a
3 changed files with 198 additions and 1 deletions

View File

@ -0,0 +1,107 @@
From e00b0a457799281b1227755dab7fa9a77729ff38 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
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 <errno.h>
+#include <sys/stat.h>
+
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

View File

@ -0,0 +1,85 @@
From a7be39947d5c002a3a92fa025e410a62be22219b Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
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

View File

@ -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 <mblaha@redhat.com> - 0.69.0-14
- module: Warn if module config file is inaccessible (RHEL-62833)
* Wed Feb 05 2025 Petr Pisar <ppisar@redhat.com> - 0.69.0-13
- Add persistence configuration option (RHEL-78024)