...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> void handler(int signum) { if (signal(signum, handler) == SIG_ERR) { /* Handle error */ } /* Handle signal */ } /* ... */ void func(void) { if (signal(SIGUSR1, handler) == SIG_ERR) { /* Handle error */ } } |
On nonpersistent platforms, this solution 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, consequently defeating the persistent behavior implied by the call to signal()
from within the handler to reassert the binding.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> void handler(int signum) { /* Handle signal */ } /* ... */ void func(void) { if (signal(SIGUSR1, handler) == SIG_ERR) { /* Handle error */ } } |
Compliant Solution (POSIX)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> void handler(int signum) { /* Handle signal */ } /* ... */ void func(void) { struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; if (sigemptyset( &act.sa_mask) != 0) { /* Handle error */ } if (sigaction(SIGUSR1, &act, NULL) != 0) { /* Handle error */ } } |
Although the handler in this example does not call signal()
, it could do so safely because the signal is masked, and the handler cannot be interrupted. If the same handler is installed for more than one signal number, the signals must be masked explicitly in act.sa_mask
to ensure that the handler cannot be interrupted because the system masks only the signal being delivered.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> void handler(int signum) { #ifndef WINDOWS#if !defined(_WIN32) if (signal(signum, SIG_DFL) == SIG_ERR) { /* Handle error */ } #endif /* Handle signal */ } /* ... */ void func(void) { if (signal(SIGUSR1, handler) == SIG_ERR) { /* Handle error */ } } |
Risk Assessment
Two signals in quick succession can trigger the race condition on nonpersistent platforms, causing the signal's default behavior despite a handler's attempt to override it.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SIG34-C | low | unlikely | low | P3 | L3 |
Automated Detection
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Compass/ROSE | Can detect violations of this rule. However, false positives may occur on systems with persistent handlers | ||||||||
PRQA QA-C |
| Warncall -wc signal | Partially implemented |
...
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | SIG34-CPP. Do not call signal() from within interruptible signal handlers |
CERT C Secure Coding Standard | SIG01-C. Understand implementation-specific details regarding signal handler persistence |
ISO/IEC TS 17961 (Draft) | Calling signal from interruptible signal handlers [sigcall] |
MITRE CWE | CWE-479, Unsafe function call from a signal handler |
...