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:
IMAGE_DLLCHARACTERISTICS_GUARD_CFflag in DLL characteristics- Valid CFG function table in load configuration
- 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:
unsafeblocks 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:
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)¶
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 |