Skip to content

Commit 056cbd8

Browse files
ppisarjan-kolarik
authored andcommitted
PGP: Set a default creation SELinux labels on GnuPG directories
This is another way how to fix mismatching SELinux context on /run/user directories without moving the directories to /run/gnupg/user. librepo used to precreate the directory in /run/user to make sure a GnuPG agent executed by GPGME library places its socket there. The directories there are normally created and removed by systemd (logind PAM session). librepo created them for a case when a package manager is invoked out of systemd session, before the super user logs in. E.g. by a timer job to cache repository metadata. A problem was when this out-of-session process was a SELinux-confined process creating files with its own SELinux label different from a DNF program. Then the directory was created with a SELinux label different from the one expected by systemd and when logging out a corresponding user, the mismatching label clashed with systemd. This patch fixes the issue by choosing a SELinux label of those directories to the label defined in a default SELinux file context database. This patch adds a new -DENABLE_SELINUX=OFF CMake option to disable the new dependency on libselinux. A default behavior is to support SELinux only if GPGME backend is selected with -DUSE_GPGME=ON. https://issues.redhat.com/browse/RHEL-10720
1 parent e206603 commit 056cbd8

4 files changed

Lines changed: 89 additions & 7 deletions

File tree

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ OPTION (WITH_ZCHUNK "Build with zchunk support" ON)
77
OPTION (ENABLE_PYTHON "Build Python bindings" ON)
88
OPTION (USE_GPGME "Use GpgMe (instead of rpm library) for OpenPGP key support" ON)
99
OPTION (USE_RUN_GNUPG_USER_SOCKET "Create a directory for gpg-agent socket in /run/gnugp/user (instead of /run/user)" OFF)
10+
OPTION (ENABLE_SELINUX "Restore SELinux labels on GnuPG directories" ON)
1011

1112
INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake)
1213
SET (VERSION "${LIBREPO_MAJOR}.${LIBREPO_MINOR}.${LIBREPO_PATCH}")
@@ -37,6 +38,9 @@ FIND_PACKAGE(CURL 7.52.0 REQUIRED)
3738

3839
IF (USE_GPGME)
3940
FIND_PACKAGE(Gpgme REQUIRED)
41+
IF (ENABLE_SELINUX)
42+
PKG_CHECK_MODULES(SELINUX REQUIRED libselinux)
43+
ENDIF(ENABLE_SELINUX)
4044
ELSE (USE_GPGME)
4145
PKG_CHECK_MODULES(RPM REQUIRED rpm>=4.18.0)
4246

@@ -93,6 +97,10 @@ ENDIF (NOT CURL_FOUND)
9397
INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIRS})
9498
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
9599
#INCLUDE_DIRECTORIES(${CHECK_INCLUDE_DIR})
100+
IF (USE_GPGME AND ENABLE_SELINUX)
101+
INCLUDE_DIRECTORIES(${SELINUX_INCLUDE_DIRS})
102+
ADD_DEFINITIONS(-DENABLE_SELINUX=1)
103+
ENDIF (USE_GPGME AND ENABLE_SELINUX)
96104

97105
include (GNUInstallDirs)
98106
# Python stuff

librepo.spec

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,21 @@
1010

1111
%if 0%{?fedora} >= 39
1212
%bcond_with use_gpgme
13+
%bcond_with use_selinux
1314
%else
1415
%bcond_without use_gpgme
16+
%bcond_without use_selinux
1517
%endif
1618

1719
# Needs to match how gnupg2 is compiled
1820
%bcond_with run_gnupg_user_socket
1921

22+
%if %{with use_gpgme} && %{with use_selinux}
23+
%global need_selinux 1
24+
%else
25+
%global need_selinux 0
26+
%endif
27+
2028
%global dnf_conflict 2.8.8
2129

2230
Name: librepo
@@ -42,6 +50,9 @@ BuildRequires: libattr-devel
4250
BuildRequires: libcurl-devel >= %{libcurl_version}
4351
BuildRequires: pkgconfig(libxml-2.0)
4452
BuildRequires: pkgconfig(libcrypto)
53+
%if %{need_selinux}
54+
BuildRequires: pkgconfig(libselinux)
55+
%endif
4556
BuildRequires: pkgconfig(openssl)
4657
%if %{with zchunk}
4758
BuildRequires: pkgconfig(zck) >= 0.9.11
@@ -82,7 +93,8 @@ Python 3 bindings for the librepo library.
8293
%cmake \
8394
-DWITH_ZCHUNK=%{?with_zchunk:ON}%{!?with_zchunk:OFF} \
8495
-DUSE_GPGME=%{?with_use_gpgme:ON}%{!?with_use_gpgme:OFF} \
85-
-DUSE_RUN_GNUPG_USER_SOCKET=%{?with_run_gnupg_user_socket:ON}%{!?with_run_gnupg_user_socket:OFF}
96+
-DUSE_RUN_GNUPG_USER_SOCKET=%{?with_run_gnupg_user_socket:ON}%{!?with_run_gnupg_user_socket:OFF} \
97+
-DENABLE_SELINUX=%{?need_selinux:ON}%{!?need_selinux:OFF}
8698
%cmake_build
8799

