src/uid_wrapper.c: always go through uwrap_bind_symbol_all() protected by pthread_once()
authorStefan Metzmacher <metze@samba.org>
Tue, 8 Nov 2022 19:08:40 +0000 (20:08 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 17 Jan 2023 13:24:03 +0000 (14:24 +0100)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15227

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

index 28e2c435c7ecb99f1d6172fdfaeb64c78fa2453e..1b1473be345fbcd628b6386a4dac7ec58684f595 100644 (file)
 
 /* Add new global locks here please */
 # define UWRAP_LOCK_ALL \
-       UWRAP_LOCK(uwrap_id); \
-       UWRAP_LOCK(libc_symbol_binding); \
-       UWRAP_LOCK(libpthread_symbol_binding)
+       UWRAP_LOCK(uwrap_id)
 
 # define UWRAP_UNLOCK_ALL \
-       UWRAP_UNLOCK(libpthread_symbol_binding); \
-       UWRAP_UNLOCK(libc_symbol_binding); \
        UWRAP_UNLOCK(uwrap_id)
 
 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
@@ -388,11 +384,7 @@ 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;
 
-/* The mutex for accessing the global libc.symbols */
-static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-/* The mutex for accessing the global libpthread.symbols */
-static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /*********************************************************
  * UWRAP PROTOTYPES
@@ -514,20 +506,66 @@ static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
 }
 
 #define uwrap_bind_symbol_libc(sym_name) \
-       UWRAP_LOCK(libc_symbol_binding); \
        if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
                uwrap.libc.symbols._libc_##sym_name.obj = \
                        _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
-       } \
-       UWRAP_UNLOCK(libc_symbol_binding)
+       }
 
 #define uwrap_bind_symbol_libpthread(sym_name) \
-       UWRAP_LOCK(libpthread_symbol_binding); \
        if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
                uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
                        _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
-       } \
-       UWRAP_UNLOCK(libpthread_symbol_binding)
+       }
+
+/* DO NOT call this function during library initialization! */
+static void __uwrap_bind_symbol_all_once(void)
+{
+       uwrap_bind_symbol_libc(setuid);
+       uwrap_bind_symbol_libc(getuid);
+#ifdef HAVE_SETEUID
+       uwrap_bind_symbol_libc(seteuid);
+#endif
+#ifdef HAVE_SETREUID
+       uwrap_bind_symbol_libc(setreuid);
+#endif
+#ifdef HAVE_SETRESUID
+       uwrap_bind_symbol_libc(setresuid);
+#endif
+#ifdef HAVE_GETRESUID
+       uwrap_bind_symbol_libc(getresuid);
+#endif
+       uwrap_bind_symbol_libc(geteuid);
+       uwrap_bind_symbol_libc(setgid);
+       uwrap_bind_symbol_libc(getgid);
+#ifdef HAVE_SETEGID
+       uwrap_bind_symbol_libc(setegid);
+#endif
+#ifdef HAVE_SETREGID
+       uwrap_bind_symbol_libc(setregid);
+#endif
+
+#ifdef HAVE_SETRESGID
+       uwrap_bind_symbol_libc(setresgid);
+#endif
+#ifdef HAVE_GETRESGID
+       uwrap_bind_symbol_libc(setresgid);
+#endif
+       uwrap_bind_symbol_libc(getegid);
+       uwrap_bind_symbol_libc(getgroups);
+       uwrap_bind_symbol_libc(setgroups);
+#ifdef HAVE_SYSCALL
+       uwrap_bind_symbol_libc(syscall);
+#endif
+       uwrap_bind_symbol_libpthread(pthread_create);
+       uwrap_bind_symbol_libpthread(pthread_exit);
+}
+
+static void uwrap_bind_symbol_all(void)
+{
+       static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
+
+       pthread_once(&all_symbol_binding_once, __uwrap_bind_symbol_all_once);
+}
 
 /*
  * IMPORTANT
@@ -539,14 +577,14 @@ static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
  */
 static int libc_setuid(uid_t uid)
 {
-       uwrap_bind_symbol_libc(setuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setuid.f(uid);
 }
 
 static uid_t libc_getuid(void)
 {
-       uwrap_bind_symbol_libc(getuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getuid.f();
 }
@@ -554,7 +592,7 @@ static uid_t libc_getuid(void)
 #ifdef HAVE_SETEUID
 static int libc_seteuid(uid_t euid)
 {
-       uwrap_bind_symbol_libc(seteuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_seteuid.f(euid);
 }
@@ -563,7 +601,7 @@ static int libc_seteuid(uid_t euid)
 #ifdef HAVE_SETREUID
 static int libc_setreuid(uid_t ruid, uid_t euid)
 {
-       uwrap_bind_symbol_libc(setreuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
 }
@@ -572,7 +610,7 @@ static int libc_setreuid(uid_t ruid, uid_t euid)
 #ifdef HAVE_SETRESUID
 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 {
-       uwrap_bind_symbol_libc(setresuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
 }
@@ -581,7 +619,7 @@ static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 #ifdef HAVE_GETRESUID
 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
 {
-       uwrap_bind_symbol_libc(getresuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
 }
@@ -589,21 +627,21 @@ static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
 
 static uid_t libc_geteuid(void)
 {
-       uwrap_bind_symbol_libc(geteuid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_geteuid.f();
 }
 
 static int libc_setgid(gid_t gid)
 {
-       uwrap_bind_symbol_libc(setgid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setgid.f(gid);
 }
 
 static gid_t libc_getgid(void)
 {
-       uwrap_bind_symbol_libc(getgid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getgid.f();
 }
@@ -611,7 +649,7 @@ static gid_t libc_getgid(void)
 #ifdef HAVE_SETEGID
 static int libc_setegid(gid_t egid)
 {
-       uwrap_bind_symbol_libc(setegid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setegid.f(egid);
 }
@@ -620,7 +658,7 @@ static int libc_setegid(gid_t egid)
 #ifdef HAVE_SETREGID
 static int libc_setregid(gid_t rgid, gid_t egid)
 {
-       uwrap_bind_symbol_libc(setregid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
 }
@@ -629,7 +667,7 @@ static int libc_setregid(gid_t rgid, gid_t egid)
 #ifdef HAVE_SETRESGID
 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 {
-       uwrap_bind_symbol_libc(setresgid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
 }
@@ -638,7 +676,7 @@ static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 #ifdef HAVE_GETRESGID
 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 {
-       uwrap_bind_symbol_libc(setresgid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
 }
@@ -646,14 +684,14 @@ static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 
 static gid_t libc_getegid(void)
 {
-       uwrap_bind_symbol_libc(getegid);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getegid.f();
 }
 
 static int libc_getgroups(int size, gid_t list[])
 {
-       uwrap_bind_symbol_libc(getgroups);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_getgroups.f(size, list);
 }
@@ -671,7 +709,7 @@ static int libc___getgroups_chk(int size, gid_t list[], size_t listlen)
 
 static int libc_setgroups(size_t size, const gid_t *list)
 {
-       uwrap_bind_symbol_libc(setgroups);
+       uwrap_bind_symbol_all();
 
        return uwrap.libc.symbols._libc_setgroups.f(size, list);
 }
@@ -684,7 +722,7 @@ static long int libc_vsyscall(long int sysno, va_list va)
        long int rc;
        int i;
 
-       uwrap_bind_symbol_libc(syscall);
+       uwrap_bind_symbol_all();
 
        for (i = 0; i < 8; i++) {
                args[i] = va_arg(va, long int);
@@ -704,13 +742,25 @@ static long int libc_vsyscall(long int sysno, va_list va)
 }
 #endif
 
+static int libpthread_pthread_create(pthread_t *thread,
+                               const pthread_attr_t *attr,
+                               void *(*start_routine) (void *),
+                               void *arg)
+{
+       uwrap_bind_symbol_all();
+       return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
+                                                                    attr,
+                                                                    start_routine,
+                                                                    arg);
+}
+
 /*
  * This part is "optimistic".
  * Thread can ends without pthread_exit call.
  */
 static void libpthread_pthread_exit(void *retval)
 {
-       uwrap_bind_symbol_libpthread(pthread_exit);
+       uwrap_bind_symbol_all();
 
        uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
 }
@@ -750,18 +800,6 @@ void pthread_exit(void *retval)
        exit(666);
 }
 
-static int libpthread_pthread_create(pthread_t *thread,
-                               const pthread_attr_t *attr,
-                               void *(*start_routine) (void *),
-                               void *arg)
-{
-       uwrap_bind_symbol_libpthread(pthread_create);
-       return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
-                                                                    attr,
-                                                                    start_routine,
-                                                                    arg);
-}
-
 struct uwrap_pthread_create_args {
        struct uwrap_thread *id;
        void *(*start_routine) (void *);
@@ -967,6 +1005,12 @@ static void uwrap_thread_prepare(void)
 {
        struct uwrap_thread *id = uwrap_tls_id;
 
+       /*
+        * We bind all symbols to avoid deadlocks of the fork is interrupted by
+        * a signal handler using a symbol of this library.
+        */
+       uwrap_bind_symbol_all();
+
        UWRAP_LOCK_ALL;
 
        /* uid_wrapper is loaded but not enabled */