You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 14 Next »

A signal handler is allowed to call signal(), and if that fails, signal() returns SIG_ERR and sets errno to a positive value.  However, if the event that caused a signal was external (not as the result of the program calling abort() or raise()), the signal handler must only call signal() on the signal currently being handled, and if signal() fails, the value of errno is indeterminate.

This is a special case of SIG31-C. Do not access or modify shared objects in signal handlers.  The object designated by errno is of static storage duration and is not a volatile sig_atomic_t.  Therefore, performing any action that would require errno to be set would normally cause undefined behavior.  The C standard makes a special exception for errno in this case, saying the only thing that is allowed to go wrong is that errno takes on an indeterminate value.  This makes it possible to call signal() from within a signal handler without risking completely unrestricted undefined behavior, but the handler must not depend on the value of errno being meaningful.

Non-Compliant Code Example

If the request to register a signal handler can be honored, the signal() function returns the value of the signal handler for the most recent successful call to the signal() function for the specified signal. Otherwise, a value of
SIG_ERR is returned and a positive value is stored in errno.

#include <signal.h>
#include <stdlib.h>
#include <string.h>

typedef void (*pfv)(int);

void handler(int signum) {
  pfv old_handler = signal(signum, handler);
  if (old_handler == SIG_ERR) {
    perror("SIGINT handler"); /* undefined behavior */
    /* handle error condition */
  }
  strcpy(err_msg, "SIGINT encountered.");
}

int main(void) {
  pfv old_handler = signal(SIGINT, handler);
  if (old_handler == SIG_ERR) {
    perror("SIGINT handler");
    /* handle error condition */
  }

  /* main code loop */

  return 0;
}

The call to perror() also violates SIG30-C. Call only asynchronous-safe functions within signal handlers.

Compliant Solution

The compliant solution does not reference errno.

#include <signal.h>
#include <stdlib.h>
#include <string.h>

typedef void (*pfv)(int);

void handler(int signum) {
  pfv old_handler = signal(signum, handler);
  if (old_handler == SIG_ERR) {
    /* handle error condition */
  }
}

int main(void) {
  pfv old_handler = signal(SIGINT, handler);
  if (old_handler == SIG_ERR) {
    perror("SIGINT handler");
    /* handle error condition */
  }

  /* main code loop */

  return 0;
}

Risk Assessment

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR32-C

1 (low)

1 (unlikely)

3 (low)

P3

L3

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

References

[[ISO/IEC 9899-1999]] Section 7.14.1.1, "The signal function"


ERR31-C. Don't redefine errno      13. Error Handling with errno (ERR)       ERR33-C. Only examine the value of errno when it is indicated to be valid by a function's return value

  • No labels