Call only asynchronous-safe functions within signal handlers. For strictly conforming programs, only the C standard library functions
signal() can be called from within a signal handler.
Subclause 18.104.22.168, paragraph 5, of the C Standard [ISO/IEC 9899:2011] states that if the signal occurs other than as the result of calling the
raise() function, the behavior is undefined if
...the signal handler calls any function in the standard library other than the
quick_exitfunction, or the
signalfunction with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler.
Many systems define an implementation-specific list of asynchronous-safe functions. These functions can also be called within a signal handler. This restriction applies to library functions as well as application-defined functions.
According to Subclause 22.214.171.124 of the C Rationale [C99 Rationale 2003],
When a signal occurs, the normal flow of control of a program is interrupted. If a signal occurs that is being trapped by a signal handler, that handler is invoked. When it is finished, execution continues at the point at which the signal occurred. This arrangement can cause problems if the signal handler invokes a library function that was being executed at the time of the signal.
In general, it is not safe to invoke I/O functions from within signal handlers. Make sure a function is included in the list of system's asynchronous-safe functions for all implementations your code will run on before using them in signal handlers.
Noncompliant Code Example
In this noncompliant example, the C standard library functions
free() are called from the signal handler via the function
log_message(). Neither function is asynchronous-safe.
Signal handlers should be as concise as possible—ideally, unconditionally setting a flag and returning. This compliant solution sets a flag of type
volatile sig_atomic_t and returns; the
free() functions are called directly from
Noncompliant Code Example
longjmp() function from within a signal handler can lead to undefined behavior if it results in the invocation of any non-asynchronous-safe functions, likely compromising the integrity of the program. Consequently, neither
longjmp() nor the POSIX
siglongjmp() should ever be called from within a signal handler.
This noncompliant code example is similar to a vulnerability in an old version of Sendmail [VU #834865]. The intent is to execute code in a
main() loop, which also logs some data. Upon receiving a
SIGINT, the program transfers out of the loop, logs the error, and terminates.
However, an attacker can exploit this noncompliant code example by generating a
SIGINT just before the second
if statement in
log_message(). The result is that
longjmp() transfers control back to
log_message() is called again. However, the first
if statement would not be executed this time (because
buf is not set to
NULL as a result of the interrupt), and the program would write to the invalid memory location referenced by
In this compliant solution, the call to
longjmp() is removed; the signal handler sets an error flag of type
volatile sig_atomic_t instead:
Noncompliant Code Example
In this noncompliant code example, the
int_handler() function is used to carry out tasks specific to
SIGINT and then raises
SIGTERM. However, there is a nested call to the
raise() function, which results in undefined behavior.
In this compliant solution,
term_handler() instead of raising
The following table from the POSIX standard [IEEE Std 1003.1:2013] defines a set of functions that are asynchronous-signal-safe. Applications may invoke these functions, without restriction, from a signal handler.
All functions not listed in this table are considered to be unsafe with respect to signals. In the presence of signals, all POSIX functions behave as defined when called from or interrupted by a signal handler, with a single exception: when a signal interrupts an unsafe function and the signal handler calls an unsafe function, the behavior is undefined.
Subclause 126.96.36.199, paragraph 4, of the C Standard [ISO/IEC 9899:2011] states:
If the signal occurs as the result of calling the
raisefunction, the signal handler shall not call the
See also undefined behavior 131.
signal() man page identifies functions that are asynchronous-signal safe. Applications may consequently invoke them, without restriction, from a signal handler.
signal() manual page lists a few additional functions that are asynchronous-safe in OpenBSD but "probably not on other systems," including
syslog_r() (but only when the
syslog_data struct is initialized as a local variable).
Compliant Solution (POSIX)
In this compliant solution, the signal handlers are installed using
sigaction(), and so it is safe to use
raise() within the signal handler:
sigaction() and deprecates
sigaction() is not defined in the C Standard and is consequently not as portable a solution.
Invoking functions that are not asynchronous-safe from within a signal handler may result in privilege escalation and other attacks.
|Compass/ROSE||Can detect violations of the rule for single-file programs|
For an overview of software vulnerabilities resulting from improper signal handling, see Zalewski's paper [Zalewski 2001] on understanding, exploiting, and preventing signal-handling-related vulnerabilities. VU #834865 describes a vulnerability resulting from a violation of this rule.
Another notable case where using the
longjmp() function in a signal handler caused a serious vulnerability is wu-ftpd 2.4 [Greenman 1997]. The effective user ID is set to 0 in one signal handler. If a second signal interrupts the first, a call is made to
longjmp(), returning the program to the main thread but without lowering the user's privileges. These escalated privileges can be used for further exploitation.
|CERT C++ Secure Coding Standard||SIG30-CPP. Call only asynchronous-safe functions within signal handlers|
|ISO/IEC TS 17961||Calling functions in the C Standard Library other than |
|MITRE CWE||CWE-479, Unsafe function call from a signal handler|
|[C99 Rationale 2003]||Subclause 5.2.3, "Signals and Interrupts"|
Subclause 188.8.131.52, "The
|[Dowd 2006]||Chapter 13, "Synchronization and State"|
|[IEEE Std 1003.1:2013]||XSH, System Interfaces, |
XSH, System Interfaces,
|[ISO/IEC 9899:2011]||Subclause 184.108.40.206, "The |
|[Zalewski 2001]||"Delivering Signals for Fun and Profit"|