Versions Compared

Key

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

Only call asynchronous-safe functions within signal handlers.

...

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 could cause problems if the signal handler invokes a library function that was being executed at the time of the signal. Since library functions are not guaranteed to be reentrant, they should not be called from a signal handler that returns.

Implementation Details

The OpenBSD signal() man page identifies functions that are either reentrant or not interruptible by signals and are asynchronous-signal safe. Applications may therefore invoke them, without restriction, from signal-catching functions.

Non-Compliant Code Example

This In this non-compliant code example, main() invokes the malloc() function to allocated space to copy a string.
The string literal is copied into the allocated memory, which is then printed and the memory freed. The program also registers the signal handler int_handler()} to handle the terminal interrupt signal {{SIGINT.

Unfortunately, the free() function is not asynchronous-safe and its invocation from within a signal handler is a violation of this rule's space for a string, copies over a string, and then cleans up the memory. The error lies with the call to the free() function inside the signal handler. If an interrupt signal is received during or after the free() call in main(), the heap will may be corrupted.

Code Block
bgColor#FFcccc
#include <signal.h>

char *foo;

void int_handler() {
  free(foo);
  _Exit(0);
}

int main(void) {
  foo = malloc(15(sizeof("Hello World."));
  if (foo == NULL) {
    /* handle error condition */
  }
  signal(SIGINT, int_handler);
  strcpy(foo, "Hello World.");
  puts(foo);
  free(foo);
  return 0;
}

Note: The _Exit() function causes immediate program termination, and is async-safe, whereas exit() may call cleanup routines first, and is therefore not async-safe.

Compliant Solution

Signal handlers should be as minimal as possible, only unconditionally setting a flag where appropriate, and returning. They may also call the _Exit() function.

Code Block
bgColor#ccccff
#include <signal.h>

char *foo;

void int_handler() {
  _Exit(0);
}

int main(void) {
  foo = malloc(15);
  if(foo == NULL) {
    /* handle error condition */
  }
  signal(SIGINT, int_handler);
  strcpy(foo, "Hello World.");
  puts(foo);
  free(foo);
  return 0;
}

Risk Assessment

Wiki Markup
Depending on the code, this could lead to any number of attacks, many of which could give root access. For an overview of some software vulnerabilities, see Zalewski's paper on understanding, exploiting and preventing signal-handling related vulnerabilities \[[Zalewski 01|AA. C References#Zalewski 01]\]. [VU #834865|http://www.kb.cert.org/vuls/id/834865] describes a vulnerability resulting from a violation of this rule.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SIG30-C

3 (high)

3 (likely)

1 (high)

P9

L2

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

References

Wiki Markup
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 13, Synchronization and State
\[[ISO/IEC 03|AA. C References#ISO/IEC 03]\] "Signals and Interrupts"
\[[Open Group 04|AA. C References#Open Group 04]\] [longjmp|http://www.opengroup.org/onlinepubs/000095399/functions/longjmp.html]
\[OpenBSD\] [{{signal()}} Man Page|http://www.openbsd.org/cgi-bin/man.cgi?query=signal]
\[[Zalewski 01|AA. C References#Zalewski 01]\]