A signal is a mechanism for transferring control that is typically used to notify a process that an event has occurred. That process can then respond to that the event accordingly. C99 provides The C Standard provides functions for sending and handling signals within a C program.
Processes handle signals by registering a signal handler using the signal()
function, which is specified as
Code Block |
---|
void (*signal(int sig, void (*func)(int)))(int);
|
This signal handler is conceptually equivalent to
Code Block |
---|
typedef void (*sighandler_t)(int signum);
extern sighandler_t signal(
int signum,
sighandler_t handler
);
|
Signal handlers can be interrupted by signals, including their own. 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 or being interrupted is asynchronousasync-signal-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 noninterruptible and need not be asynchronous-safeasync-signal-safe. However, even when a signal is masked while its own handler is processed, the handler must still avoid invoking async-signal-safe unsafe functions because their execution may be (or have been) interrupted by another signal.
Vulnerabilities can arise if a non—asynchronoussignal handler that is not async-signal-safe signal handler is interrupted with any unmasked signal, including its own.
...
This noncompliant code example registers a single signal handler to process both SIGUSR1
and SIGUSR2
. The variable sig2
should be set to 1
if one or more SIGUSR1
signals are followed by SIGUSR2
, essentially implementing a finite state machine within the signal handler.
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 (sig1) {
sig2 = 1;
}
}
int main(void) {
if (signal(SIGUSR1, handler) == SIG_ERR) {
/* Handle error */
}
if (signal(SIGUSR2, handler) == SIG_ERR) {
/* Handler error */
}
while (sig2 == 0) {
/* Do nothing or give up CPU for a while */
}
/* ... */
return 0;
}
|
Unfortunately, there is a race condition occurs 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.
...
The POSIX sigaction()
function assigns handlers to signals in a similar manner to the C99 C signal()
function, but it also allows signal masks to be set explicitly. Consequently, sigaction()
can be used to prevent a signal handler from interrupting itself.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t sig1 = 0;
volatile sig_atomic_t sig2 = 0;
void handler(int signum) {
if (signum == SIGUSR1) {
sig1 = 1;
}
else if (sig1) {
sig2 = 1;
}
}
int main(void) {
struct sigaction act;
act.sa_handler = &handler;
act.sa_flags = 0;
if (sigemptyset(&act.sa_mask) != 0) {
/* Handle error */
}
if (sigaddset(&act.sa_mask, SIGUSR1)) {
/* Handle error */
}
if (sigaddset(&act.sa_mask, SIGUSR2)) {
/* Handle error */
}
if (sigaction(SIGUSR1, &act, NULL) != 0) {
/* Handle error */
}
if (sigaction(SIGUSR2, &act, NULL) != 0) {
/* Handle error */
}
while (sig2 == 0) {
/* Do nothing or give up CPU for a while */
}
/* ... */
return 0;
}
|
POSIX recommends sigaction()
and deprecates the use of signal()
to register signal handlers. Unfortunately, sigaction()
is not defined in C99 and in the C Standard and is consequently not as portable a solution.
Risk Assessment
Interrupting a noninterruptible signal handler can result in a variety of vulnerabilities \ [[Zalewski 01|AA. References#Zalewski 01]\]Zalewski 2001]. Wiki Markup
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SIG00-C |
High |
Likely |
High | P9 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
CodeSonar |
| BADFUNC.SIGNAL | Use of signal | ||||||
Helix QAC |
| C5019 | |||||||
LDRA tool suite |
| 44 S | Enhanced enforcement | ||||||
Parasoft C/C++test |
| CERT_C-SIG00-a | The signal handling facilities of <signal.h> shall not be used | ||||||
PC-lint Plus |
| 586 | Assistance provided: reports use of the signal function |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
...
Related Guidelines
...
...
...
...
Wiki Markup |
---|
\[[Dowd 06 | AA. References#Dowd 06]\] Chapter 13, "Synchronization and State" (Signal Interruption and Repetition)
\[[ISO/IEC 03|AA. References#ISO/IEC 03]\] Section 5.2.3, "Signals and interrupts"
\[[MITRE 07|AA. References#MITRE 07]\] [CWE ID 662|http://cwe.mitre.org/data/definitions/662.html], "Insufficient Synchronization"
\[[Open Group 04|AA. References#Open Group 04]\] [longjmp|http://www.opengroup.org/onlinepubs/000095399/functions/longjmp.html]
\[[OpenBSD|AA. References#OpenBSD]\] [{{signal()}} Man Page|http://www.openbsd.org/cgi-bin/man.cgi?query=signal]
\[[Zalewski 01|AA. References#Zalewski 01]\] |
CWE-662, Insufficient synchronization |
Bibliography
[C99 Rationale 2003] | Subclause 5.2.3, "Signals and Interrupts" |
[Dowd 2006] | Chapter 13, "Synchronization and State" ("Signal Interruption and Repetition") |
[IEEE Std 1003.1:2013] | XSH, System Interface, longjmp |
[OpenBSD] | signal() Man Page |
[Zalewski 2001] | "Delivering Signals for Fun and Profit" |
...