VNX-831 – Signal Handler for Multiple Signals

Overview

This rule flags C code where a single handler function is registered for multiple signals (e.g., both SIGINT and SIGTERM, or both SIGUSR1 and SIGUSR2). If signals arrive simultaneously or one signal interrupts handling of another, the shared handler function executes re-entrantly. If the handler accesses shared state (a flag, counter, or data structure), race conditions occur. This maps to CWE-831: Signal Handler Function Associated with Multiple Signals.

Severity: Low | CWE: CWE-831

Why This Matters

When the same signal handler is registered for multiple signals, it’s easy to assume incorrectly that the handler body knows which signal triggered it, especially when the sig parameter is ignored. If signal A arrives while the handler is processing signal B, the shared state the handler updates may be corrupted. Separate handlers that set distinct flags are clearer, safer, and easier to reason about.

What Gets Flagged

// FLAGGED: same handler for SIGINT and SIGTERM
void signal_handler(int sig) {
    cleanup();
    exit(0);
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// FLAGGED: same handler for SIGUSR1 and SIGUSR2
void usr_handler(int sig) {
    handle_user_signal();  // doesn't distinguish which signal
}
signal(SIGUSR1, usr_handler);
signal(SIGUSR2, usr_handler);

Remediation

// SAFE: separate handlers for each signal
static volatile sig_atomic_t got_sigint = 0;
static volatile sig_atomic_t got_sigterm = 0;

void sigint_handler(int sig) {
    (void)sig;
    got_sigint = 1;
}

void sigterm_handler(int sig) {
    (void)sig;
    got_sigterm = 1;
}

int main(void) {
    signal(SIGINT, sigint_handler);
    signal(SIGTERM, sigterm_handler);
    
    while (1) {
        if (got_sigint) {
            printf("Interrupted by user\n");
            break;
        }
        if (got_sigterm) {
            printf("Termination requested\n");
            graceful_shutdown();
            break;
        }
        do_work();
    }
    return 0;
}
// SAFE: if sharing is necessary, use sigaction with SA_SIGINFO
// to get the full siginfo_t and distinguish signals properly
void shared_handler(int sig, siginfo_t *info, void *context) {
    if (sig == SIGUSR1) {
        got_sigusr1 = 1;
    } else if (sig == SIGUSR2) {
        got_sigusr2 = 1;
    }
}

struct sigaction sa = {
    .sa_sigaction = shared_handler,
    .sa_flags = SA_SIGINFO
};
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);

References