]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: protect dladdr() against reentrant calls from the debug handler
authorWilly Tarreau <w@1wt.eu>
Fri, 4 Apr 2025 16:08:45 +0000 (18:08 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 17 Apr 2025 14:25:47 +0000 (16:25 +0200)
If a thread is currently resolving a symbol while another thread triggers
a thread dump, the current thread may enter the debug handler and call
resolve_sym_addr() again, possibly deadlocking if the underlying libc
uses locking. Let's postpone the debug signal delivery in this area
during the call. This will slow the resolution a little bit but we don't
care, it's not supposed to happen often and it must remain rock-solid.

src/tools.c

index b0b066a1d834df0432dd03705d5c0d7d5a42df3e..a8aaccd9f0745efaceddf11379d10c5b2f192c38 100644 (file)
@@ -35,6 +35,7 @@ extern void *__elf_aux_vector;
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -5562,6 +5563,7 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
        static Dl_info dli_main;
        static int dli_main_done; // 0 = not resolved, 1 = resolve in progress, 2 = done
        __decl_thread_var(static HA_SPINLOCK_T dladdr_lock);
+       sigset_t new_mask, old_mask;
        int isolated;
        Dl_info dli;
        size_t size = 0;
@@ -5610,9 +5612,26 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
            HA_SPIN_TRYLOCK(OTHER_LOCK, &dladdr_lock) != 0)
                goto use_array;
 
+       /* make sure we don't re-enter from wdt nor debug coming from other
+        * threads as dladdr() is not re-entrant. We'll block these sensitive
+        * signals while possibly dumping a backtrace.
+        */
+       sigemptyset(&new_mask);
+#ifdef WDTSIG
+       sigaddset(&new_mask, WDTSIG);
+#endif
+#ifdef DEBUGSIG
+       sigaddset(&new_mask, DEBUGSIG);
+#endif
+       ha_sigmask(SIG_BLOCK, &new_mask, &old_mask);
+
+       /* now resolve the symbol */
        i = dladdr_and_size(addr, &dli, &size);
 
        if (!i) {
+               /* unblock temporarily blocked signals */
+               ha_sigmask(SIG_SETMASK, &old_mask, NULL);
+
                if (!isolated)
                        HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);
                goto use_array;
@@ -5638,6 +5657,9 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
                ha_thread_relax();
        }
 
+       /* unblock temporarily blocked signals */
+       ha_sigmask(SIG_SETMASK, &old_mask, NULL);
+
        if (!isolated)
                HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);