AD3036: EnableControlFlowIntegrity¶
Summary¶
| Property | Value |
|---|---|
| ID | AD3036 |
| Name | EnableControlFlowIntegrity |
| Category | Security |
| Severity | Warning |
| Applies to | ELF (Linux/Unix) |
Description¶
Control Flow Integrity (CFI) is a security mechanism that restricts the targets of indirect control flow transfers (function calls through pointers, virtual method calls, etc.) to valid destinations. This prevents many exploitation techniques that rely on hijacking program control flow.
Why This Matters¶
CFI provides the most comprehensive software-based protection against control-flow hijacking attacks. It validates every indirect branch, making exploitation extremely difficult even with memory corruption.
The Control-Flow Attack Problem¶
Attackers exploit indirect branches:
void (*func_ptr)(int);
func_ptr = legitimate_function;
// ... memory corruption ...
func_ptr = attacker_function; // Hijacked!
(*func_ptr)(42); // Calls attacker code
How CFI Protects¶
Without CFI:
Indirect call → Any address → Attacker's code
With CFI:
Indirect call → Must match allowed type signature
→ Only valid functions of that type allowed
→ Invalid target = abort
CFI Check Types¶
| Check | Protects Against |
|---|---|
| cfi-vcall | Virtual function hijacking |
| cfi-nvcall | Non-virtual member call hijacking |
| cfi-derived-cast | Bad downcasts |
| cfi-unrelated-cast | Invalid type casts |
| cfi-icall | Function pointer hijacking |
Why LTO Is Required¶
Without LTO:
file1.c: void (*fp)(int); // Call here
file2.c: void target(int); // Target here
Compiler can't see both → weak CFI
With LTO:
Entire program visible
All valid targets known
Precise CFI enforcement
Attack Difficulty with CFI¶
| Attack Technique | Without CFI | With CFI |
|---|---|---|
| ROP | Works | Harder (return-type checks) |
| Function pointer overwrite | Works | Blocked (type mismatch) |
| Vtable hijacking | Works | Blocked (virtual call check) |
| JOP | Works | Blocked (branch checks) |
Performance Characteristics¶
| Aspect | Overhead |
|---|---|
| Indirect calls | Small check |
| Virtual calls | Small check |
| Direct calls | None |
| Overall | 1-5% typical |
Cross-DSO CFI¶
For shared libraries, use -fsanitize-cfi-cross-dso:
Without cross-DSO:
CFI only within binary
Library calls unchecked
With cross-DSO:
CFI across library boundaries
Comprehensive protection
Clang's CFI implementation provides several types of protection: - cfi-vcall: Virtual function call validation - cfi-nvcall: Non-virtual member function call validation - cfi-derived-cast: Derived class cast validation - cfi-unrelated-cast: Unrelated class cast validation - cfi-icall: Indirect function call validation
CFI requires Link-Time Optimization (LTO) to work across translation units.
Category¶
Security
Resolution¶
Enable CFI when building with Clang:
# Enable all CFI checks (recommended)
clang -flto -fsanitize=cfi -fvisibility=hidden -o output source.c
# Enable specific CFI checks
clang -flto -fsanitize=cfi-vcall,cfi-icall -fvisibility=hidden -o output source.c
# For cross-DSO CFI (libraries)
clang -flto -fsanitize=cfi -fsanitize-cfi-cross-dso -fvisibility=hidden -o output source.c
For CMake projects:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto -fsanitize=cfi -fvisibility=hidden")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fsanitize=cfi -fvisibility=hidden")
Detection¶
This rule detects CFI through multiple methods:
- Symbol-based detection: Checks for CFI runtime symbols:
__cfi_check__cfi_slowpath__cfi_slowpath_diag-
__ubsan_handle_cfi_check_fail -
DWARF-based detection: Checks for
-fsanitize=cfiin compiler flags recorded in debug information
Applicability¶
This rule applies to: - ELF executables (ET_EXEC) - ELF shared libraries (ET_DYN that are not PIE executables) - Binaries compiled with Clang/LLVM
Examples¶
Pass¶
Fail¶
Notes¶
- CFI requires LTO (-flto) to function properly
- The
-fvisibility=hiddenflag is recommended to reduce the attack surface - Cross-DSO CFI (
-fsanitize-cfi-cross-dso) enables CFI checks across shared library boundaries - CFI may have a small runtime performance overhead
Related Rules¶
- AD3019: EnableLTO - LTO is required for CFI
- AD2008: EnableControlFlowGuard - Windows equivalent of CFI
- AD3031: EnableClangSafeStack - Another Clang security feature