Skip to content

AD3034: RustEnableControlFlowGuard

Summary

Property Value
ID AD3034
Name RustEnableControlFlowGuard
Category Security
Severity Warning
Applies to PE (Windows) - Rust binaries

Description

Rust PE binaries should be compiled with Control Flow Guard (CFG) enabled when targeting Windows. CFG provides protection against control-flow hijacking attacks by validating indirect call targets at runtime.

How It Works

The rule checks Rust PE binaries for:

  1. IMAGE_DLLCHARACTERISTICS_GUARD_CF flag in DLL characteristics
  2. Valid CFG function table in load configuration
  3. CFG instrumentation markers

When enabled, the Windows loader: - Validates indirect calls against a table of valid targets - Terminates the process if an invalid target is detected

Why This Matters

Rust's safety guarantees apply to safe Rust code, but Windows Rust applications often interact with system APIs, COM objects, and native libraries where CFG provides essential protection against control-flow attacks.

Windows-Specific Attack Surface

Rust on Windows has unique risks:

// Windows API calls via FFI
use windows::Win32::Foundation::*;
use windows::Win32::System::Com::*;

unsafe {
    // COM interfaces are vtable-based - CFG protects these
    CoInitializeEx(None, COINIT_MULTITHREADED)?;
    // Any COM call could be a target for vtable hijacking
}

CFG Protection for Rust

Attack Vector Rust Protection CFG Protection
Safe Rust Type system Redundant
unsafe blocks None Active
Win32 API calls None Active
COM interfaces None Active (vtables)
Native DLL loads None Active

Windows Ecosystem Integration

Rust Windows apps often use:

windows-rs crate → Win32 APIs → unsafe FFI
winapi crate → Legacy Win32 → unsafe FFI
COM interfaces → Vtables → CFG protects calls
Native plugins → DLL loading → unsafe boundaries

Each boundary benefits from CFG.

How CFG Helps Rust

Without CFG:
  Bug in winapi call → Corrupt vtable → Hijacked call → Exploit

With CFG:
  Bug in winapi call → Corrupt vtable → Hijacked call attempt
                                       → CFG validation fails
                                       → Process terminated safely

Real-World Rust Unsafe in Windows Crates

Crate Unsafe Reason CFG Benefit
windows-rs Win32 bindings High
wgpu GPU driver calls High
tokio (Windows) IOCP async I/O Medium
winit Window management High

Enterprise Deployment

CFG is often required in enterprise Windows environments:

Environment CFG Expectation
Microsoft internal Required
Windows Store apps Encouraged
Enterprise security Often mandated
Antivirus integration May check for CFG

Performance Considerations

CFG has low runtime overhead:

Metric Impact
Runtime overhead 1-2% typical
Indirect call cost Small validation
Memory overhead Small CFG bitmap
Startup overhead CFG table loading

Rust-specific factors: - Safe Rust uses few indirect calls (trait objects, fn ptrs) - FFI-heavy code sees higher relative benefit and overhead - Pure Rust binaries may see <1% overhead

Workload impact:

Workload Overhead
Compute-bound <0.5%
GUI applications 1-2%
COM-heavy apps 2-3%
Game engines 1-2%

Trade-offs: - Nightly Rust required (stable doesn't support CFG) - Minimal overhead for significant security improvement - Essential for Windows security certification

Even with Rust's memory safety guarantees, CFG provides defense-in-depth:

  • Unsafe Rust code: unsafe blocks may have vulnerabilities
  • C/C++ dependencies: Foreign code through FFI
  • Windows integration: COM, system APIs may introduce risks
  • Defense-in-depth: Multiple layers of protection

Resolution

Rust Nightly Compiler

CFG requires nightly Rust with unstable features:

RUSTFLAGS="-Z control-flow-guard" cargo +nightly build --release --target x86_64-pc-windows-msvc

Cargo Configuration

Add to .cargo/config.toml:

[build]
rustflags = ["-Z", "control-flow-guard"]

[target.x86_64-pc-windows-msvc]
rustflags = ["-Z", "control-flow-guard"]

Build Script (PowerShell)

$env:RUSTFLAGS = "-Z control-flow-guard"
cargo +nightly build --release

Build Script (Bash/WSL)

export RUSTFLAGS="-Z control-flow-guard"
cargo +nightly build --release --target x86_64-pc-windows-msvc

When to Suppress

This rule can be suppressed in the following scenarios:

  • Stable Rust required: CFG requires nightly compiler
  • Non-Windows target: CFG is Windows-specific
  • Pure Rust code: Minimal benefit without FFI or unsafe code
  • Testing environments: When CFG interferes with testing tools

Caveats

  • Requires Rust nightly compiler
  • Windows-specific (use CET for Linux)
  • Some runtime overhead for validation
  • May impact debugging experience

Comparison with CET

Feature CFG (Windows) CET (Linux)
Implementation Software Hardware
Overhead Low Very Low
Rust Flag -Z control-flow-guard -Z cf-protection=full
Compiler Nightly Nightly

References