Fix slow login with ipa and SELinux

- Resolves: upstream #2624 - Only set the selinux context if the context
                             differs from the local one
This commit is contained in:
Lukas Slebodnik 2015-04-15 14:30:16 +02:00
parent 7e203ada3a
commit 32425edf44
4 changed files with 355 additions and 1 deletions

View File

@ -0,0 +1,70 @@
From 24553c550248ac1a989f43921d2a3b45295b42cd Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 10 Apr 2015 10:55:22 +0200
Subject: [PATCH 3/5] selinux: Disconnect before closing the handle
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
libsemanage documentation says:
~~~~
be sure that a semanage_disconnect() was previously called if the handle
was connected.
~~~~
Otherwise we get a memory leak.
Reviewed-by: Michal Židek <mzidek@redhat.com>
(cherry picked from commit aa00d67b2a8e07c9080e7798defdc6c774c93465)
---
src/util/sss_semanage.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
index b85831c3d3f262f49b19082e96aa62ccf3afeaa8..d141de1c671e6d62a731e56b10ee14069f27ae87 100644
--- a/src/util/sss_semanage.c
+++ b/src/util/sss_semanage.c
@@ -68,6 +68,13 @@ static void sss_semanage_error_callback(void *varg,
free(message);
}
+static void sss_semanage_close(semanage_handle_t *handle)
+{
+ /* Calling disconnect on a disconnected handle is safe */
+ semanage_disconnect(handle);
+ semanage_handle_destroy(handle);
+}
+
static semanage_handle_t *sss_semanage_init(void)
{
int ret;
@@ -110,7 +117,7 @@ static semanage_handle_t *sss_semanage_init(void)
return handle;
fail:
- semanage_handle_destroy(handle);
+ sss_semanage_close(handle);
return NULL;
}
@@ -278,7 +285,7 @@ int set_seuser(const char *login_name, const char *seuser_name,
ret = EOK;
done:
semanage_seuser_key_free(key);
- semanage_handle_destroy(handle);
+ sss_semanage_close(handle);
return ret;
}
@@ -350,7 +357,7 @@ int del_seuser(const char *login_name)
ret = EOK;
done:
- semanage_handle_destroy(handle);
+ sss_semanage_close(handle);
return ret;
}
--
2.3.5

View File

@ -0,0 +1,68 @@
From 47987b0af3b1898a0ed5a772dbc4438b59fba8c8 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 10 Apr 2015 11:06:44 +0200
Subject: [PATCH 4/5] selinux: Begin and end the transaction on the same
nesting level
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Transaction should be started and commited on the same code nesting or
abstraction level. Also, transactions are really costly with libselinux
and splitting them from initialization will make init function reusable
by read-only libsemanage functions.
Reviewed-by: Michal Židek <mzidek@redhat.com>
(cherry picked from commit 748b38a7991d78cbf4726f2a14ace5e926629a54)
---
src/util/sss_semanage.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
index d141de1c671e6d62a731e56b10ee14069f27ae87..c0342498cbd0495733a0bf701a06a02cfb705fc7 100644
--- a/src/util/sss_semanage.c
+++ b/src/util/sss_semanage.c
@@ -109,12 +109,6 @@ static semanage_handle_t *sss_semanage_init(void)
goto fail;
}
- ret = semanage_begin_transaction(handle);
- if (ret != 0) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot begin SELinux transaction\n");
- goto fail;
- }
-
return handle;
fail:
sss_semanage_close(handle);
@@ -243,6 +237,13 @@ int set_seuser(const char *login_name, const char *seuser_name,
goto done;
}
+ ret = semanage_begin_transaction(handle);
+ if (ret != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot begin SELinux transaction\n");
+ ret = EIO;
+ goto done;
+ }
+
ret = semanage_seuser_key_create(handle, login_name, &key);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux user key\n");
@@ -303,6 +304,13 @@ int del_seuser(const char *login_name)
goto done;
}
+ ret = semanage_begin_transaction(handle);
+ if (ret != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot begin SELinux transaction\n");
+ ret = EIO;
+ goto done;
+ }
+
ret = semanage_seuser_key_create(handle, login_name, &key);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux user key\n");
--
2.3.5

