Blame 0001-PGP-Set-a-default-creation-SELinux-labels-on-GnuPG-d.patch

Petr Písař 458f8b
From 69e3a61e62d7b0c214e49c88a20422da4dfca238 Mon Sep 17 00:00:00 2001
Petr Písař 458f8b
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Petr Písař 458f8b
Date: Thu, 12 Oct 2023 15:55:43 +0200
Petr Písař 458f8b
Subject: [PATCH] PGP: Set a default creation SELinux labels on GnuPG
Petr Písař 458f8b
 directories
Petr Písař 458f8b
MIME-Version: 1.0
Petr Písař 458f8b
Content-Type: text/plain; charset=UTF-8
Petr Písař 458f8b
Content-Transfer-Encoding: 8bit
Petr Písař 458f8b
Petr Písař 458f8b
This is another way how to fix mismatching SELinux context on
Petr Písař 458f8b
/run/user directories without moving the directories to
Petr Písař 458f8b
/run/gnupg/user.
Petr Písař 458f8b
Petr Písař 458f8b
librepo used to precreate the directory in /run/user to make sure
Petr Písař 458f8b
a GnuPG agent executed by GPGME library places its socket there.
Petr Písař 458f8b
Petr Písař 458f8b
The directories there are normally created and removed by systemd
Petr Písař 458f8b
(logind PAM session). librepo created them for a case when a package
Petr Písař 458f8b
manager is invoked out of systemd session, before the super user logs
Petr Písař 458f8b
in. E.g. by a timer job to cache repository metadata.
Petr Písař 458f8b
Petr Písař 458f8b
A problem was when this out-of-session process was a SELinux-confined
Petr Písař 458f8b
process creating files with its own SELinux label different from a DNF
Petr Písař 458f8b
program. Then the directory was created with a SELinux label different
Petr Písař 458f8b
from the one expected by systemd and when logging out a corresponding
Petr Písař 458f8b
user, the mismatching label clashed with systemd.
Petr Písař 458f8b
Petr Písař 458f8b
This patch fixes the issue by choosing a SELinux label of those
Petr Písař 458f8b
directories to the label defined in a default SELinux file context
Petr Písař 458f8b
database.
Petr Písař 458f8b
Petr Písař 458f8b
This patch adds a new -DENABLE_SELINUX=OFF CMake option to disable the
Petr Písař 458f8b
new dependency on libselinux. A default behavior is to support SELinux
Petr Písař 458f8b
only if GPGME backend is selected with -DUSE_GPGME=ON.
Petr Písař 458f8b
Petr Písař 458f8b
https://issues.redhat.com/browse/RHEL-10720
Petr Písař 458f8b
Signed-off-by: Petr Písař <ppisar@redhat.com>
Petr Písař 458f8b
---
Petr Písař 458f8b
 CMakeLists.txt         |  8 ++++++
Petr Písař 458f8b
 librepo.spec           |  9 +++++-
Petr Písař 458f8b
 librepo/CMakeLists.txt |  4 +++
Petr Písař 458f8b
 librepo/gpg.c          | 64 ++++++++++++++++++++++++++++++++++++++++++
Petr Písař 458f8b
 4 files changed, 84 insertions(+), 1 deletion(-)
Petr Písař 458f8b
Petr Písař 458f8b
diff --git a/CMakeLists.txt b/CMakeLists.txt
Petr Písař 458f8b
index b4007e3..1a107bc 100644
Petr Písař 458f8b
--- a/CMakeLists.txt
Petr Písař 458f8b
+++ b/CMakeLists.txt
Petr Písař 458f8b
@@ -5,6 +5,7 @@ OPTION (ENABLE_TESTS "Build test?" ON)
Petr Písař 458f8b
 OPTION (ENABLE_DOCS "Build docs?" ON)
Petr Písař 458f8b
 OPTION (WITH_ZCHUNK "Build with zchunk support" ON)
Petr Písař 458f8b
 OPTION (ENABLE_PYTHON "Build Python bindings" ON)
Petr Písař 458f8b
+OPTION (ENABLE_SELINUX "Restore SELinux labels on GnuPG directories" ON)
Petr Písař 458f8b
 
