Memory Safety - Speichersicherheits-Schwachstellen
Memory safety vulnerabilities arise in languages without automatic memory management (C/C++) due to incorrect manual memory management. Main categories: Buffer overflow (stack/heap), use-after-free, double-free, integer overflow, format string. Historically, this category accounts for ~70% of all critical CVEs in large software projects (Microsoft, Google). Protection: Memory-safe languages (Rust, Go), AddressSanitizer, stack canaries, ASLR, DEP/NX.
Memory safety vulnerabilities are a class of bugs in low-level software (C, C++, Assembly) that occur when a program accesses memory not intended for it. Microsoft reported that ~70% of all CVEs in Windows products are attributable to memory safety flaws. Google Chrome: similar figures. These vulnerabilities are particularly dangerous because they often lead to remote code execution (RCE).
Vulnerability Classes
Buffer Overflow (Stack-based)
// Classic example:
void unsafe_copy(char* user_input) {
char buffer[64];
strcpy(buffer, user_input); // NO length check!
}
// If input > 64 bytes: overwrites return address!
// Attacker controls where function jumps back → Code execution!
Exploitation:
- Fill buffer with attacker payload: shellcode or ROP chain
- Set return address to point to shellcode
- Function returns → jumps to attacker code → RCE
Modern countermeasures:
- Stack Canaries: random value between buffer and return address – if overwritten, the program terminates
- ASLR: Addresses are assigned randomly; attacker does not know shellcode address
- NX/DEP: Stack is not executable; shellcode cannot be executed → ROP required
Heap Buffer Overflow
// Overwrite memory on the heap:
char* buf = malloc(64);
memcpy(buf, user_data, user_len); // user_len > 64 → Overflow!
// → Overwrites heap metadata → Allocator compromised → Exploit
Use-After-Free (UAF)
// Free memory, then use it again:
char* ptr = malloc(100);
free(ptr);
ptr[0] = 'A'; // UNDEFINED BEHAVIOR! ptr is a dangling pointer!
Exploitation:
- Object A is allocated (ptr_a) → Free A
- Attacker ensures that object B is assigned the ptr_a memory
- Legacy code still uses ptr_a → reads/writes to B
- Type confusion → Attacker controls B’s contents → Exploit
UAF is one of the most common browser exploit classes. In Chrome, ~70% of high-severity CVEs are UAF-based.
Double-Free
// Free memory twice:
char* ptr = malloc(100);
free(ptr);
// ... code ...
free(ptr); // Double-Free! Heap corruption!
// → Modifies heap allocator structures
// → Can lead to UAF or arbitrary write
Integer Overflow
// Overflow in integer arithmetic:
int size = user_provided_size * 2; // If size = MAX_INT/2: Overflow → 0!
char* buf = malloc(size);
memcpy(buf, user_data, user_provided_size * 2); // Insufficient buffer!
// → Buffer overflow despite malloc!
// Real-world example: libpng length calculations
uint16_t width, height; // 16-bit
int total = width * height * 4; // Overflow if > 65535x65535!
Format string vulnerability
printf(user_input); // NEVER! Only printf("%s", user_input)!
// → If user_input = "%x %x %x %x": Stack values are printed!
// → If user_input = "%n": Writes to memory!
// → Arbitrary memory read and write access!
// CORRECT:
printf("%s", user_input); // %s as format string, input as argument
Protective Measures at the Compiler/OS Level
Stack Canaries (GCC/Clang)
gcc -fstack-protector-strong app.c
Random value between local variables and return address. When the function returns, the canary is checked—if overwritten, the program terminates (stack smashing protection).
ASLR (Address Space Layout Randomization)
The OS randomizes the stack, heap, libraries, and PIE binary base. Attackers do not know the addresses; jumps fail.
# Linux:
sysctl kernel.randomize_va_space=2 # full randomization
# Windows: ASLR enabled in Security Center (default)
ASLR bypass requires: information leak + ROP chain.
NX/DEP (No-Execute / Data Execution Prevention)
Memory regions are marked as non-executable. Stack and heap are data regions—shellcode cannot be executed.
gcc -Wl,-z,noexecstack
Bypass: ROP (Return-Oriented Programming).
PIE (Position Independent Executable)
gcc -fPIE -pie app.c
The binary base is also randomized (not just libraries). Full ASLR is only possible with PIE.
RELRO (RELocation Read-Only)
gcc -Wl,-z,relro,-z,now app.c
The GOT (Global Offset Table) is set to read-only after loading. This prevents GOT overwrite attacks.
AddressSanitizer (Development/Testing Phase)
gcc -fsanitize=address,undefined app.c
Instruments all memory accesses. Buffer overflows, UAF, and double-free result in an immediate crash with an error message. Performance overhead: ~2x - only for testing/fuzzing, not for production.
# MemorySanitizer (for uninitialized reads):
clang -fsanitize=memory app.c
Control Flow Integrity (CFI)
clang -fsanitize=cfi app.c
Ensures that indirect jumps only lead to valid targets. Significantly hinders ROP attacks. Enabled in Chrome, Windows (Microsoft CET).
Memory-Safe Languages
Rust - Memory Safety without a Garbage Collector
The compiler’s ownership system prevents UAF, double-free, and buffer overflow. Zero-cost abstractions deliver the same performance as C/C++. NSA, CISA, and the White House recommend memory-safe languages (2023/2024).
fn safe_access(v: &Vec;<i32>, idx: usize) -> Option<&i32;> {
v.get(idx) // Bounds check! Returns None if out-of-bounds
}
// NO buffer overflow possible with safe Rust code!
// unsafe{}-block: required for FFI/system code, explicitly marked
Adoption of Rust:
- Linux kernel: Rust as a second language since kernel 6.1
- Android: Rust for new kernel components (UAF drastically reduced)
- Windows: Rust for new security-critical components
- Google: 70% fewer memory safety bugs in Android Rust code
Go - Safe, but with a garbage collector
- Garbage collector prevents UAF and double-free
- Automatic bounds checks
- Performance lower than C, but significantly higher than Python
- Trade-off: GC pauses, but safe memory management
Python / Java / JavaScript - Fully GC-managed
- Memory management handled by the runtime
- Native extensions (C extensions) can be unsafe
- Python C extensions (numpy, scipy) are potentially memory-unsafe
Recommendation
- New projects with performance requirements: Prefer Rust
- Existing C/C++ codebase: Gradual Rust rewrite for critical parts
- All C/C++ projects: ASAN/fuzzing in CI/CD is mandatory