88100
%check

librepo/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ TARGET_LINK_LIBRARIES(librepo
7171
)
7272
IF (USE_GPGME)
7373
TARGET_LINK_LIBRARIES(librepo ${GPGME_VANILLA_LIBRARIES})
74+
IF (ENABLE_SELINUX)
75+
TARGET_LINK_LIBRARIES(librepo ${SELINUX_LIBRARIES})
76+
ENDIF(ENABLE_SELINUX)
7477
ELSE(USE_GPGME)
7578
TARGET_LINK_LIBRARIES(librepo ${RPM_LIBRARIES})
7679
ENDIF (USE_GPGME)

librepo/gpg_gpgme.c

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include <stdint.h>
2929
#include <unistd.h>
3030

31+
#if ENABLE_SELINUX
32+
#include <selinux/selinux.h>
33+
#include <selinux/label.h>
34+
#endif
35+
3136
#include "gpg.h"
3237
#include "gpg_internal.h"
3338
#include "rcodes.h"
@@ -45,10 +50,14 @@
4550
* Previous solution was to send the agent a "KILLAGENT" message, but that
4651
* would cause a race condition with calling gpgme_release(), see [2], [3].
4752
*
48-
* Another previous solution used /run/user/$UID which showed problematic when
49-
* this library was used out of an systemd-logind session. Then /run/user/$UID,
50-
* normally maintained by systemd, was assigned a SELinux label unexpected by
51-
* systemd causing errors on a user logout [4].
53+
* Current solution with precreating /run/user/$UID showed problematic when
54+
* this library was used out of an systemd-logind session. Then
55+
* /run/user/$UID, normally maintained by systemd, was assigned a SELinux
56+
* label unexpected by systemd causing errors on a user logout [4].
57+
*
58+
* We remedy it by choosing the label according to a default file context
59+
* policy (ENABLE_SELINUX macro) or by using a different path supported by
60+
* some GnuPG configurations (DUSE_RUN_GNUPG_USER_SOCKET macro).
5261
*
5362
* Since the agent doesn't clean up its sockets properly, by creating this
5463
* directory we make sure they are in a place that is not causing trouble with
@@ -72,19 +81,69 @@ lr_gpg_ensure_socket_dir_exists()
7281
const uid_t uid = getuid();
7382
char dirname[32];
7483
int res;
84+
#if ENABLE_SELINUX
85+
char *old_default_context = NULL;
86+
int old_default_context_was_retrieved = 0;
87+
struct selabel_handle *labeling_handle = NULL;
88+
89+
/* A purpose of this piece of code is to deal with applications whose
90+
* security policy overrides a file context for temporary files but don't
91+
* know that librepo executes GnuPG which expects a default file context. */
92+
if (0 == getfscreatecon(&old_default_context)) {
93+
old_default_context_was_retrieved = 1;
94+
} else {
95+
g_debug("Failed to retrieve a default SELinux context");
96+
}
97+
labeling_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
98+
if (labeling_handle == NULL) {
99+
g_debug("Failed to open a SELinux labeling handle: %s", strerror(errno));
100+
}
101+
#endif
75102

76103
for (int i = 0; templates[i] != NULL; i++) {
77104
res = snprintf(dirname, sizeof(dirname), templates[i], (uintmax_t)uid);
78105
if (res >= sizeof(dirname)) {
79106
g_debug("Failed to format a GnuPG agent socket path because of a small buffer");
80-
return;
107+
goto exit;
81108
}
109+
110+
#if ENABLE_SELINUX
111+
if (labeling_handle != NULL) {
112+
char *new_default_context = NULL;
113+
if (selabel_lookup(labeling_handle, &new_default_context, dirname, modes[i])) {
114+
/* Here we could hard-code "system_u:object_r:user_tmp_t:s0", but
115+
* that value should be really defined in default file context
116+
* SELinux policy. Only log that the policy is incomplete. */
117+
g_debug("Failed to look up a default SELinux label for \"%s\"", dirname);
118+
} else {
119+
if (setfscreatecon(new_default_context)) {
120+
g_debug("Failed to set default SELinux context to \"%s\"",
121+
new_default_context);
122+
}
123+
freecon(new_default_context);
124+
}
125+
}
126+
#endif
127+
82128
res = mkdir(dirname, modes[i]);
83129
if (res != 0 && errno != EEXIST) {
84130
g_debug("Failed to create \"%s\": %d - %s\n", dirname, errno, strerror(errno));
85-
return;
131+
goto exit;
132+
}
133+
}
134+
135+
exit:
136+
#if ENABLE_SELINUX
137+
if (labeling_handle != NULL) {
138+
selabel_close(labeling_handle);
139+
}
140+
if (old_default_context_was_retrieved) {
141+
if (setfscreatecon(old_default_context)) {
142+
g_debug("Failed to restore a default SELinux context");
86143
}
87144
}
145+
freecon(old_default_context);
146+
#endif
88147
}
89148

90149
static gpgme_ctx_t

0 commit comments

Comments
 (0)