CWE-831 is a function used as the handler for more than one signal. MITRE says this is sometimes intentional and safe. It becomes a problem when the function touches state outside its own locals.
It applies to any program that registers signal handlers, most often C code on Unix style systems.
How it happens
In many operating systems, while a handler runs for one signal, that same signal will not invoke the handler again until it finishes. A different signal sharing the same handler has no such protection. An attacker can send signal A, and while the handler runs, send signal B. The handler is interrupted mid way, and if it uses global variables, non-reentrant functions or has side effects, shared state may be corrupted.
// Vulnerable: one handler, two signals, shared global state
static char *buf;
void handler(int sig) {
free(buf);
buf = NULL;
log_exit(sig);
}
sigaction(SIGTERM, &sa, NULL); // same handler
sigaction(SIGINT, &sa, NULL); // for both
A second signal during the first run can lead to a double free.
What an attacker gains
MITRE says the most common result is corrupted product state, possibly a crash or exit. Depending on the state touched, the record also lists code execution, reading application data, gaining privileges and bypassing protections.
How to find it
The record lists no detection methods. Search for every registration call and see whether one function appears more than once. For each, check whether it uses anything shared.
How to fix it
The record gives no formal mitigations. Practical options:
- Use a separate, small handler per signal.
- Make handlers only set a
volatile sig_atomic_tflag, then act on it in the main flow. - When sharing is needed, mask the other signals while the handler runs by filling
sa_mask.
sigfillset(&sa.sa_mask); // block others during the handler
Quick check
Why is one signal safe from itself but not from another?
The system usually blocks the same signal while its handler runs. Other signals are not blocked unless you ask.