Blame SOURCES/0010-CLIENT-fix-client-fd-leak.patch

de2e0a
From 1b2e4760c52b9abd0d9b9f35b47ed72e79922ccc Mon Sep 17 00:00:00 2001
de2e0a
From: Alexey Tikhonov <atikhono@redhat.com>
de2e0a
Date: Thu, 25 Aug 2022 18:10:46 +0200
de2e0a
Subject: [PATCH] CLIENT: fix client fd leak
de2e0a
de2e0a
 - close client socket at thread exit
de2e0a
 - only build lock-free client support if libc has required
de2e0a
   functionality for a proper cleanup
de2e0a
 - use proper mechanisms to init lock_mode only once
de2e0a
de2e0a
:relnote:Lock-free client support will be only built if libc
de2e0a
provides `pthread_key_create()` and `pthread_once()`. For glibc
de2e0a
this means version 2.34+
de2e0a
de2e0a
Reviewed-by: Justin Stephenson <jstephen@redhat.com>
de2e0a
Reviewed-by: Sumit Bose <sbose@redhat.com>
de2e0a
(cherry picked from commit 1a6f67c92399ff8e358a6c6cdda43fb2547a5fdb)
de2e0a
---
de2e0a
 configure.ac                     | 29 +++++++++--
de2e0a
 src/man/Makefile.am              |  5 +-
de2e0a
 src/man/sssd.8.xml               |  2 +-
de2e0a
 src/sss_client/common.c          | 83 +++++++++++++++++++-------------
de2e0a
 src/sss_client/idmap/common_ex.c |  4 ++
de2e0a
 5 files changed, 84 insertions(+), 39 deletions(-)