View File

@ -0,0 +1,208 @@
From 566c45a78757c73700ce9535d70fa37c8077e678 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 9 Apr 2015 22:18:35 +0200
Subject: [PATCH 5/5] selinux: Only call semanage if the context actually
changes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://fedorahosted.org/sssd/ticket/2624
Add a function to query the libsemanage database for a user context and
only update the database if the context differes from the one set on the
server.
Adds talloc dependency to libsss_semanage.
Reviewed-by: Michal Židek <mzidek@redhat.com>
(cherry picked from commit 1e0fa55fb377db788e065de917ba8e149eb56161)
---
Makefile.am | 5 +++
src/providers/ipa/selinux_child.c | 35 ++++++++++++++++---
src/util/sss_semanage.c | 71 +++++++++++++++++++++++++++++++++++++++
src/util/util.h | 2 ++
4 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 29d148c4a0cbda6882b4a619d6c71d2efcc8fb43..73970024a6ce55bfe91c5e14d5127d189e321716 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -767,10 +767,15 @@ endif
libsss_util_la_LDFLAGS = -avoid-version
pkglib_LTLIBRARIES += libsss_semanage.la
+libsss_semanage_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(TALLOC_CFLAGS) \
+ $(NULL)
libsss_semanage_la_SOURCES = \
src/util/sss_semanage.c \
$(NULL)
libsss_semanage_la_LIBADD = \
+ $(TALLOC_LIBS) \
libsss_debug.la \
$(NULL)
if BUILD_SEMANAGE
diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
index 81c1de877ef08a299d07837fefcd195d465849fa..7c5731d66b7d0ed17b7be18c4adaa65394002fc4 100644
--- a/src/providers/ipa/selinux_child.c
+++ b/src/providers/ipa/selinux_child.c
@@ -165,6 +165,29 @@ static int sc_set_seuser(const char *login_name, const char *seuser_name,
return ret;
}
+static bool seuser_needs_update(struct input_buffer *ibuf)
+{
+ bool needs_update = true;
+ char *db_seuser = NULL;
+ char *db_mls_range = NULL;
+ errno_t ret;
+
+ ret = get_seuser(ibuf, ibuf->username, &db_seuser, &db_mls_range);
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "get_seuser: ret: %d seuser: %s mls: %s\n",
+ ret, db_seuser ? db_seuser : "unknown",
+ db_mls_range ? db_mls_range : "unknown");
+ if (ret == EOK && db_seuser && db_mls_range &&
+ strcmp(db_seuser, ibuf->seuser) == 0 &&
+ strcmp(db_mls_range, ibuf->mls_range) == 0) {
+ needs_update = false;
+ }
+
+ talloc_free(db_seuser);
+ talloc_free(db_mls_range);
+ return needs_update;
+}
+
int main(int argc, const char *argv[])
{
int opt;
@@ -177,6 +200,7 @@ int main(int argc, const char *argv[])
struct input_buffer *ibuf = NULL;
struct response *resp = NULL;
ssize_t written;
+ bool needs_update;
struct poptOption long_options[] = {
POPT_AUTOHELP
@@ -296,10 +320,13 @@ int main(int argc, const char *argv[])
DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n");
- ret = sc_set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set SELinux login context.\n");
- goto fail;
+ needs_update = seuser_needs_update(ibuf);
+ if (needs_update == true) {
+ ret = sc_set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set SELinux login context.\n");
+ goto fail;
+ }
}
ret = prepare_response(main_ctx, ret, &resp);
diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
index c0342498cbd0495733a0bf701a06a02cfb705fc7..01a2f41d8752e127f2aa1b72faa61c23f315edd7 100644
--- a/src/util/sss_semanage.c
+++ b/src/util/sss_semanage.c
@@ -369,6 +369,71 @@ done:
return ret;
}
+int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name,
+ char **_seuser, char **_mls_range)
+{
+ errno_t ret;
+ const char *seuser;
+ const char *mls_range;
+ semanage_handle_t *sm_handle = NULL;
+ semanage_seuser_t *sm_user = NULL;
+ semanage_seuser_key_t *sm_key = NULL;
+
+ sm_handle = sss_semanage_init();
+ if (sm_handle == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n");
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_key_create(sm_handle, login_name, &sm_key);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create key for %s\n", login_name);
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_query(sm_handle, sm_key, &sm_user);
+ if (ret < 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot query for %s\n", login_name);
+ ret = EIO;
+ goto done;
+ }
+
+ seuser = semanage_seuser_get_sename(sm_user);
+ if (seuser != NULL) {
+ *_seuser = talloc_strdup(mem_ctx, seuser);
+ if (*_seuser == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_OP_FAILURE,
+ "SELinux user for %s: %s\n", login_name, *_seuser);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get sename for %s\n", login_name);
+ }
+
+ mls_range = semanage_seuser_get_mlsrange(sm_user);
+ if (mls_range != NULL) {
+ *_mls_range = talloc_strdup(mem_ctx, mls_range);
+ if (*_mls_range == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_OP_FAILURE,
+ "SELinux range for %s: %s\n", login_name, *_mls_range);
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get mlsrange for %s\n", login_name);
+ }
+
+ ret = EOK;
+done:
+ semanage_seuser_key_free(sm_key);
+ semanage_seuser_free(sm_user);
+ sss_semanage_close(sm_handle);
+ return ret;
+}
+
#else /* HAVE_SEMANAGE */
int set_seuser(const char *login_name, const char *seuser_name,
const char *mls)
@@ -380,4 +445,10 @@ int del_seuser(const char *login_name)
{
return EOK;
}
+
+int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name,
+ char **_seuser, char **_mls_range)
+{
+ return EOK;
+}
#endif /* HAVE_SEMANAGE */
diff --git a/src/util/util.h b/src/util/util.h
index bf3a9a057aed77e93949370f8651af2631d91432..d217688f81d7a2e49cd3eaaf0d1be609a0f679ea 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -635,5 +635,7 @@ errno_t restore_creds(struct sss_creds *saved_creds);
int set_seuser(const char *login_name, const char *seuser_name,
const char *mlsrange);
int del_seuser(const char *login_name);
+int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name,
+ char **_seuser, char **_mls_range);
#endif /* __SSSD_UTIL_H__ */
--
2.3.5

View File

@ -27,7 +27,7 @@
Name: sssd
Version: 1.12.4
Release: 2%{?dist}
Release: 3%{?dist}
Group: Applications/System
Summary: System Security Services Daemon
License: GPLv3+
@ -38,6 +38,9 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
### Patches ###
Patch0001: 0001-selinux-Delete-existing-user-mapping-on-empty-defaul.patch
Patch0002: 0002-selinux-Handle-setup-with-empty-default-and-no-confi.patch
Patch0003: 0003-selinux-Disconnect-before-closing-the-handle.patch
Patch0004: 0004-selinux-Begin-and-end-the-transaction-on-the-same-ne.patch
Patch0005: 0005-selinux-Only-call-semanage-if-the-context-actually-c.patch
### Dependencies ###
Requires: sssd-common = %{version}-%{release}
@ -904,6 +907,11 @@ if [ $1 -eq 0 ]; then
fi
%changelog
* Wed Apr 15 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-3
- Fix slow login with ipa and SELinux
- Resolves: upstream #2624 - Only set the selinux context if the context
differs from the local one
* Mon Mar 23 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.12.4-2
- Fix regressions with ipa and SELinux
- Resolves: upstream #2587 - With empty ipaselinuxusermapdefault security