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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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 | ||||
---|---|---|---|---|
| ||||
#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" |
...