Table of Contents
Buffer Overflow: The Bug That Built the Hacking Industry#
Programming is just logic, right? Change variable A, and variable B should stay exactly the same.
But what if, by simply filling a small box with too much stuff, you could teleport to a part of the program you were never supposed to see?
Today we are dissecting the classic buffer overflow — the bug that built the hacking industry.
The stack is a stack of drawers#
In your computer's memory, variables are often stored directly next to each other on the stack. Think of the stack as a column of wooden drawers: one for your socks, and the one right below it for the secret bank safe.
Now, C is a very trusting language. If you tell C to put ten items into an eight-item drawer, C does not say no. C says, "I'll try my best."
The C disaster#
Watch what happens when that trust is misplaced:
int authenticated = 0;
char buffer[8];
strcpy(buffer, "OVERFLOWING");
Three lines, and none of them look dangerous. But "OVERFLOWING" is 11 characters long — 12 bytes once the NUL terminator is counted — and buffer has room for 8. strcpy has no idea how large the destination is. It is not even looking. It copies until it hits the end of the string.
The first 8 bytes fill the drawer. The remaining 4 do not simply vanish — they spill over the edge and crush whatever was stored in the next drawer down. In this layout, that happens to be authenticated:
stack (grows downward)
[ buffer[8] ] ← 8 bytes, full
[ OVERFLOWIN ] ← the extras land here...
[ G\0 ] ← ...overwriting the variable below
[ authenticated = 0 ]
authenticated is no longer zero. It now holds whatever bytes your overflow happened to spill — and if the code that follows only checks whether it is not zero, congratulations: you have just granted yourself access to your own program, without even trying.
This is not hypothetical. Buffer overflows in C and C++ are among the most exploited bug classes in history — the engine behind decades of worms, rootkits, and zero-days. The language gives you raw memory, and the language will not stop you from writing past the edge of it. No bounds check. No complaint. Not even a warning at runtime.
Rust intercepts#
Now let's attempt the same crime in Rust. Rust is the bodyguard who checks the size of every item before you are even allowed to touch the drawer:
let mut buffer = [0u8; 8];
let data = [1u8; 10];
buffer.copy_from_slice(&data);
A fixed-size array of 8 bytes, and an attempt to copy 10 bytes into it. The moment the program reaches this line, Rust does not let the spill happen. It stops the entire universe instead:
thread 'main' panicked at src/main.rs:5:12:
copy_from_slice: source slice length (10) does not match destination slice length (8)
Read that error like a love letter, because it is one. C would have stayed silent while the bank safe was being crushed. Rust tells you exactly what went wrong, where it went wrong — file, line, and the full history of the call stack. It is loud, it is messy, and it is beautiful.
The philosophy#
This is the core of the Rust philosophy.
A C program is like a polite waiter who lets the kitchen burn down because he does not want to interrupt your soup. Rust is the bodyguard who tackles you to the ground the moment he sees a suspicious shadow.
Because for a Rust developer, a panic is a promise: I would rather the world end than overwrite a single byte of memory I am not supposed to touch.
A wall of red text is a rescue#
So the next time you see a wall of red text, remember: it is not a failure. It is a rescue.
That panic is the moment your program stopped itself one instruction before it became a vulnerability — the same vulnerability that C would have shipped silently, straight into production, straight into the hands of whoever found it first.
