signal-handler ยท diff
git:20261016.fb3b156 to git:20261017.a78401f
10 added, 0 removed. Audit A to A.
---
name: signal-handler
description: Classify signal handler evidence โ a signal(2) handler that calls a non-async-signal-safe libc function. Maps to CWE-479.
license: MIT
compatibility: opencode,claude code,DSH
metadata:
cwe: CWE-479
severity: HIGH
domain: security
---
## Signal Handler Analysis (CWE-479)
### Evidence Pattern
A signal-handler candidate has:
- **signal_handler_unsafe**: the non-async-signal-safe call (e.g. `malloc`, `printf`, `pthread_mutex_lock`) with category `signal_handler_unsafe`
- The event's `function` is the handler registered via `signal(SIGxxx, handler)`
- **call_path**: The registering function is reachable from an entry point
+ ### Hint Tokens (Verdict Basis)
+
+ | Token | Meaning | Your action |
+ |-------|---------|-------------|
+ | `async-unsafe@<fn>` | the handler calls this function, which is off the POSIX async-signal-safe list | a certain CWE-479 โ verify the call is inside the handler, then confirm |
+
+ `async-unsafe@` names the offending call; the defect is the
+ non-reentrancy itself, so no dataflow proof is needed beyond the call
+ being in the handler.
+
### Detection Logic
1. Find `signal(SIGxxx, handler)` registrations where `handler` is a named function (not `SIG_DFL`/`SIG_IGN`)
2. Find the handler's function definition
3. Emit `SIGNAL_HANDLER` for each DIRECT call to a known non-async-signal-safe libc function in its body
### Classification Rules
| Condition | Classification |
|-----------|---------------|
| A registered handler calls `malloc`/`free`/`printf`/`pthread_mutex_lock`/`syslog`/... | **confirmed** |
| The handler calls only async-signal-safe functions (`write`, `close`, `fork`, `_exit`, ...) | **false-positive** (the detector never emits it) |
The unsafe list is the POSIX async-signal-safe list inverted: a direct call to a
function absent from that list is a certain defect, so the pipeline auto-confirms
it. `read`/`write`/`open`/`close`/`socket`/`send`/`recv`/`connect`/`fcntl`/`fork`/
`exec*`/`_exit`/`abort` are async-signal-safe and are never reported.
### Common False Positives
- The detector only reports DIRECT calls in the handler body; it never flags a
helper function the handler calls (transitive cases are out of scope), and it
does not flag the async-signal-safe functions listed above.
### Fix Suggestions
- Do only async-signal-safe work in the handler: set a `volatile sig_atomic_t`
flag and return; let the main loop do the heavy lifting
- If logging is required, use `write(fd, ...)` to a pre-opened fd, not `printf`/`syslog`
- Never allocate or take a lock in a signal handler
### Severity Matrix
`status` and `severity` are independent: `status` = evidence verdict
(confirmed/dismissed), `severity` = impact (low/medium/high/critical).
`metadata.severity` is the type default, not a ceiling. The verdict is binary (confirmed/dismissed); dismissed โ `low`.
| Shape | Severity |
|-------|----------|
| Direct call to a non-async-signal-safe function in a registered handler | HIGH |