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

Compare with Current View Page History

« Previous Version 36 Next »

According to the C Standard, subclause 7.14.1.1 [ISO/IEC 9899:2011], if a signal handler entered as a result of a computational exception (that is, with the value of its argument of SIGFPE , SIGILL, or SIGSEGV or any other implementation-defined value corresponding to such an exception) returns, the behavior is undefined.  See undefined behavior 130.

The POSIX standard [IEEE Std 1003.1:2013] adds SIGBUS to the list of computational exception signal handlers,

The behavior of a process is undefined after it ignores a SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal that was not generated by kill(), sigqueue(), or raise().

Do not return from SIGFPE , SIGILL, or SIGSEGV, or any other implementation-defined value corresponding to a computational exception such as SIGBUS on POSIX systems, regardless of how the signal was generated.

Noncompliant Code Example

In this noncompliant code example, the division operation has undefined behavior if denom equals  0 (see INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors),  and may result in a SIGFPE signal to the program:

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

volatile sig_atomic_t denom;

void sighandle(int s) {
  /* Fix the offending volatile */
  if (denom == 0) {
    denom = 1;
  }
}

int main(int argc, char *argv[]) {
  int result;
    
  if (argc < 2) {
    return 0;
  }
  denom = (sig_atomic_t) strtol(argv[1], NULL, 10);   
  signal(SIGFPE, (*sighandle));
  result = 100 / (int)denom;
  return 0;
}

This noncompliant code example will loop infinitely on input 0 when compiled with some implementations. It illustrates that even when a SIGFPE handler attempts to fix the error condition while obeying all other rules of signal handling, the program still does not behave as expected.

Compliant Solution

In the compliant solution, the only portably safe way to leave a SIGFPE, SIGILL, or SIGSEGV handler is by invoking abort() or _Exit(). In the case of SIGFPE, the default handler calls abort(), so no user-defined handler is required.

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

void sighandle(int s) {
  /* Recovery is impossible */
  abort();
}

int main(int argc, char *argv[]) {
  int result;
  int denom;

  if (argc < 2) {
    return 0;
  }
  denom = (sig_atomic_t) strtol(argv[1], NULL, 10);   
  signal(SIGFPE, (*sighandle));
  result = 100 / (int)denom;
  return 0;
}

Implementation Details

Some implementations define useful behavior for programs that return from one or more of these signal handlers. For example, Solaris provides the sigfpe() function specifically to set a SIGFPE handler that a program may safely return from. Oracle also provides platform-specific computational exceptions for the SIGTRAP, SIGBUS, and SIGEMT signals. Finally, GNU libsigsegv takes advantage of the ability to return from a SIGSEGV handler to implement page-level memory management in user mode.

Risk Assessment

Code that attempts to handle SIGFPE , SIGILL, or SIGSEGV signals is rare. However, code that does rely on handling these signals might need to be redesigned to fix this problem.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SIG35-C

Low

Unlikely

High

P1

L3

Related Vulnerabilities

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

Bibliography

[IEEE Std 1003.1:2013]

2.4.1 Signal Generation and Delivery

[ISO/IEC 9899:2011]Subclause 7.14.1.1, "The signal Function"

 


  • No labels