Versions Compared

Key

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

Call only asynchronous-safe functions within signal handlers. For strictly conforming programs, only the C standard library functions abort(), _Exit(), and signal() can be called from within a signal handler. 

Section 7Subclause 7.14.1.1, paragraph 5, of the C Standard [ISO/IEC 9899:2011], states that if the signal occurs other than as the result of calling the abort() or raise() function, the behavior is undefined if

...

Code Block
bgColor#FFcccc
langc
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

enum { MAXLINE = 1024 };
char *info = NULL;

void log_message(void) {
  fprintf(stderr, info); /* violation */
}

void handler(int signum) {
  log_message();
  free(info); /* violation */
  info = NULL;
}

int main(void) {
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }
  info = (char *)malloc(MAXLINE);
  if (info == NULL) {
    /* Handle Error */
  }

  while (1) {
    /* Main loop program code. */

    log_message();

    /* More program code. */
  }
  return 0;
}

Compliant Solution

...

Code Block
bgColor#ccccff
langc
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

enum { MAXLINE = 1024 };
volatile sig_atomic_t eflag = 0;
char *info = NULL;

void log_message(void) {
  fprintf(stderr, info);
}

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

int main(void) {
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }
  info = (char *)malloc(MAXLINE);
  if (info == NULL) {
    /* Handle error */
  }

  while (!eflag) {
    /* Main loop program code */

    log_message();

    /* More program code */
  }

  log_message();
  free(info);
  info = NULL;

  return 0;
}

...

Code Block
bgColor#ffcccc
langc
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>

enum { MAXLINE = 1024 };
static jmp_buf env;

void handler(int signum) {
  longjmp(env, 1); /* violation */
}

void log_message(char *info1, char *info2) {
  static char *buf = NULL;
  static size_t bufsize;
  char buf0[MAXLINE];

  if (buf == NULL) {
    buf = buf0;
    bufsize = sizeof(buf0);
  }

  /*
   *  Try to fit a message into buf, else reallocate
   *  it on the heap and then log the message.
   */

  /*** VULNERABILITY IF SIGINT RAISED HERE ***/

  if (buf == buf0) {
    buf = NULL;
  }
}

int main(void) {
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }
  char *info1;
  char *info2;

  /* info1 and info2 are set by user input here. */

  if (setjmp(env) == 0) {
    while (1) {
      /* Main loop program code. */
      log_message(info1, info2);
      /* More program code */
    }
  }
  else {
    log_message(info1, info2);
  }

  return 0;
}

...

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

enum { MAXLINE = 1024 };
volatile sig_atomic_t eflag = 0;

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

void log_message(char *info1, char *info2) {
  static char *buf = NULL;
  static size_t bufsize;
  char buf0[MAXLINE];

  if (buf == NULL) {
    buf = buf0;
    bufsize = sizeof(buf0);
  }

  /*
   *  Try to fit a message into buf, else re-allocate
   *  it on the heap and then log the message.
   */
  if (buf == buf0) {
    buf = NULL;
  }
}

int main(void) {
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }
  char *info1;
  char *info2;

  /* info1 and info2 are set by user input here. */

  while (!eflag) {
    /* Main loop program code. */
    log_message(info1, info2);
    /* More program code. */
  }

  log_message(info1, info2);

  return 0;
}

...

Code Block
bgColor#ffcccc
langc
#include <signal.h>
#include <stdlib.h>
 
void term_handler(int signum) {
  /* SIGTERM handling specific. */
}
 
void int_handler(int signum) {
  /* SIGINT handling specific. */
  if (raise(SIGTERM) != 0) {  /* violation */
    /* Handle error */
  }
}
 
int main(void) {
  if (signal(SIGTERM, term_handler) == SIG_ERR) {
    /* Handle error */
  }
  if (signal(SIGINT, int_handler) == SIG_ERR) {
    /* Handle error */
  }
 
  /* Program code */
  if (raise(SIGINT) != 0) {
    /* Handle error */
  }
  /* More code */
 
  return EXIT_SUCCESS;
}

...

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

void log_msg(int signum) {
  /* Log error message in some asynchronous-safe manner. */
}

void handler(int signum) {
  /* Do some handling specific to SIGINT. */
  log_msg(SIGUSR1);
}

int main(void) {
  if (signal(SIGUSR1, log_msg) == SIG_ERR) {
    /* Handle error */
  }
  if (signal(SIGINT, handler) == SIG_ERR) {
    /* Handle error */
  }

  /* program code */
  if (raise(SIGINT) != 0) {
    /* Handle error */
  }
  /* More code */

  return 0;
}

...

Code Block
bgColor#ffcccc
langc
#include <signal.h>

void log_msg(int signum) {
  /* Log error message. */
}

void handler(int signum) {
  /* Do some handling specific to SIGINT. */
  if (raise(SIGUSR1) != 0) { /* violation */
    /* Handle error */
  }
}

int main(void) {

  signal(SIGUSR1, log_msg);
  signal(SIGINT, handler);
   
  /* program code */
  if (raise(SIGINT) != 0) {
    /* Handle error */
  }
  /* More code */

  return 0;
}

...

The following table from the the Open Group Base Specifications [Open Group 2004] defines a set of functions that are asynchronous-signal-safe. Applications may invoke these functions, without restriction, from a signal handler.

...

Note that although raise() is on the list of asynchronous-safe functions, it should not be called within a signal handler if the signal occurs as a result of the abort() or raise() function.

Section Subclause 7.14.1.1, paragraph 4, of the C Standard [ISO/IEC 9899:2011] states:

...

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

void log_msg(int signum) {
  /* Log error message in some asynchronous-safe manner. */
}

void handler(int signum) {
  /* Do some handling specific to SIGINT. */
  if (raise(SIGUSR1) != 0) {
    /* Handle error */
  }
}

int main(void) {
  struct sigaction act;
  act.sa_flags = 0;
  if (sigemptyset(&act.sa_mask) != 0) {
    /* Handle error */
  }
  act.sa_handler = log_msg;
  if (sigaction(SIGUSR1, &act, NULL) != 0) {
    /* Handle error */
  }
  act.sa_handler = handler;
  if (sigaction(SIGINT, &act, NULL) != 0) {
    /* Handle error */
  }

  /* program code */
  if (raise(SIGINT) != 0) {
    /* Handle error */
  }
  /* More code */

  return 0;
}

...

[Dowd 2006]Chapter 13, "Synchronization and State"
[ISO/IEC 2003]Section 5.2.3, "Signals and Interrupts"
Section 7.14.1.1, "The signal Function"
[ISO/IEC 9899:2011]Section 7.14.1.1, "Signal Handling <signal.h>The signal function"
[Open Group 2004]longjmp()
[OpenBSD]signal() Man Page
[Zalewski 2001]"Delivering Signals for Fun and Profit"

...