Zorya includes overlay path analysis to detect vulnerabilities by exploring untaken paths using a copy-on-write overlay mechanism. This technique allows full concolic execution on unexplored paths without modifying the base execution state.
Note: The same vulnerability checks (NULL deref, div/0, dangling pointers) run in both concrete and overlay execution. See Vulnerability-Detection.md for details on detection mechanisms.
For every conditional branch involving symbolic variables, Zorya:
- Takes the concrete path (normal execution continues)
- Creates an overlay state for the untaken path
- Executes up to N instructions in overlay mode (default: 15)
- Detects vulnerability patterns:
LOAD [address]where address could be 0 → NULL_DEREF_LOADSTORE [address], valuewhere address could be 0 → NULL_DEREF_STOREDIV/REMwhere divisor could be 0 → DIV_BY_ZERO- Memory access to freed stack frame → DANGLING_POINTER
- Reports vulnerability with SMT constraints to trigger it
- Discards overlay and continues normal execution
The overlay uses copy-on-write semantics for efficiency:
- CPU registers: Modified registers are stored in overlay, unmodified ones read from base state
- Memory: Modified regions are cloned on first write, unmodified regions read from base
- Stack frames: Overlay frames are tracked and cleaned up after overlay ends
- No state pollution: Base execution state remains unchanged
- Max depth: 15 instructions (configurable in
overlay_path_analysis.rs) - Automatic: Enabled for all conditional branches with symbolic variables
- Overhead: Minimal - overlay is discarded after analysis
Overlay path analysis is automatically enabled for:
- Go GC binaries - Detects implicit nil dereferences
- C/C++ binaries - Detects segfaults and undefined behavior
- TinyGo binaries - Works alongside explicit panic detection
Implementation: src/state/overlay_path_analysis.rs
The overlay state provides:
- Copy-on-write CPU registers
- Copy-on-write memory regions
- Full concolic execution in isolated environment
- Zero impact on base execution state
Stack frame cleanup: When overlay execution ends, any overlay stack frames (from CALL/RETURN in overlay) are removed from tracking to prevent false positives in dangling pointer detection:
// Before overlay
let saved_call_stack_depth = executor.state.call_stack.len();
let saved_freed_frames_count = executor.state.freed_stack_frames.len();
// After overlay
executor.state.call_stack.truncate(saved_call_stack_depth);
executor.state.freed_stack_frames.truncate(saved_freed_frames_count);This ensures only frames from concrete execution are used for vulnerability detection.