According to the C Standard, subclause 7.14.1.1 [ISO/IEC 9899:2011], returning from a SIGSEGV
SIGFPE
, SIGILL
, or SIGFPE
signal handler is undefined behavior:
...
SIGSEGV
...
or any other implementation-defined value corresponding to a computational exception
...
signal handler is undefined behavior 130. Furthermore, SIGFPE
may not be caught for a significant number of instructions after the floating-point instruction that creates it.
Noncompliant Code Example
In this noncompliant code example, if the given user input is 0
, the division operation sends 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:
Code Block | ||||
---|---|---|---|---|
| ||||
#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 = 0; 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 through by invoking abort()
or/ _Exit()
. In the case of SIGFPE
, the default handler calls abort()
, so no user-defined handler is actually needed. The handler shown is only for consistency.required.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> #include <stdlib.h> volatile sig_atomic_t denom; void sighandle(int s) { /* Recovery is impossible */ abort(); } int main(int argc, char *argv[]) { int result = 0; 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 SIGSEGV
SIGFPE
, SIGILL
, or SIGFPE
signals is rare. However, code that does rely on handling these signals will usually require a redesign might need to be redesigned to fix the this problem.SIGSEGV
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
[ISO/IEC 9899:2011] | Subclause 7.14.1.1, "The signal Function" |
...