]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: wdt/debug: avoid signal re-entrance between debugger and watchdog
authorWilly Tarreau <w@1wt.eu>
Fri, 4 Apr 2025 15:20:25 +0000 (17:20 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 17 Apr 2025 14:25:47 +0000 (16:25 +0200)
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.

src/debug.c
src/wdt.c

index 273c59ce19a40a4b38757387591cfb68ca57b891..f4e5da14aefb0337b8efeb7a0edb8e78857c1fdc 100644 (file)
@@ -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);
 
index be1b65c31e0d9c28f3f7eb73e5be0574464effb6..16af0a914393c45554b0ca744693910378bbf1f9 100644 (file)
--- 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;