Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added sigaction(2) examples, identified unfixable race cond. on Windows

...

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

Non-Persistent Handlers

Errors and potential vulnerabilities exist when the actual signal handler persistence behavior is inconsistent with the developer's expectations, for example, the developer expects the signal handler to persist but it does not.

...

Code Block
bgColor#ffcccc
void handler(int signum) {
  /* handling code */
}

Non-Compliant

...

Code Example (Windows)

A C99-compliant solution to persist the handler on a Windows system is to rebind the signal to the handler in the first line of the handler itselfcommon solution to make persistent signal handlers is to call signal() inside the handler itself, thus 'unresetting' the reset signal.

Code Block
bgColor#ccccff#ffcccc
void handler(int signum) {
#ifdef WINDOWS
  signal(signum, handler);
#endif
  /* handling code */
}

Unfortunately this solution still permits a race window. starting when the OS first resets the signal, and ending when the handler calls signal(). During that time, a second signal sent to the program will still trigger the default signal behavior, thereby destroying persistence.

A secure solution would prevent the OS from resetting the signal in the first place, and thereby guarantee persistence. Unfortunately, Windows does not provide a secure solution to this problem.

Compliant Solution (POSIX)

POSIX defines the sigaction(2) function, which assigns handlers to signals like signal(2), but also allows one to explicitly set persistence. One can thus use sigaction(2) and sidestep the race window on non-persistent OS's.

Code Block
bgColor#ccccff

  /* Equivalent to signal( SIGUSR1, handler); */
  struct sigaction act;
  act.sa_handler = &handler;
  act.sa_flags = 0; /* makes signal persistent by default */
  if (sigfillset( &act.sa_mask) != 0) {
    /* handle error */
  }
  if (sigaction(SIGUSR1, &act, NULL) != 0) {
    /* handle error */
  }

sigaction(2) is not C99-compliant.

Non-Persistent Handlers

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

...

Windows automatically resets handlers to default.

There is no race condition that can be utilizied by an attacker in sending a second signal here, because a second signal sent to the handler before it calls signal() will merely cause it to restart, and call signal() anyway.

Compliant Solution (POSIX)

POSIX defines the sigaction(2) function, which assigns handlers to signals like signal(2), but also allows one to explicitly set persistence. One can thus use sigaction(2) and sidestep the race window on non-persistent OS's.

Code Block
bgColor#ccccff

  /* Equivalent to signal( SIGUSR1, handler); */
  struct sigaction act;
  act.sa_handler = &handler;
  act.sa_flags = SA_RESETHAND; /* makes signal non-persistent */
  if (sigfillset( &act.sa_mask) != 0) {
    /* handle error */
  }
  if (sigaction(SIGUSR1, &act, NULL) != 0) {
    /* handle error */
  }

sigaction(2) is not C99-compliant.

Risk Assessment

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

...