It is possible to safely use the same handler for multiple signals, but doing so increases the likelihood of a security vulnerability. The delivered signal is masked and is not delivered until the registered signal handler exits. However, if this same handler is registered to handle a different signal, execution of the handler may be interrupted by this new signal. If a signal handler is constructed with the expectation that it cannot be interrupted, a vulnerability might exist. To eliminate this attack vector, each signal handler should only be registered to handle only one type of signal.
Non-Compliant Coding Example
...
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdlib.h> #include <string.h> volatile sig_atomic_t sig1 = 0; volatile sig_atomic_t sig2 = 0; void handler(int signum) { if (sig1) { sig2 = 1; } if (signum == SIGUSR1) { sig1 = 1; } } int main(void) { signal(SIGUSR1, handler); signal(SIGUSR2, handler); while (1) { if (sig2) break; sleep(SLEEP_TIME); } /* ... */ return 0; } |
The problem with this code is that there is a race condition in the implementation of handler()
. If handler()
is called to handle SIGUSR1
, and is interrupted to handle SIGUSR2
, it is possible that sig2
will not be set. This non-compliant code example also violates SIG31-C. Do not access or modify shared objects in signal handlers.
...
This compliant solution registers two separate signal handlers to process SIGUSR1
and SIGUSR2
. The sig1_handler()
handler waits for SIGUSER1
. After this signal occurs, the sig2_handler()
is registered to handle SIGUSER2
. This solution is fully compliant and accomplishing accomplishes the goal of detecting whether one or more SIGUSR1
signals are followed by SIGUSR2
.
Code Block | ||
---|---|---|
| ||
#include <signal.h> #include <stdlib.h> #include <string.h> volatile sig_atomic_t sig1 = 0; volatile sig_atomic_t sig2 = 0; void sig1_handler(int signum) { sig1 = 1; } void sig2_handler(int signum) { sig2 = 1; } int main(void) { signal(SIGUSR1, handler); while (1) { if (sig1) break; sleep(SLEEP_TIME); } signal(SIGUSR2, handler); while (1) { if (sig2) break; sleep(SLEEP_TIME); } /* ... */ return 0; } |
...