Buffer overflow and memory safety: why C programs are vulnerable
In short: A buffer overflow occurs when a program writes more data into a memory area than it holds; neighbouring data or return addresses can then be overwritten. Modern protections and memory-safe languages slow this down.
In more detail: In languages such as C/C++ nobody automatically checks array bounds. If code writes beyond the end, it overwrites neighbouring data: this is the root of many serious vulnerabilities (Morris worm 1988, Heartbleed 2014 as an over-read). The article explains principle and protection without attack instructions.
In Depth
The principle
A program reserves e.g. 8 bytes for a name (char name[8]) on the stack. If it copies more characters unchecked (strcpy, gets), the data runs into neighbouring memory: other variables, the saved return address or function pointers. An attacker can thus redirect program flow. Related: heap overflow, use-after-free (memory reused after being freed), double free, off-by-one, format-string bugs, integer overflow (leads to a too small buffer), out-of-bounds read (Heartbleed).
Protection mechanisms
- Stack canaries: guard value before the return address, checked before returning.
- ASLR (random memory addresses), PIE.
- NX/DEP (data areas not executable), W^X.
- RELRO, CFI/shadow stack (control-flow integrity), Intel CET, ARM PAC/MTE.
- Compiler warnings and protection (
-Wall -Wextra,-fstack-protector-strong,-D_FORTIFY_SOURCE=2). - Sanitizers (AddressSanitizer, UBSan) and Valgrind find errors during testing, fuzzing (AFL++, libFuzzer) provokes them. No single protection is perfect; attackers combine techniques (ROP). Best strategy: avoid the bugs.
Programming more safely
- Safe functions:
fgetsinstead ofgets,snprintf/strlcpyinstead ofsprintf/strcpy, always check lengths. - C++:
std::string,std::vector,std::span,.at(), smart pointers instead ofnew/delete(RAII). - Validate inputs, check sizes, mind integer overflows.
- Memory-safe languages: Rust (ownership, borrow checker), Go, Java, C#, Python, Swift: array bounds are checked, memory managed (but
unsafeblocks/native extensions remain a risk). - Policy: authorities (BSI, CISA) recommend memory-safe languages for new software; Linux kernel, Windows, Android introduce Rust.
- Code reviews, static analysis (clang-tidy, Coverity, CodeQL).
Classification and learning
- Roughly 60–70 % of severe vulnerabilities in large C/C++ code bases (Microsoft, Chromium) were memory errors.
- Install updates: many attacks use known flaws in old programs.
- Learning (legal): examine your own small C programs with ASan/Valgrind, CTF tasks (pwn) on practice platforms, lecture material (stack/heap, assembler).
- Heartbleed as a case study: missing length check → server memory readable.
- Exam: name stack layout, causes, countermeasures.
- Related: segmentation fault, memory leak, stack and heap, Valgrind.
See also: Segmentation fault, Stack and heap, Valgrind and sanitizers, Rust: ownership and borrowing