Skip to content

AD2014: DoNotDisableStackProtectionForFunctions

Summary

Property Value
ID AD2014
Name DoNotDisableStackProtectionForFunctions
Category Security
Severity Warning
Applies to PE (Windows) with PDB files

Description

Application code should not disable stack protection for specific functions using #pragma strict_gs_check(off), #pragma runtime_checks, or __declspec(safebuffers). These mechanisms bypass the security provided by /GS.

How It Works

The rule examines:

  1. PDB compilation flags for disabled security checks
  2. Command lines for /GS- flags
  3. Compiland information indicating security check overrides

Why This Matters

Disabling stack protection for specific functions creates precisely-targeted vulnerabilities that attackers actively seek out. A single unprotected function in an otherwise-hardened application becomes the focus of exploitation attempts.

The Targeted Attack Surface

When /GS is selectively disabled:

#pragma strict_gs_check(off)
void parse_network_data(char *input, size_t len) {
    char buffer[1024];
    // ... buffer overflow here becomes easily exploitable
}
#pragma strict_gs_check(on)

An attacker who discovers this function will: 1. Focus all exploitation efforts on this specific entry point 2. Exploit it trivially since there's no cookie check 3. Bypass the application's other security measures

Why Developers Disable Protection

Common (usually misguided) reasons:

Reason Given Reality
"Performance" /GS overhead is <1%, usually unmeasurable
"Compiler warnings" Fix the code, don't disable protection
"Legacy compatibility" Refactor incrementally
"Won't be exploited" Attackers specifically look for these

Attack Economics

Selective disabling is worse than global disabling:

Configuration Attacker Strategy
/GS globally enabled Must bypass cookies everywhere
/GS globally disabled Many attack vectors, but obvious in audits
Selective /GS- Target specific functions, hidden from quick audits

Detection Challenges

Selective disabling is hard to detect in code review:

  • #pragma statements may be in distant header files
  • __declspec(safebuffers) doesn't obviously mean "insecure"
  • Per-function compiler flags require build system analysis

Real-World Examples

Security researchers have found critical vulnerabilities in functions with disabled stack protection:

  1. Network parsers: Developers disabled /GS for "performance" in hot paths
  2. Cryptographic code: Misunderstanding led to disabling in sensitive functions
  3. Legacy wrappers: Old code grandfathered in without protection

The Safebuffers Problem

__declspec(safebuffers) was intended for functions the developer "knows" are safe:

__declspec(safebuffers)
void my_safe_function() {
    // "I know what I'm doing"
}

In practice: - Developers overestimate their code's safety - Code changes over time - Future maintainers may not understand the implications

Defense in Depth Failure

Stack protection is one layer of defense. Removing it for any function: - Eliminates that protection layer for that attack surface - May cascade if the function is called by other vulnerable code - Reduces overall security posture

Resolution

Remove #pragma strict_gs_check(off)

// Bad
#pragma strict_gs_check(off)
void vulnerable_function() {
    char buffer[100];
    // ...
}
#pragma strict_gs_check(on)

// Good - remove the pragma entirely
void secure_function() {
    char buffer[100];
    // ...
}

Remove __declspec(safebuffers)

// Bad
__declspec(safebuffers)
void my_function() {
    // ...
}

// Good
void my_function() {
    // ...
}

Remove /GS- from Command Line

Check your build scripts for /GS-:

# Bad
cl.exe /GS- file.cpp

# Good
cl.exe /GS file.cpp

Check Individual Source Files

Some files may have /GS- in their properties:

  1. Right-click source file → Properties
  2. C/C++ → Code Generation
  3. Ensure "Security Check" is not "Disable (/GS-)"

When to Suppress

This rule may be suppressed for:

  • Performance-critical paths: After security review confirms safety
  • Assembly interop: Functions that don't use C stack layout
  • Leaf functions: Functions with no buffers and no calls
  • Documented exceptions: With explicit security review

Caveats

  • Sometimes disabled for compatibility with inline assembly
  • May be disabled in legacy code for performance
  • Third-party libraries may disable protection

Safe Alternatives

If you're disabling /GS for performance, consider:

  1. Profiling first: Is /GS actually the bottleneck?
  2. Restructuring: Move buffers to non-critical functions
  3. Stack-allocated arrays: Replace with heap allocation
  4. Compiler optimization: Modern compilers optimize /GS well

Example Review Process

Before suppressing this rule:

  1. ✅ Function has no stack buffers
  2. ✅ Function makes no calls
  3. ✅ Function doesn't take user input
  4. ✅ Security team has reviewed
  5. ✅ Documented in code comments

References