From: Willy Tarreau Date: Fri, 4 Apr 2025 15:20:25 +0000 (+0200) Subject: BUG/MINOR: wdt/debug: avoid signal re-entrance between debugger and watchdog X-Git-Tag: v3.2-dev11~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ebf1757dc26572578492d421e9905707b5e0ca7d;p=thirdparty%2Fhaproxy.git BUG/MINOR: wdt/debug: avoid signal re-entrance between debugger and watchdog As seen in issue #2860, there are some situations where a watchdog could trigger during the debug signal handler, and where similarly the debug signal handler may trigger during the wdt handler. This is really bad because it could trigger some deadlocks inside inner libc code such as dladdr() or backtrace() since the code will not protect against re- entrance but only against concurrent accesses. A first attempt was made using ha_sigmask() but that's not always very convenient because the second handler is called immediately after unblocking the signal and before returning, leaving signal cascades in backtrace. Instead, let's mark which signals to block at registration time. Here we're blocking wdt/dbg for both signals, and optionally SIGRTMAX if DEBUG_DEV is used as that one may also be used in this case. This should be backported at least to 3.1. --- diff --git a/src/debug.c b/src/debug.c index 273c59ce1..f4e5da14a 100644 --- a/src/debug.c +++ b/src/debug.c @@ -2481,6 +2481,13 @@ static int init_debug() sa.sa_handler = NULL; sa.sa_sigaction = debug_handler; sigemptyset(&sa.sa_mask); +#ifdef WDTSIG + sigaddset(&sa.sa_mask, WDTSIG); +#endif + sigaddset(&sa.sa_mask, DEBUGSIG); +#if defined(DEBUG_DEV) + sigaddset(&sa.sa_mask, SIGRTMAX); +#endif sa.sa_flags = SA_SIGINFO; sigaction(DEBUGSIG, &sa, NULL); diff --git a/src/wdt.c b/src/wdt.c index be1b65c31..16af0a914 100644 --- a/src/wdt.c +++ b/src/wdt.c @@ -263,6 +263,13 @@ int init_wdt() sa.sa_handler = NULL; sa.sa_sigaction = wdt_handler; sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, WDTSIG); +#ifdef DEBUGSIG + sigaddset(&sa.sa_mask, DEBUGSIG); +#endif +#if defined(DEBUG_DEV) + sigaddset(&sa.sa_mask, SIGRTMAX); +#endif sa.sa_flags = SA_SIGINFO; sigaction(WDTSIG, &sa, NULL); return ERR_NONE;