src/uid_wrapper.c: fix mutex fork handling
authorStefan Metzmacher <metze@samba.org>
Tue, 8 Nov 2022 19:31:35 +0000 (20:31 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 17 Jan 2023 13:30:49 +0000 (14:30 +0100)
We need to use pthread_mutex_init in the child handler...
See https://sourceware.org/bugzilla/show_bug.cgi?id=2745

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/uid_wrapper.c

index 9246546be7d4c79b7baac997d5e137ca1c3a82f0..f81c5539fa45d187381cc4c27a776a3ea064ae48 100644 (file)
 # define UWRAP_THREAD
 #endif
 
-# define UWRAP_LOCK(m) do { \
-       pthread_mutex_lock(&( m ## _mutex)); \
-} while(0)
-
-# define UWRAP_UNLOCK(m) do { \
-       pthread_mutex_unlock(&( m ## _mutex)); \
-} while(0)
-
-/* Add new global locks here please */
-# define UWRAP_LOCK_ALL \
-       UWRAP_LOCK(uwrap_id)
-
-# define UWRAP_UNLOCK_ALL \
-       UWRAP_UNLOCK(uwrap_id)
-
 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
 #else
@@ -384,7 +369,113 @@ static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
 /* The mutex or accessing the id */
 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+#define uwrap_init_mutex(m) _uwrap_init_mutex(m, #m)
+static int _uwrap_init_mutex(pthread_mutex_t *m, const char *name)
+{
+       pthread_mutexattr_t ma;
+       bool need_destroy = false;
+       int ret = 0;
+
+#define __CHECK(cmd)                                    \
+       do {                                            \
+               ret = cmd;                              \
+               if (ret != 0) {                         \
+                       UWRAP_LOG(UWRAP_LOG_ERROR,      \
+                                 "%s: %s - failed %d", \
+                                 name,                 \
+                                 #cmd,                 \
+                                 ret);                 \
+                       goto done;                      \
+               }                                       \
+       } while (0)
+
+       *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+       __CHECK(pthread_mutexattr_init(&ma));
+       need_destroy = true;
+       __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
+       __CHECK(pthread_mutex_init(m, &ma));
+done:
+       if (need_destroy) {
+               pthread_mutexattr_destroy(&ma);
+       }
+       return ret;
+}
 
+#define uwrap_mutex_lock(m) _uwrap_mutex_lock(m, #m, __func__, __LINE__)
+static void _uwrap_mutex_lock(pthread_mutex_t *mutex,
+                             const char *name,
+                             const char *caller,
+                             unsigned line)
+{
+       int ret;
+
+       ret = pthread_mutex_lock(mutex);
+       if (ret != 0) {
+               UWRAP_LOG(UWRAP_LOG_ERROR,
+                         "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread "
+                         "mutex(%s) - %s",
+                         getpid(),
+                         getppid(),
+                         caller,
+                         line,
+                         name,
+                         strerror(ret));
+               abort();
+       }
+}
+
+#define uwrap_mutex_unlock(m) _uwrap_mutex_unlock(m, #m, __func__, __LINE__)
+static void _uwrap_mutex_unlock(pthread_mutex_t *mutex,
+                               const char *name,
+                               const char *caller,
+                               unsigned line)
+{
+       int ret;
+
+       ret = pthread_mutex_unlock(mutex);
+       if (ret != 0) {
+               UWRAP_LOG(UWRAP_LOG_ERROR,
+                         "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread "
+                         "mutex(%s) - %s",
+                         getpid(),
+                         getppid(),
+                         caller,
+                         line,
+                         name,
+                         strerror(ret));
+               abort();
+       }
+}
+
+#define UWRAP_LOCK(m)                           \
+       do {                                    \
+               uwrap_mutex_lock(&(m##_mutex)); \
+       } while (0)
+
+#define UWRAP_UNLOCK(m)                           \
+       do {                                      \
+               uwrap_mutex_unlock(&(m##_mutex)); \
+       } while (0)
+
+/* Add new global locks here please */
+#define UWRAP_REINIT_ALL                                 \
+       do {                                             \
+               int ret;                                 \
+               ret = uwrap_init_mutex(&uwrap_id_mutex); \
+               if (ret != 0)                            \
+                       exit(-1);                        \
+       } while (0)
+
+/* Add new global locks here please */
+#define UWRAP_LOCK_ALL                \
+       do {                          \
+               UWRAP_LOCK(uwrap_id); \
+       } while (0)
+
+#define UWRAP_UNLOCK_ALL                \
+       do {                            \
+               UWRAP_UNLOCK(uwrap_id); \
+       } while (0)
 
 /*********************************************************
  * UWRAP PROTOTYPES
@@ -1063,9 +1154,10 @@ static void uwrap_thread_child(void)
        struct uwrap_thread *id = uwrap_tls_id;
        struct uwrap_thread *u = uwrap.ids;
 
+       UWRAP_REINIT_ALL;
+
        /* uid_wrapper is loaded but not enabled */
        if (id == NULL) {
-               UWRAP_UNLOCK_ALL;
                return;
        }
 
@@ -1092,8 +1184,6 @@ static void uwrap_thread_child(void)
        uwrap_export_ids(id);
 
        id->enabled = true;
-
-       UWRAP_UNLOCK_ALL;
 }
 
 static unsigned long uwrap_get_xid_from_env(const char *envname)
@@ -2607,6 +2697,8 @@ void uwrap_constructor(void)
        }
        glibc_malloc_lock_bug[0] = '\0';
 
+       UWRAP_REINIT_ALL;
+
        /*
        * If we hold a lock and the application forks, then the child
        * is not able to unlock the mutex and we are in a deadlock.