Petr Písař 458f8b
 INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake)
Petr Písař 458f8b
 SET (VERSION "${LIBREPO_MAJOR}.${LIBREPO_MINOR}.${LIBREPO_PATCH}")
Petr Písař 458f8b
@@ -33,6 +34,9 @@ PKG_SEARCH_MODULE(LIBCRYPTO REQUIRED libcrypto openssl)
Petr Písař 458f8b
 PKG_CHECK_MODULES(LIBXML2 libxml-2.0 REQUIRED)
Petr Písař 458f8b
 FIND_PACKAGE(CURL 7.52.0 REQUIRED)
Petr Písař 458f8b
 FIND_PACKAGE(Gpgme REQUIRED)
Petr Písař 458f8b
+IF (ENABLE_SELINUX)
Petr Písař 458f8b
+    PKG_CHECK_MODULES(SELINUX REQUIRED libselinux)
Petr Písař 458f8b
+ENDIF(ENABLE_SELINUX)
Petr Písař 458f8b
 
Petr Písař 458f8b
 
Petr Písař 458f8b
 IF (WITH_ZCHUNK)
Petr Písař 458f8b
@@ -63,6 +67,10 @@ ENDIF (NOT CURL_FOUND)
Petr Písař 458f8b
 INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIRS})
Petr Písař 458f8b
 INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
Petr Písař 458f8b
 #INCLUDE_DIRECTORIES(${CHECK_INCLUDE_DIR})
Petr Písař 458f8b
+IF (ENABLE_SELINUX)
Petr Písař 458f8b
+    INCLUDE_DIRECTORIES(${SELINUX_INCLUDE_DIRS})
Petr Písař 458f8b
+    ADD_DEFINITIONS(-DENABLE_SELINUX=1)
Petr Písař 458f8b
+ENDIF (ENABLE_SELINUX)
Petr Písař 458f8b
 
Petr Písař 458f8b
 include (GNUInstallDirs)
Petr Písař 458f8b
 # Python stuff
Petr Písař 458f8b
diff --git a/librepo.spec b/librepo.spec
Petr Písař 458f8b
index e8c88d8..0a5c867 100644
Petr Písař 458f8b
--- a/librepo.spec
Petr Písař 458f8b
+++ b/librepo.spec
Petr Písař 458f8b
@@ -8,6 +8,8 @@
Petr Písař 458f8b
 %bcond_without zchunk
Petr Písař 458f8b
 %endif
Petr Písař 458f8b
 
Petr Písař 458f8b
+%bcond_without selinux
Petr Písař 458f8b
+
Petr Písař 458f8b
 %global dnf_conflict 2.8.8
Petr Písař 458f8b
 
Petr Písař 458f8b
 Name:           librepo
Petr Písař 458f8b
@@ -29,6 +31,9 @@ BuildRequires:  libattr-devel
Petr Písař 458f8b
 BuildRequires:  libcurl-devel >= %{libcurl_version}
Petr Písař 458f8b
 BuildRequires:  pkgconfig(libxml-2.0)
Petr Písař 458f8b
 BuildRequires:  pkgconfig(libcrypto)
Petr Písař 458f8b
+%if %{with selinux}
Petr Písař 458f8b
+BuildRequires:  pkgconfig(libselinux)
Petr Písař 458f8b
+%endif
Petr Písař 458f8b
 BuildRequires:  pkgconfig(openssl)
Petr Písař 458f8b
 %if %{with zchunk}
Petr Písař 458f8b
 BuildRequires:  pkgconfig(zck) >= 0.9.11
Petr Písař 458f8b
@@ -66,7 +71,9 @@ Python 3 bindings for the librepo library.
Petr Písař 458f8b
 %autosetup -p1
Petr Písař 458f8b
 
Petr Písař 458f8b
 %build
Petr Písař 458f8b
-%cmake %{!?with_zchunk:-DWITH_ZCHUNK=OFF}
Petr Písař 458f8b
+%cmake \
Petr Písař 458f8b
+    %{!?with_zchunk:-DWITH_ZCHUNK=OFF} \
Petr Písař 458f8b
+    -DENABLE_SELINUX=%{?with_selinux:ON}%{!?with_selinux:OFF}
Petr Písař 458f8b
 %cmake_build
