From: Willy Tarreau Date: Fri, 4 Apr 2025 16:08:45 +0000 (+0200) Subject: MINOR: tools: protect dladdr() against reentrant calls from the debug handler X-Git-Tag: v3.2-dev11~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2dfb63313b0d2b9d4d636dbd23688d6a20cba2cf;p=thirdparty%2Fhaproxy.git MINOR: tools: protect dladdr() against reentrant calls from the debug handler 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. --- diff --git a/src/tools.c b/src/tools.c index b0b066a1d..a8aaccd9f 100644 --- a/src/tools.c +++ b/src/tools.c @@ -35,6 +35,7 @@ extern void *__elf_aux_vector; #include #include #include +#include #include #include #include @@ -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);