Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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

The following code example illustrates shows this behavior:

Code Block

#include <stdio.h>
#include <signal.h>

volatile sig_atomic_t e_flag = 0;

void handler(int signum) {
  e_flag = 1;
}

int main(void) {
  if (signal(SIGINT, handler); == SIG_ERR) {
    /* Handle error */
  }
  while (!e_flag) {}
  puts("Escaped from first while ()");
  e_flag = 0;
  while (!e_flag) {}
  puts("Escaped from second while ()");
  return 0;
}

Many Unix UNIX (and UnixUNIX-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 GCC 3.4.4 and executed under Red Hat Linux, the SIGINT is captured both times by handler.:

Code Block

% ./SIG01-Atest
^C
Escaped from first while ()
^C
Escaped from second while ()
%

When a signal handler is installed with the signal() function in Windows and some Unix 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.:

Code Block

> SIG01-Atest.exe
^C
Escaped from first while ()
^C
>

...

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 potentially hostile sources outside malicious actors external to the process. Consequently, vulnerabilities may exist in cases where the if the signal-handler-persistence behavior is inconsistent with the developer's expectations, for example, such as when the developer expects the signal handler to persist when but it does not.

...

Noncompliant Code Example

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

Code Block
bgColor#ffcccc
langc

void handler(int signum) {
  /* Handle Signalsignal */
}

...

Noncompliant Code Example

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

Code Block
bgColor#ffcccc
langc

void handler(int signum) {
  if (signal(signum, handler); == SIG_ERR) {
    /* Handle error */
  }
  /* Handle Signalsignal */
}

Wiki Markup
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 (see \[[SIG34-C. Do not call signal() from within interruptible signal handlers]\]).

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 SIG34-C. Do not call signal() from within interruptible signal handlers.)

A secure solution must A secure solution would prevent the environment from resetting the signal in the first place, and thereby 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 manner to the C99 C signal() function , but also allows signal-handler persistence to be controlled via the SA_RESETHAND flag. (Leaving the flag clear makes the handler persistent.)

Code Block
bgColor#ccccff
langc
/* 
 
/* Equivalent to signal(SIGUSR1, handler) but makemakes
 * signal persistent. 
 */
struct sigaction act;
act.sa_handler = handler;
act.sa_flags = 0;
if (sigemptyset(&act.sa_mask) != 0) {
  /* Handle Errorerror */
}
if (sigaction(SIGUSR1, &act, NULL) != 0) {
  /* Handle Errorerror */
}

POSIX recommends sigaction() and deprecates signal(). Unfortunately, sigaction() is not defined in C99 and in the C Standard 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 instead.

...

Noncompliant Code Example (

...

UNIX)

This non-compliant noncompliant code example fails to reset the signal handler to its default behavior on those Unix systems where handlers are persistent by default.:

Code Block
bgColor#ffcccc
langc

void handler(int signum) {
  /* Handle Signalsignal */
}

Compliant Solution (

...

UNIX and Windows)

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

Code Block
bgColor#ccccff
langc

void handler(int signum) {
#ifndef WINDOWS
  if (signal(signum, SIG_DFL); == SIG_ERR) {
    /* Handler error */
  }
#endif
  /* Handle Signalsignal */
}

With the Compliant Solution compliant solution for UnixUNIX, there is no race condition occurs that can be exploited by an attacker in sending a second signal. And that This is because a second signal sent to the handler, before the latter calls signal(signum, SIG_DFL), will merely only cause the handler to restart , and call signal() anyway.

Wiki MarkupThis solution is an exception to \[[SIG34-C. Do not call signal() from within interruptible signal handlers]\].

Compliant Solution (POSIX)

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

Code Block
bgColor#ccccff
langc
/* 
/ * Equivalent to signal( SIGUSR1, handler) but makes
 make* signal non-persistent nonpersistent.
 */
struct sigaction act;
act.sa_handler = handler;
act.sa_flags = SA_RESETHAND;
if (sigemptyset(&act.sa_mask) != 0) {
  /* Handle Errorerror */
}
if (sigaction(SIGUSR1, &act, NULL) != 0) {
  /* Handle Errorerror */
}

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-

A

1 (low)

1 (unlikely)

3 (low)

P3

L3

C

Low

Unlikely

Low

P3

L3

Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
BADFUNC.SIGNALUse of signal
Compass/ROSE



Could detect possible violations by flagging any signal handler that calls signal() to (re)assert itself as the handler for its signal

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5020
LDRA tool suite
Include Page
LDRA_V
LDRA_V
97 DPartially implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V
CERT_C-SIG01-a
The signal handling facilities of <signal.h> shall not be used
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

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.

References

Wiki Markup
\[[ISO/IEC 9899-1999TR2|AA. C References#ISO/IEC 9899-1999]\] Section 7.14.1.1, "The {{signal}} function"

Related Guidelines


...

Image Added Image Added Image AddedSIG00-A. Mask signals handled by non-interruptible signal handlers      11. Signals (SIG)       SIG02-A. Avoid using signals to implement normal functionality