Petr Písař 458f8b
 
Petr Písař 458f8b
 %check
Petr Písař 458f8b
diff --git a/librepo/CMakeLists.txt b/librepo/CMakeLists.txt
Petr Písař 458f8b
index 4f00a5e..e759692 100644
Petr Písař 458f8b
--- a/librepo/CMakeLists.txt
Petr Písař 458f8b
+++ b/librepo/CMakeLists.txt
Petr Písař 458f8b
@@ -53,6 +53,10 @@ TARGET_LINK_LIBRARIES(librepo
Petr Písař 458f8b
                         ${GPGME_VANILLA_LIBRARIES}
Petr Písař 458f8b
                         ${GLIB2_LIBRARIES}
Petr Písař 458f8b
                      )
Petr Písař 458f8b
+IF (ENABLE_SELINUX)
Petr Písař 458f8b
+    TARGET_LINK_LIBRARIES(librepo ${SELINUX_LIBRARIES})
Petr Písař 458f8b
+ENDIF(ENABLE_SELINUX)
Petr Písař 458f8b
+
Petr Písař 458f8b
 IF (WITH_ZCHUNK)
Petr Písař 458f8b
     TARGET_LINK_LIBRARIES(librepo ${ZCHUNKLIB_LIBRARIES})
Petr Písař 458f8b
 ENDIF (WITH_ZCHUNK)
Petr Písař 458f8b
diff --git a/librepo/gpg.c b/librepo/gpg.c
Petr Písař 458f8b
index a134d44..e4b6589 100644
Petr Písař 458f8b
--- a/librepo/gpg.c
Petr Písař 458f8b
+++ b/librepo/gpg.c
Petr Písař 458f8b
@@ -28,6 +28,11 @@
Petr Písař 458f8b
 #include <gpgme.h>
Petr Písař 458f8b
 #include <unistd.h>
Petr Písař 458f8b
 
Petr Písař 458f8b
+#if ENABLE_SELINUX
Petr Písař 458f8b
+#include <selinux/selinux.h>
Petr Písař 458f8b
+#include <selinux/label.h>
Petr Písař 458f8b
+#endif
Petr Písař 458f8b
+
Petr Písař 458f8b
 #include "rcodes.h"
Petr Písař 458f8b
 #include "util.h"
Petr Písař 458f8b
 #include "gpg.h"
Petr Písař 458f8b
@@ -44,6 +49,14 @@
Petr Písař 458f8b
  * Previous solution was to send the agent a "KILLAGENT" message, but that
Petr Písař 458f8b
  * would cause a race condition with calling gpgme_release(), see [2], [3].
Petr Písař 458f8b
  *
Petr Písař 458f8b
+ * Current solution with precreating /run/user/$UID showed problematic when
Petr Písař 458f8b
+ * this library was used out of an systemd-logind session. Then
Petr Písař 458f8b
+ * /run/user/$UID, normally maintained by systemd, was assigned a SELinux
Petr Písař 458f8b
+ * label unexpected by systemd causing errors on a user logout [4].
Petr Písař 458f8b
+ *
Petr Písař 458f8b
+ * We remedy it by choosing the label according to a default file context
Petr Písař 458f8b
+ * policy (ENABLE_SELINUX macro).
Petr Písař 458f8b
+ *
Petr Písař 458f8b
  * Since the agent doesn't clean up its sockets properly, by creating this
Petr Písař 458f8b
  * directory we make sure they are in a place that is not causing trouble with
Petr Písař 458f8b
  * container images.
Petr Písař 458f8b
@@ -51,14 +64,65 @@
Petr Písař 458f8b
  * [1] https://bugzilla.redhat.com/show_bug.cgi?id=1650266
Petr Písař 458f8b
  * [2] https://bugzilla.redhat.com/show_bug.cgi?id=1769831
Petr Písař 458f8b
  * [3] https://github.com/rpm-software-management/microdnf/issues/50
Petr Písař 458f8b
+ * [4] https://issues.redhat.com/browse/RHEL-10720
Petr Písař 458f8b
  */