de2e0a
de2e0a
diff --git a/configure.ac b/configure.ac
de2e0a
index 93bd93b85..5a05de41e 100644
de2e0a
--- a/configure.ac
de2e0a
+++ b/configure.ac
de2e0a
@@ -51,18 +51,39 @@ AC_CHECK_TYPES([errno_t], [], [], [[#include <errno.h>]])
de2e0a
 m4_include([src/build_macros.m4])
de2e0a
 BUILD_WITH_SHARED_BUILD_DIR
de2e0a
 
de2e0a
-AC_COMPILE_IFELSE(
de2e0a
+
de2e0a
+SAVE_LIBS=$LIBS
de2e0a
+LIBS=
de2e0a
+AC_LINK_IFELSE(
de2e0a
     [AC_LANG_PROGRAM([[#include <pthread.h>]],
de2e0a
         [[pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
de2e0a
-          (void) m; /* unused */
de2e0a
+          pthread_mutex_lock(&m);
de2e0a
+          pthread_mutex_unlock(&m);
de2e0a
         ]])],
de2e0a
     [AC_DEFINE([HAVE_PTHREAD], [1], [Pthread mutexes available.])
de2e0a
      HAVE_PTHREAD=1
de2e0a
     ],
de2e0a
-    [AC_MSG_WARN([Pthread library not found! Clients will not be thread safe...])])
de2e0a
+    [AC_MSG_WARN([Pthread mutex support not found! Clients will not be thread safe...])])
de2e0a
+LIBS=$SAVE_LIBS
de2e0a
+AM_CONDITIONAL([HAVE_PTHREAD], [test x"$HAVE_PTHREAD" != "x"])
de2e0a
 
de2e0a
 
de2e0a
-AM_CONDITIONAL([HAVE_PTHREAD], [test x"$HAVE_PTHREAD" != "x"])
de2e0a
+SAVE_LIBS=$LIBS
de2e0a
+LIBS=
de2e0a
+AC_LINK_IFELSE(
de2e0a
+    [AC_LANG_PROGRAM([[#include <pthread.h>]],
de2e0a
+        [[static pthread_key_t k;
de2e0a
+          static pthread_once_t f = PTHREAD_ONCE_INIT;
de2e0a
+          pthread_once(&f, NULL);
de2e0a
+          pthread_key_create(&k, NULL);
de2e0a
+        ]])],
de2e0a
+    [AC_DEFINE([HAVE_PTHREAD_EXT], [1], [Extended pthread functionality is available.])
de2e0a
+     HAVE_PTHREAD_EXT=1
de2e0a
+    ],
de2e0a
+    [AC_MSG_WARN([Extended pthread functionality is not available. Lock-free client feature will not be built.])])
de2e0a
+LIBS=$SAVE_LIBS
de2e0a
+AM_CONDITIONAL([BUILD_LOCKFREE_CLIENT], [test x"$HAVE_PTHREAD_EXT" != "x"])
de2e0a
+
de2e0a
 
de2e0a
 # Check library for the timer_create function
de2e0a
 SAVE_LIBS=$LIBS
de2e0a
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
de2e0a
index 93dd14819..063ff1bf0 100644
de2e0a
--- a/src/man/Makefile.am
de2e0a
+++ b/src/man/Makefile.am
de2e0a
@@ -46,9 +46,12 @@ endif
de2e0a
 if BUILD_KCM_RENEWAL
de2e0a
 KCM_RENEWAL_CONDS = ;enable_kcm_renewal
de2e0a
 endif
de2e0a
+if BUILD_LOCKFREE_CLIENT
de2e0a
+LOCKFREE_CLIENT_CONDS = ;enable_lockfree_support
de2e0a
+endif
de2e0a
 
de2e0a
 
de2e0a
-CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(KCM_RENEWAL_CONDS)
de2e0a
+CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS)$(STAP_CONDS)$(KCM_RENEWAL_CONDS)$(LOCKFREE_CLIENT_CONDS)
de2e0a
 
de2e0a
 
de2e0a
 #Special Rules:
de2e0a
diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml
de2e0a
index df07b7f29..5f507c631 100644
de2e0a
--- a/src/man/sssd.8.xml
de2e0a
+++ b/src/man/sssd.8.xml
de2e0a
@@ -240,7 +240,7 @@
de2e0a
             If the environment variable SSS_NSS_USE_MEMCACHE is set to "NO",
de2e0a
             client applications will not use the fast in-memory cache.
de2e0a
         </para>
de2e0a
-        <para>
de2e0a
+        <para condition="enable_lockfree_support">
de2e0a
             If the environment variable SSS_LOCKFREE is set to "NO", requests
de2e0a
             from multiple threads of a single application will be serialized.
de2e0a
         </para>
de2e0a
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
de2e0a
index 29c751a50..d762dff49 100644
de2e0a
--- a/src/sss_client/common.c
de2e0a
+++ b/src/sss_client/common.c
de2e0a
@@ -35,7 +35,6 @@
de2e0a
 #include <stdlib.h>
de2e0a
 #include <stdbool.h>
de2e0a
 #include <stdint.h>
de2e0a
-#include <stdatomic.h>
de2e0a
 #include <string.h>
de2e0a
 #include <fcntl.h>
de2e0a
 #include <poll.h>
de2e0a
@@ -62,8 +61,15 @@
de2e0a
 
de2e0a
 /* common functions */
de2e0a
 
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
+static pthread_key_t sss_sd_key;
de2e0a
+static pthread_once_t sss_sd_key_initialized = PTHREAD_ONCE_INIT;
de2e0a
 static __thread int sss_cli_sd = -1; /* the sss client socket descriptor */
de2e0a
 static __thread struct stat sss_cli_sb; /* the sss client stat buffer */
de2e0a
+#else
de2e0a
+static int sss_cli_sd = -1; /* the sss client socket descriptor */
de2e0a
+static struct stat sss_cli_sb; /* the sss client stat buffer */
de2e0a
+#endif
de2e0a
 
de2e0a
 #if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR
de2e0a
 __attribute__((destructor))
de2e0a
@@ -76,6 +82,18 @@ void sss_cli_close_socket(void)
de2e0a
     }
de2e0a
 }
de2e0a
 
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
+static void sss_at_thread_exit(void *v)
de2e0a
+{
de2e0a
+    sss_cli_close_socket();
de2e0a
+}
de2e0a
+
de2e0a
+static void init_sd_key(void)
de2e0a
+{
de2e0a
+    pthread_key_create(&sss_sd_key, sss_at_thread_exit);
de2e0a
+}
de2e0a
+#endif
de2e0a
+
de2e0a
 /* Requests:
de2e0a
  *
de2e0a
  * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
de2e0a
@@ -553,6 +571,16 @@ static int sss_cli_open_socket(int *errnop, const char *socket_name, int timeout
de2e0a
         return -1;
de2e0a
     }
de2e0a
 
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
+    pthread_once(&sss_sd_key_initialized, init_sd_key); /* once for all threads */
de2e0a
+
de2e0a
+    /* It actually doesn't matter what value to set for a key.
de2e0a
+     * The only important thing: key must be non-NULL to ensure
de2e0a
+     * destructor is executed at thread exit.
de2e0a
+     */
de2e0a
+    pthread_setspecific(sss_sd_key, &sss_cli_sd);
de2e0a
+#endif
de2e0a
+
de2e0a
     /* set as non-blocking, close on exec, and make sure standard
de2e0a
      * descriptors are not used */
de2e0a
     sd = make_safe_fd(sd);
de2e0a
@@ -1129,41 +1157,38 @@ errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len)
de2e0a
 }
de2e0a
 
de2e0a
 #if HAVE_PTHREAD
de2e0a
-bool sss_is_lockfree_mode(void)
de2e0a
+
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
+static bool sss_lock_free = true;
de2e0a
+static pthread_once_t sss_lock_mode_initialized = PTHREAD_ONCE_INIT;
de2e0a
+
de2e0a
+static void init_lock_mode(void)
de2e0a
 {
de2e0a
-    const char *env = NULL;
de2e0a
-    enum {
de2e0a
-        MODE_UNDEF,
de2e0a
-        MODE_LOCKING,
de2e0a
-        MODE_LOCKFREE
de2e0a
-    };
de2e0a
-    static atomic_int mode = MODE_UNDEF;
de2e0a
-
de2e0a
-    if (mode == MODE_UNDEF) {
de2e0a
-        env = getenv("SSS_LOCKFREE");
de2e0a
-        if ((env != NULL) && (strcasecmp(env, "NO") == 0)) {
de2e0a
-            mode = MODE_LOCKING;
de2e0a
-        } else {
de2e0a
-            mode = MODE_LOCKFREE;
de2e0a
-        }
de2e0a
+    const char *env = getenv("SSS_LOCKFREE");
de2e0a
+
de2e0a
+    if ((env != NULL) && (strcasecmp(env, "NO") == 0)) {
de2e0a
+        sss_lock_free = false;
de2e0a
     }
de2e0a
+}
de2e0a
 
de2e0a
-    return (mode == MODE_LOCKFREE);
de2e0a
+bool sss_is_lockfree_mode(void)
de2e0a
+{
de2e0a
+    pthread_once(&sss_lock_mode_initialized, init_lock_mode);
de2e0a
+    return sss_lock_free;
de2e0a
 }
de2e0a
+#endif
de2e0a
 
de2e0a
 struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
de2e0a
-
de2e0a
 static struct sss_mutex sss_pam_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
de2e0a
-
de2e0a
-static struct sss_mutex sss_nss_mc_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
de2e0a
-
de2e0a
 static struct sss_mutex sss_pac_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
de2e0a
 
de2e0a
 static void sss_mt_lock(struct sss_mutex *m)
de2e0a
 {
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
     if (sss_is_lockfree_mode()) {
de2e0a
         return;
de2e0a
     }
de2e0a
+#endif
de2e0a
 
de2e0a
     pthread_mutex_lock(&m->mtx);
de2e0a
     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m->old_cancel_state);
de2e0a
@@ -1171,9 +1196,11 @@ static void sss_mt_lock(struct sss_mutex *m)
de2e0a
 
de2e0a
 static void sss_mt_unlock(struct sss_mutex *m)
de2e0a
 {
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
     if (sss_is_lockfree_mode()) {
de2e0a
         return;
de2e0a
     }
de2e0a
+#endif
de2e0a
 
de2e0a
     pthread_setcancelstate(m->old_cancel_state, NULL);
de2e0a
     pthread_mutex_unlock(&m->mtx);
de2e0a
@@ -1189,7 +1216,7 @@ void sss_nss_unlock(void)
de2e0a
     sss_mt_unlock(&sss_nss_mtx);
de2e0a
 }
de2e0a
 
de2e0a
-/* NSS mutex wrappers */
de2e0a
+/* PAM mutex wrappers */
de2e0a
 void sss_pam_lock(void)
de2e0a
 {
de2e0a
     sss_mt_lock(&sss_pam_mtx);
de2e0a
@@ -1199,16 +1226,6 @@ void sss_pam_unlock(void)
de2e0a
     sss_mt_unlock(&sss_pam_mtx);
de2e0a
 }
de2e0a
 
de2e0a
-/* NSS mutex wrappers */
de2e0a
-void sss_nss_mc_lock(void)
de2e0a
-{
de2e0a
-    sss_mt_lock(&sss_nss_mc_mtx);
de2e0a
-}
de2e0a
-void sss_nss_mc_unlock(void)
de2e0a
-{
de2e0a
-    sss_mt_unlock(&sss_nss_mc_mtx);
de2e0a
-}
de2e0a
-
de2e0a
 /* PAC mutex wrappers */
de2e0a
 void sss_pac_lock(void)
de2e0a
 {
de2e0a
diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c
de2e0a
index 4f454cd63..8c4894fd9 100644
de2e0a
--- a/src/sss_client/idmap/common_ex.c
de2e0a
+++ b/src/sss_client/idmap/common_ex.c
de2e0a
@@ -28,7 +28,9 @@
de2e0a
 #include "common_private.h"
de2e0a
 
de2e0a
 extern struct sss_mutex sss_nss_mtx;
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
 bool sss_is_lockfree_mode(void);
de2e0a
+#endif
de2e0a
 
de2e0a
 #define SEC_FROM_MSEC(ms) ((ms) / 1000)
de2e0a
 #define NSEC_FROM_MSEC(ms) (((ms) % 1000) * 1000 * 1000)
de2e0a
@@ -51,9 +53,11 @@ static int sss_mt_timedlock(struct sss_mutex *m, const struct timespec *endtime)
de2e0a
 {
de2e0a
     int ret;
de2e0a
 
de2e0a
+#ifdef HAVE_PTHREAD_EXT
de2e0a
     if (sss_is_lockfree_mode()) {
de2e0a
         return 0;
de2e0a
     }
de2e0a
+#endif
de2e0a
 
de2e0a
     ret = pthread_mutex_timedlock(&m->mtx, endtime);
de2e0a
     if (ret != 0) {
de2e0a
-- 
de2e0a
2.37.1
de2e0a