From 700e3cf1759f7da387411d13cffbdd3420b81313 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Mon, 16 Nov 2015 18:56:02 +0000 Subject: Remove potential race condition when setting signal handlers There was the potential for signal_run_callback to be invoked after calling sigaction for a signal, prior to the internal signal handler signal_SIG***_handler and signal_SIG***_v variables being set up. To remove the race condition, when setting a signal handler block the signal until the internal handlers have been fully set up. Signed-off-by: Quentin Armitage (cherry picked from commit 223ee0dcd19de5cc92be8a8a452eb37f702a27ef) --- lib/signals.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/signals.c b/lib/signals.c index d6bbcac..9d437f8 100644 --- a/lib/signals.c +++ b/lib/signals.c @@ -81,16 +81,38 @@ void * signal_set(int signo, void (*func) (void *, int), void *v) { int ret; + sigset_t sset; struct sigaction sig; struct sigaction osig; - sig.sa_handler = signal_handler; + assert(func != NULL); + + if (func == (void*)SIG_IGN || func == (void*)SIG_DFL) { + sig.sa_handler = (void*)func; + + /* We are no longer handling the signal, so + * clear our handlers + */ + func = NULL; + v = NULL; + } + else + sig.sa_handler = signal_handler; sigemptyset(&sig.sa_mask); sig.sa_flags = 0; #ifdef SA_RESTART sig.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ + /* Block the signal we are about to configure, to avoid + * any race conditions while setting the handler and + * parameter */ + if (func != NULL) { + sigemptyset(&sset); + sigaddset(&sset, signo); + sigprocmask(SIG_BLOCK, &sset, NULL); + } + ret = sigaction(signo, &sig, &osig); switch(signo) { @@ -122,8 +144,12 @@ signal_set(int signo, void (*func) (void *, int), void *v) if (ret < 0) return (SIG_ERR); - else - return (osig.sa_handler); + + /* Release the signal */ + if (func != NULL) + sigprocmask(SIG_UNBLOCK, &sset, NULL); + + return (void*)osig.sa_handler; } /* Signal Ignore */ -- 1.7.12.1