Buffer Overflow
Buffer Overflow or Buffer Overrun is a bug where the program writes data outside the allocated memory of a buffer. It can be Stack-based or Heap-based and result in risks to confidentiality, integrity or availability depending on whether this bug corrupt valid data, cause the program to crash or execute arbitrary code (CWE-121,CWE-122).
A simple example is the code below:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 6
int main(void) {
int my_array[ARRAY_SIZE] = {0};
int modified = 0;
int i = 0;
for (i = 0; i <= ARRAY_SIZE; i++) { // `<=` should be `<`.
my_array[i] = 2 * i;
}
printf("%d\n", modified); // Prints 12 (6 * 2).
return EXIT_SUCCESS;
}
Detection and Debugging Tools
To detect these bugs, it is possible to use static code analysis tools such as Clang Static Analyzer, Cppcheck or Infer (for the C language) or fuzzers such as AFL++ (for the C language), although these tools do not detect all occurrences of the problem.
In the event of a failure, it is therefore also necessary to have debugging tools such as GDB or Valgrind (for the C language), that can identify the instruction causing the problem.
A more drastic solution to this bug is to use languages that perform index checking when the program tries to access the element at a certain index of a buffer, such as Kotlin, Java or Rust.
Exercise
The exercise program contains the implementation of some functions and, unfortunately, it doesn’t work. Your goal is:
- to find the bug using debugging tools;
- and to fix it.
The Case of Rust
In Rust, this bug is not possible because Rust uses a combination of static analysis and runtime index checking.
Here is an example of Rust code that shows this feature:
const ARRAY_SIZE: usize = 6;
fn main() {
let mut my_array: [i32; ARRAY_SIZE] = [0; ARRAY_SIZE];
let modified: i32 = 0;
for i in 0..=ARRAY_SIZE { // Should be `0..ARRAY_SIZE`.
my_array[i] = 2 * i as i32; // Panics here.
}
println!("{}", modified);
}
It is the equivalent of the C code showed in the intro.