Accessing or modifying shared objects in signal handlers can lead to race conditions, opening up security holes.
According to the "Signals and Interrupts" section of the C99 Rationale:
The C89 Committee concluded that about the only thing a strictly conforming program can do in a signal handler is to assign a value to a
volatile static
variable which can be written uninterruptedly and promptly return.
Non-Compliant Code Example
err_msg
is updated to reflect the SIGINT
signal that was encountered. Issues will occur if a SIGINT
is generated prior to the malloc
of err_msg
finishing.
#include <signal.h> #include <stdlib.h> #include <string.h> char *err_msg; void handler() { strcpy(err_msg, "SIGINT encountered."); } int main() { signal(SIGINT, handler); err_msg = malloc(24); strcpy(err_msg, "No errors yet."); /* main code loop */ return 0; }
Compliant Solution
Signal handlers should only unconditionally set and flag, and then return.
#include <signal.h> #include <stdlib.h> #include <string.h> char *err_msg; volatile sig_atomic_t e_flag = 0; void handler() { e_flag = 1; } int main() { signal(SIGINT, handler); err_msg = malloc(24); strcpy(err_msg, "No errors yet."); /* main code loop */ if(e_flag) strcpy(err_msg, "SIGINT received."); return 0; }
Risk Assessment
Depending on the code, this could lead to any number of attacks, many of which could give root access. For an overview of some software vulnerabilities, see [[Zalewski 06]].
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
SIG31-C |
3 (high) |
3 (likely) |
1 (high) |
P9 |
L2 |
References
[[Dowd 06]] Chapter 13, Synchronization and State
[[ISO/IEC 03]] "Signals and Interrupts"
[[Open Group 04]] longjmp
[OpenBSD] signal()
Man Page
[Zalewski] http://lcamtuf.coredump.cx/signals.txt