AD2031: EnableControlStackChecking¶
Summary¶
| Property | Value |
|---|---|
| ID | AD2031 |
| Name | EnableControlStackChecking |
| Category | Security |
| Severity | Warning |
| Applies to | PE (Windows) - Native binaries |
Description¶
The /Gs compiler option controls the threshold for stack probes. When a function's local variables exceed the threshold, the compiler inserts calls to __chkstk to probe stack pages. This helps prevent stack overflow vulnerabilities by ensuring stack pages are committed before use.
How It Works¶
The rule examines the PDB file for /Gs compiler flags and checks for the presence of stack probing symbols. It also verifies that the security cookie (/GS) is enabled, which typically implies proper /Gs configuration.
Default Behavior¶
- Default threshold is 4KB (one page)
/Gs0probes every stack allocation/Gswith no value uses the default threshold- Large thresholds (e.g.,
/Gs65536) may skip important probes
Why This Matters¶
Stack probing is a critical defense against stack clash attacks, where attackers exploit large stack allocations to bypass guard pages and corrupt adjacent memory regions. Without proper probing, a single function call could compromise memory protection.
The Stack Clash Attack¶
Stack clash exploits how the OS manages stack memory:
Normal stack growth:
βββββββββββββββββββ
β Used Stack β β Stack pointer
βββββββββββββββββββ€
β Guard Page β β Access = crash (protection)
βββββββββββββββββββ€
β Unmapped/Heap β
βββββββββββββββββββ
Stack clash attack:
βββββββββββββββββββ
β Used Stack β
βββββββββββββββββββ€
β Guard Page β β SKIPPED!
βββββββββββββββββββ€
β Heap/Other β β Corrupted!
βββββββββββββββββββ
How the Attack Works¶
- Large allocation: Function allocates huge stack frame
- Skip guard page: Allocation jumps over guard page
- Write to stack: Actually writes to heap/other memory
- Corruption: Critical data structures modified
- Exploitation: Code execution or privilege escalation
Stack Probing Prevention¶
With proper /Gs, every page is touched:
// Large local array
char buffer[65536]; // 16 pages
// Without probing: Single SP adjustment
sub rsp, 65536 // May skip guard pages!
// With probing: Touch each page
call __chkstk // Probes page by page
// Hits guard page if stack exhausted
Threshold Configuration¶
| Setting | Behavior | Use Case |
|---|---|---|
/Gs (default) |
Probe for >4KB | Normal code |
/Gs0 |
Probe all allocations | Security-critical |
/Gs65536 |
Probe for >64KB | DANGEROUS! |
/Gs1 |
Nearly all probed | Maximum protection |
Real-World Impact¶
Stack clash vulnerabilities have affected:
| System | CVE | Impact |
|---|---|---|
| Linux/glibc | CVE-2017-1000364 | Local privilege escalation |
| Linux kernel | CVE-2017-1000365 | Container escape |
| Windows | Various | Process-to-kernel attacks |
| BSD | Multiple | Privilege escalation |
Performance Considerations¶
Stack probing overhead is minimal:
| Scenario | Overhead |
|---|---|
| Small functions (<4KB stack) | Zero (no probe needed) |
| Large stack allocations | Few cycles per page |
| Recursive algorithms | May accumulate |
| Overall application | <0.1% typically |
The probe is a simple memory touch per pageβextremely fast.
Why Guard Pages Aren't Enough¶
| Guard Page Limitation | Problem |
|---|---|
| Single page only | Large jumps skip it |
| Between stack/heap | Can be bypassed |
| No proactive checking | Relies on access patterns |
Stack probing ensures guard pages are actually encountered.
Stack probing prevents several attack vectors:
- Stack clash attacks: Prevent stack from colliding with heap or other memory regions
- Stack overflow exploits: Detect when stack grows beyond allocated space
- Guard page bypasses: Ensure guard pages are touched before overflow
Without proper stack probing, an attacker could: 1. Allocate a large stack frame that skips the guard page 2. Corrupt adjacent memory regions 3. Achieve arbitrary code execution
Resolution¶
Use Default Stack Checking¶
Aggressive Stack Checking¶
For security-critical code, probe all allocations:
Project Properties¶
- Open Project Properties
- Navigate to C/C++ β Code Generation
- Ensure "Security Check" is enabled (/GS)
- Set "Stack Probe Size" appropriately
CMake¶
When to Suppress¶
This rule can be suppressed in the following scenarios:
- Known stack usage: Functions with well-understood, bounded stack use
- Performance-critical hot paths: Where probe overhead is unacceptable
- Leaf functions: Small functions with minimal stack usage
Caveats¶
- Large
/Gsthresholds may not catch all stack issues - Stack probing adds some runtime overhead
- Works in conjunction with
/GS(buffer security check)
Related Rules¶
- AD2011: EnableStackProtection
- AD2012: DoNotModifyStackProtectionCookie
- AD3005: EnableStackClashProtection