AD3003: EnableStackProtector¶
Summary¶
| Property | Value |
|---|---|
| ID | AD3003 |
| Name | EnableStackProtector |
| Category | Security |
| Severity | Error |
| Applies to | ELF (Linux/Unix) |
Description¶
Stack protector adds a 'canary' value between local variables and the return address on the stack. If a buffer overflow overwrites the canary, the program will detect this and abort before the corrupted return address is used.
Enable this protection by compiling with -fstack-protector-strong or -fstack-protector-all.
How It Works¶
The rule checks for the presence of stack canary symbols:
__stack_chk_fail__stack_chk_guard
These symbols indicate stack protector is enabled and linked.
Why This Matters¶
Stack protectors (canaries) are one of the most effective and widely-deployed exploit mitigations. They detect stack buffer overflows before the attacker can hijack control flow, converting potential code execution into a controlled crash.
How Stack Canaries Work¶
Stack Layout with Canary:
┌─────────────────┐ High address
│ Return Address │ ← Attacker target
├─────────────────┤
│ Saved RBP │
├─────────────────┤
│ CANARY VALUE │ ← Random value, checked on return
├─────────────────┤
│ Local buffer │ ← Overflow source
└─────────────────┘ Low address
Overflow must pass through canary to reach return address.
Canary mismatch = abort before return.
Protection Levels¶
| Flag | Protection | Overhead | Use Case |
|---|---|---|---|
-fstack-protector |
Arrays ≥ 8 bytes | Very low | Legacy |
-fstack-protector-strong |
Arrays, address-taken locals | Low | Recommended |
-fstack-protector-all |
Every function | Moderate | High security |
-fstack-protector-strong protects functions with:
- Arrays of any size
- Variables whose address is taken
- Local struct/unions with arrays
Real-World Effectiveness¶
Stack canaries have stopped countless attacks:
| Scenario | Without Canary | With Canary |
|---|---|---|
| strcpy overflow | Code execution | Crash |
| gets() abuse | Code execution | Crash |
| Off-by-one (typical) | Maybe exploitable | Usually crash |
| Format string (write) | Depends on target | Often crash |
Canary Types¶
Linux uses "terminator canaries":
Canary value includes: 0x00, 0x0a, 0x0d, 0xff
These bytes terminate:
- String copy (0x00)
- Line reads (0x0a, 0x0d)
Makes overflow with intact canary very hard.
Performance Considerations¶
| Protection Level | Typical Overhead |
|---|---|
-fstack-protector |
<1% |
-fstack-protector-strong |
1-2% |
-fstack-protector-all |
5-10% |
For most applications, -fstack-protector-strong is the best trade-off.
Bypass Techniques (and Defenses)¶
Canaries aren't perfect, but bypass is hard:
| Bypass | Mitigation |
|---|---|
| Information leak | Keep canary secret |
| Brute force (forking) | Random per-process |
| Non-linear overflow | Rare vulnerability type |
| Direct ret overwrite | Canary is in the way |
Distribution Defaults¶
| Distribution | Default Stack Protector |
|---|---|
| Ubuntu | -fstack-protector-strong |
| Fedora | -fstack-protector-strong |
| Debian | -fstack-protector-strong |
| Alpine | -fstack-protector-strong |
- Buffer overflow detection: Catches stack smashing at runtime
- Controlled abort: Crashes safely instead of executing attacker code
- Low overhead: Minimal performance impact with
-fstack-protector-strong - Standard protection: Enabled by default on most distributions
Resolution¶
GCC/Clang¶
# Recommended - protects most vulnerable functions
gcc -fstack-protector-strong source.c -o binary
# Maximum protection - all functions
gcc -fstack-protector-all source.c -o binary
# Basic protection - only functions with arrays
gcc -fstack-protector source.c -o binary
CMake¶
add_compile_options(-fstack-protector-strong)
# For specific target
target_compile_options(myapp PRIVATE -fstack-protector-strong)
Makefile¶
Autotools¶
When to Suppress¶
This rule may be suppressed for:
- Performance-critical code: After profiling shows significant impact
- Freestanding code: No libc (kernel, boot code)
- Minimal runtime: Embedded systems without stack protector support
Caveats¶
- Requires libc support (
__stack_chk_fail) -fstack-protector-allhas higher overhead- Some very old compilers may not support
-fstack-protector-strong
Stack Protector Variants¶
| Option | Coverage | Overhead |
|---|---|---|
-fstack-protector |
Functions with char arrays > 8 bytes |
Low |
-fstack-protector-strong |
Functions with arrays, address-taken variables | Medium |
-fstack-protector-all |
All functions | High |
-fstack-protector-explicit |
Only __attribute__((stack_protect)) functions |
Minimal |
How It Works (Detailed)¶
Stack Layout with Canary:
┌─────────────────┐
│ Return Address │ ← Target of overflow
├─────────────────┤
│ Saved Frame Ptr │
├─────────────────┤
│ Stack Canary │ ← Random value checked on return
├─────────────────┤
│ Local Variables │ ← Buffer overflow starts here
└─────────────────┘
On function return:
1. Compare canary to expected value
2. Mismatch → call __stack_chk_fail()
3. __stack_chk_fail() aborts process