...
Code Block |
---|
|
void handler(int signum) {
/* handlingHandle codeSignal */
}
|
Non-Compliant Code Example
...
Code Block |
---|
|
void handler(int signum) {
signal(signum, handler);
/* handlingHandle codeSignal */
}
|
Unfortunately this solution still contains a race window, starting when the host environment resets the signal and ending when the handler calls signal()
. During that time, a second signal sent to the program will trigger the default signal behavior, thereby defeating the persistent behavior.
...
Code Block |
---|
|
/* Equivalent to signal(SIGUSR1, handler) but make signal persistent */
struct sigaction act;
act.sa_handler = handler;
act.sa_flags = 0;
if (sigemptyset(&act.sa_mask) != 0) {
/* handleHandle errorError */
}
if (sigaction(SIGUSR1, &act, NULL) != 0) {
/* handleHandle errorError */
}
|
POSIX recommends sigaction()
and deprecates signal()
. Unfortunately, sigaction()
is not defined in C99 and is consequently not as portable a solution.
...
Code Block |
---|
|
void handler(int signum) {
/* handlingHandle codeSignal */
}
|
Compliant Solution (Unix & Windows)
...
Code Block |
---|
|
void handler(int signum) {
#ifndef WINDOWS
signal(signum, SIG_DFL);
#endif
/* handlingHandle codeSignal */
}
|
With the Compliant Solution for Unix, there is no race condition that can be exploited by an attacker in sending a second signal. And that is because a second signal sent to the handler, before the latter calls signal(signum, SIG_DFL),
will merely cause the handler to restart, and call signal()
anyway.
...
Code Block |
---|
|
/* Equivalent to signal( SIGUSR1, handler) but make signal non-persistent */
struct sigaction act;
act.sa_handler = handler;
act.sa_flags = SA_RESETHAND;
if (sigemptyset(&act.sa_mask) != 0) {
/* handleHandle errorError */
}
if (sigaction(SIGUSR1, &act, NULL) != 0) {
/* handleHandle errorError */
}
|
Risk Assessment
Failure to understand implementation-specific details regarding signal handler persistence can lead to unexpected behavior.
...