TL;DR
Buffer overflows happen when a program tries to write more data into a memory area than it’s allowed, potentially crashing the program or letting attackers take control. This guide shows how to prevent them without relying on environment variables.
Understanding Buffer Overflows
A buffer overflow occurs when you attempt to store more data in a fixed-size block of memory (the ‘buffer’) than it can hold. This overwrites adjacent memory, leading to unpredictable behaviour. Common causes include unchecked input and string manipulation.
Preventing Buffer Overflows
- Use Safe Functions: Avoid functions like
strcpy,strcat, andsprintfwhich don’t perform bounds checking. Instead, use their safer counterparts:strncpy: Copies a specified number of characters.char dest[10]; strncpy(dest, source, sizeof(dest) - 1); dest[sizeof(dest) - 1] = ' '; // Always null-terminate!strncat: Appends a specified number of characters.char dest[20]; strncat(dest, source, sizeof(dest) - strlen(dest) - 1); dest[sizeof(dest) - 1] = ' '; // Always null-terminate!snprintf: Formats a string with a maximum length.char dest[30]; snprintf(dest, sizeof(dest), "Formatted string: %s", source); dest[sizeof(dest) - 1] = ' '; // Always null-terminate!
- Input Validation: Check the length of user input before copying it into a buffer. Ensure it doesn’t exceed the buffer’s capacity.
int input_length = strlen(user_input); if (input_length >= BUFFER_SIZE) { // Handle error - input too long } else { strcpy(buffer, user_input); // Now safe because of length check } - Bounds Checking: Explicitly verify that you’re not writing beyond the buffer boundaries.
for (int i = 0; i < input_length && i < BUFFER_SIZE - 1; ++i) { buffer[i] = user_input[i]; } buffer[BUFFER_SIZE - 1] = ' '; // Null-terminate - Stack Canaries: Compilers can insert 'canary' values onto the stack before function return addresses. If a buffer overflow overwrites the canary, it indicates an attack and terminates the program.
- Enable this feature in your compiler (e.g.,
-fstack-protectorwith GCC).
- Enable this feature in your compiler (e.g.,
- Address Space Layout Randomization (ASLR): ASLR randomizes the memory addresses of key program components, making it harder for attackers to predict where to inject malicious code.
- Enable this feature in your operating system. Most modern OSes have this enabled by default.
- Data Execution Prevention (DEP): DEP marks certain memory regions as non-executable, preventing attackers from executing injected code.
- Enable this feature in your operating system.
Example Scenario & Fix
Let's say you have the following vulnerable code:
void copy_input(char *user_input) {
char buffer[16];
strcpy(buffer, user_input); // Vulnerable! No bounds checking.
printf("Copied input: %sn", buffer);
}
To fix this:
void copy_input(char *user_input) {
char buffer[16];
strncpy(buffer, user_input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = ' '; // Ensure null termination.
printf("Copied input: %sn", buffer);
}
Testing for Buffer Overflows
Use tools like:
- Valgrind: A memory debugging tool that can detect buffer overflows and other memory errors.
- AddressSanitizer (ASan): Another powerful memory error detector, often faster than Valgrind.

