Versions Compared

Key

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

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.

Signals are handled by a process 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 (*SighandlerTypesighandler_t)(int signum);
extern SighandlerTypesighandler_t signal(
  int signum, SighandlerType
  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 non-interruptible noninterruptible and need not be asynchronousasync-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.

...

Noncompliant Code Example

This non-compliant noncompliant code example registers a single signal handler to process both SIGUSR1 and SIGUSR2. The variable sig2 should be set to one 1 if one or more SIGUSR1 signals are followed by SIGUSR2, essentially implementing a finite state machine within the signal handler.

Code Block
bgColor#FFcccc
langc

#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) {
    /* doDo 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.

Compliant Solution (POSIX)

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
bgColor#ccccff
langc

#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) {
    /* handleHandle error */
  }
  if (sigaddset(&act.sa_mask, SIGUSR1)) {
    /* handleHandle error */
  }
  if (sigaddset(&act.sa_mask, SIGUSR2)) {
    /* handleHandle error */
  }

  if (sigaction(SIGUSR1, &act, NULL) != 0) {
    /* handleHandle error */
  }
  if (sigaction(SIGUSR2, &act, NULL) != 0) {
    /* handleHandle error */
  }

  while (sig2 == 0) {
    /* doDo 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 non-interruptible noninterruptible signal handler can result in a variety of vulnerabilities \ [[Zalewski 01|AA. C References#Zalewski 01]\]Zalewski 2001].

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

SIG00-

A

C

high

High

likely

Likely

high

High

P9

L2

Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
BADFUNC.SIGNALUse of signal
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5019
LDRA tool suite
Include Page
LDRA_V
LDRA_V
44 SEnhanced enforcement
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V
CERT_C-SIG00-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
\[[Dowd 06 | AA. C References#Dowd 06]\] Chapter 13, "Synchronization and State" (Signal Interruption and Repetition)
\[[ISO/IEC 03|AA. C References#ISO/IEC 03]\] Section 5.2.3, "Signals and interrupts"
\[[Open Group 04|AA. C References#Open Group 04]\] [longjmp|http://www.opengroup.org/onlinepubs/000095399/functions/longjmp.html]
\[[OpenBSD|AA. C References#OpenBSD]\] [{{signal()}} Man Page|http://www.openbsd.org/cgi-bin/man.cgi?query=signal]
\[[Zalewski 01|AA. C References#Zalewski 01]\]

Related Guidelines

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"


...

Image Added Image Added Image Added11. Signals (SIG)      11. Signals (SIG)       SIG01-A. Understand implementation-specific details regarding signal handler persistence