Signal handlers can be interrupted by signals, including their own signals. If a signal is not reset before its handler is called, the handler can interrupt its own execution. A handler that always successfully executes its code despite interrupting itself is said to be re-entrantasynchronous-safe.
Some platforms provide the ability to mask signals while a signal handler is being processed. If a signal is masked while its own handler is processed, the handler is un-interruptible, and need not be reasynchronous-entrantsafe.
Vulnerabilities can arise if a non-reasynchronous-entrant safe signal handler is interrupted with its own signal, especially if it manipulates globally-accessible data.
...
This non-compliant code example moves the finite state machine out of the signal handler, making the handler reasynchronous-entrantsafe.
Code Block | ||
---|---|---|
| ||
#include <signal.h> volatile sig_atomic_t sig1 = 0; volatile sig_atomic_t sig2 = 0; void handler(int signum) { if (signum == SIGUSR1) { sig1 = 1; } else if (signum == SIGUSR2) { sig2 = 1; } } int main(void) { int state = 0; signal(SIGUSR1, handler); signal(SIGUSR2, handler); while (state != 2) { /* do nothing or give up CPU for a while */ if (state == 0 && sig1) { state = 1; sig2 = 0; } if (state == 1 && sig2) { state = 2; } } /* ... */ return 0; } |
...