Chapter 27 Β· Concepts

Buffer Overflows β€” Concepts

How overflows work mechanically, why bounds checking prevents them, why they are difficult to exploit, and what makes them truly dangerous.

How a Buffer Overflow Works

A buffer overflow happens when a program writes more data into a buffer than the buffer was designed to hold. The excess data has nowhere to go in the intended space β€” so it overflows. It spills into whatever memory sits directly next to the buffer in the program's allocated memory.

1
Buffer is allocated
The developer reserves a fixed area of memory to hold incoming data. For example: an 8-byte buffer to hold a user's input. The program is designed assuming no input will ever exceed 8 bytes.
2
Attacker sends more data than the buffer holds
The attacker sends 9 bytes instead of 8. The program has no bounds check β€” it writes all 9 bytes. The first 8 bytes fill the buffer exactly as designed.
3
The 9th byte overflows into adjacent memory
The 9th byte has nowhere to go in the buffer. The program continues writing β€” and the 9th byte lands in whatever memory sits directly adjacent to the buffer. That adjacent memory is now overwritten.
4
Adjacent memory is corrupted
Whatever was stored in adjacent memory β€” another variable, a permission value, a control structure β€” is now overwritten with the overflow data. The program's behaviour from this point depends on what that memory held and what value the overflow wrote into it.

Bounds Checking: The Developer's Prevention

Bounds checking is the technique that prevents buffer overflows entirely. The logic is simple: before writing data into a buffer, check whether the incoming data actually fits.

The Check

Is the incoming data smaller than or equal to the buffer's allocated size?

If yes β€” proceed with the write. The data fits.

If no β€” reject the write. Do not proceed. Return an error.

That single check, applied consistently, is all that is required. No data can overflow if it is verified to fit before being written.

Why Overflows Exist

Buffer overflows exist because developers make mistakes with bounds checking:

They forget to add the check entirely. They check the wrong variable β€” the wrong size or the wrong limit. They use a library function that performs no check at all. They calculate the size incorrectly.

Attackers know this. They spend time examining applications looking for precisely these openings β€” places where data flows into memory without a valid bounds check in place.

The Developer's Responsibility

Bounds checking is entirely within the developer's control. It does not require special hardware or operating system support. It requires discipline in code: verify every write before it happens.

When bounds checking is applied correctly everywhere data is written into memory, buffer overflows cannot occur. The overflow is stopped before it starts β€” the excess data is rejected, not written.

Why Buffer Overflows Are Not Simple to Exploit

Finding a buffer overflow is not the same as successfully exploiting one. The path from "I found an overflow" to "I have a working exploit" is often enormous.

The ProblemWhat HappensWhat the Attacker Needs
Adjacent memory may be critical Overflowing into memory the program relies on to run correctly causes a crash. A crashed application is useless to the attacker β€” it cannot do anything they want. The attacker needs to identify what is in adjacent memory and determine whether it can be overwritten without crashing the application.
Most overflows crash the application The attacker sends data that overflows, but the result is a crash, not a useful change. Many overflows produce only this outcome. The attacker needs to find the specific input that corrupts memory in a controlled, predictable way β€” not one that crashes everything. This takes time and effort.
The desired outcome must be reachable Even if the overflow changes adjacent memory, the changed value may not produce the outcome the attacker wants. The attacker cannot always choose what is in adjacent memory. The attacker needs both a buffer overflow and something valuable in adjacent memory β€” a permission flag, a variable that controls access, a control structure worth changing.
Buffer overflows are not instant exploitation. They are a starting point for a long, iterative process. The attacker must understand exactly what is in adjacent memory, find the specific overflow input that changes it in a useful way, and verify the result. Most overflows encountered in the wild simply crash the target application.

The Three Conditions for a Dangerous Buffer Overflow

Not every buffer overflow is dangerous. Three conditions must all be present for an overflow to become a serious exploit.

Condition 1: No Bounds Checking

A buffer exists where data is written without verifying it fits. The overflow is possible because the developer did not check the size of incoming data against the buffer's allocated space.

This is the root cause. Without this condition, the other two cannot occur. Proper bounds checking by the developer eliminates condition one β€” and without condition one, the rest cannot happen.

Condition 2: Something Valuable in Adjacent Memory

Adjacent memory contains something worth changing β€” another variable, a permission flag, a value that controls what the program does next.

If adjacent memory holds nothing the attacker cares about, the overflow may crash the application or change a harmless value. The overflow is only useful if adjacent memory holds something that grants the attacker what they want.

Condition 3: Repeatability

The overflow consistently produces the same outcome, reliably, every time the specific input is sent. Every single attempt produces the same result.

When all three conditions are present, the developer has created a door they did not know was there. The attacker walks right through it β€” reliably, on demand, against every machine running that software.