Petr Písař 458f8b
 void ensure_socket_dir_exists() {
Petr Písař 458f8b
     char dirname[32];
Petr Písař 458f8b
+#if ENABLE_SELINUX
Petr Písař 458f8b
+    char *old_default_context = NULL;
Petr Písař 458f8b
+    int old_default_context_was_retrieved = 0;
Petr Písař 458f8b
+    struct selabel_handle *labeling_handle = NULL;
Petr Písař 458f8b
+
Petr Písař 458f8b
+    /* A purpose of this piece of code is to deal with applications whose
Petr Písař 458f8b
+     * security policy overrides a file context for temporary files but don't
Petr Písař 458f8b
+     * know that librepo executes GnuPG which expects a default file context. */
Petr Písař 458f8b
+    if (0 == getfscreatecon(&old_default_context)) {
Petr Písař 458f8b
+        old_default_context_was_retrieved = 1;
Petr Písař 458f8b
+    } else {
Petr Písař 458f8b
+        g_debug("Failed to retrieve a default SELinux context");
Petr Písař 458f8b
+    }
Petr Písař 458f8b
+    labeling_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
Petr Písař 458f8b
+    if (labeling_handle == NULL) {
Petr Písař 458f8b
+        g_debug("Failed to open a SELinux labeling handle: %s", strerror(errno));
Petr Písař 458f8b
+    }
Petr Písař 458f8b
+#endif
Petr Písař 458f8b
+
Petr Písař 458f8b
     snprintf(dirname, sizeof(dirname), "/run/user/%u", getuid());
Petr Písař 458f8b
+
Petr Písař 458f8b
+#if ENABLE_SELINUX
Petr Písař 458f8b
+    if (labeling_handle != NULL) {
Petr Písař 458f8b
+        char *new_default_context = NULL;
Petr Písař 458f8b
+        if (selabel_lookup(labeling_handle, &new_default_context, dirname, 0700)) {
Petr Písař 458f8b
+            /* Here we could hard-code "system_u:object_r:user_tmp_t:s0", but
Petr Písař 458f8b
+             * that value should be really defined in default file context
Petr Písař 458f8b
+             * SELinux policy. Only log that the policy is incomplete. */
Petr Písař 458f8b
+            g_debug("Failed to look up a default SELinux label for \"%s\"", dirname);
Petr Písař 458f8b
+        } else {
Petr Písař 458f8b
+            if (setfscreatecon(new_default_context)) {
Petr Písař 458f8b
+                g_debug("Failed to set default SELinux context to \"%s\"",
Petr Písař 458f8b
+                        new_default_context);
Petr Písař 458f8b
+            }
Petr Písař 458f8b
+            freecon(new_default_context);
Petr Písař 458f8b
+        }
Petr Písař 458f8b
+    }
Petr Písař 458f8b
+#endif
Petr Písař 458f8b
+
Petr Písař 458f8b
     int res = mkdir(dirname, 0700);
Petr Písař 458f8b
     if (res != 0 && errno != EEXIST) {
Petr Písař 458f8b
         g_debug("Failed to create \"%s\": %d - %s\n", dirname, errno, strerror(errno));
Petr Písař 458f8b
     }
Petr Písař 458f8b
+
Petr Písař 458f8b
+#if ENABLE_SELINUX
Petr Písař 458f8b
+    if (labeling_handle != NULL) {
Petr Písař 458f8b
+        selabel_close(labeling_handle);
Petr Písař 458f8b
+    }
Petr Písař 458f8b
+    if (old_default_context_was_retrieved) {
Petr Písař 458f8b
+        if (setfscreatecon(old_default_context)) {
Petr Písař 458f8b
+            g_debug("Failed to restore a default SELinux context");
Petr Písař 458f8b
+         }
Petr Písař 458f8b
+     }
Petr Písař 458f8b
+    freecon(old_default_context);
Petr Písař 458f8b
+#endif
Petr Písař 458f8b
 }
Petr Písař 458f8b
 
Petr Písař 458f8b
 gboolean
Petr Písař 458f8b
-- 
Petr Písař 458f8b
2.41.0
Petr Písař 458f8b