CERT
Skip to end of metadata
Go to start of metadata

This guideline has not been reviewed recently and may be outdated. Please review it and comment to reflect any newly available information.

The signal() function has implementation-defined behavior and behaves differently on Windows, for example, than it does on many UNIX systems.

The following code example shows this behavior:

Many UNIX (and UNIX-like) systems automatically reinstall signal handlers upon handler execution, meaning that the signal handler defined by the user is left in place until it is explicitly removed. For example, when this code is compiled with GCC 3.4.4 and executed under Red Hat Linux, SIGINT is captured both times by handler.

When a signal handler is installed with the signal() function in Windows and some UNIX systems, the default action is restored for that signal after the signal is triggered. This means that signal handlers are not automatically reinstalled. For example, when this code is compiled with Microsoft Visual Studio 2005 version 8.0, only the first SIGINT is captured by handler.

The second SIGINT executes the default action, which is to terminate program execution.

Different actions must be taken depending on whether or not the application requires signal handlers to be persistent.

Persistent Handlers

Asynchronous signals may originate from malicious actors external to the process. Consequently, vulnerabilities may exist in cases where the signal handler persistence behavior is inconsistent with the developer's expectations, such as when the developer expects the signal handler to persist but it does not.

Noncompliant Code Example

This noncompliant code example fails to persist the signal handler on Windows platforms and on those UNIX systems where handlers are not persistent by default.

Noncompliant Code Example

A common approach to create persistent signal handlers is to call signal() from within the handler itself, consequently unresetting the reset signal.

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, defeating the persistent behavior (see VOID SIG34-CPP. Do not call signal() from within interruptible signal handlers).

A secure solution must prevent the environment from resetting the signal in the first place, guaranteeing persistence. Unfortunately, Windows does not provide a secure solution to this problem.

Compliant Solution (POSIX)

The POSIX sigaction() function assigns handlers to signals in a manner similar to the C99 signal() function but also allows signal handler persistence to be controlled via the SA_RESETHAND flag. (Leaving the flag clear makes the handler persistent.)

POSIX recommends sigaction() and deprecates signal(). Unfortunately, sigaction() is not defined in C99 and is consequently not as portable a solution.

Nonpersistent Handlers

Errors may also occur when the developer expects the default action to be restored for a signal but instead the signal handler persists.

Noncompliant Code Example (UNIX)

This noncompliant code example fails to reset the signal handler to its default behavior on those UNIX systems where handlers are persistent by default.

Compliant Solution (UNIX and Windows)

A C99-compliant solution to reset the handler on a UNIX system is to rebind the signal to the default handler in the first line of the handler itself. Windows, however, automatically resets handlers to default.

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 only cause the handler to restart and call signal() anyway.

This solution is an exception to VOID SIG34-CPP. Do not call signal() from within interruptible signal handlers.

Compliant Solution (POSIX)

The POSIX sigaction() function assigns handlers to signals in a manner similar to the C99 signal() function but also allows signal handler persistence to be controlled via the SA_RESETHAND flag. (Setting the flag makes the handler nonpersistent.)

Risk Assessment

Failure to understand implementation-specific details regarding signal handler persistence can lead to unexpected behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

SIG01-CPP

low

unlikely

low

P3

L3

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE  could detect possible violations by flagging any signal handler that calls signal() to (re)assert itself as the handler for its signal.
 LDRA tool suite9.5.8

 

97 D

Partially implemented

Parasoft C/C++test9.5MISRA2012-RULE-21_5_b 

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

This rule appears in the C Secure Coding Standard as SIG01-C. Understand implementation-specific details regarding signal handler persistence.

Bibliography

[ISO/IEC 9899-1999TR2] Section 7.14.1.1, "The signal function"