Skip to content

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

CFLAGS += -fstack-protector-strong

Autotools

./configure CFLAGS="-fstack-protector-strong"

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-all has 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

References