|
|
Finding memory bugs
|
|
|
===================
|
|
|
|
|
|
A memory bug occurs when a program accesses a region of memory that it should not access at that moment.
|
|
|
|
|
|
Memory bugs are often not obvious: While sometimes a memory bug triggers a SIGSEGV (or, on BSD or Hurd systems, a SIGBUS), often it is silent. A wrong memory read will just return wrong data; a wrong memory write will write wrong data into memory, that might cause undefined behaviour later during execution of the program.
|
|
|
|
|
|
There are several classes of memory bugs:
|
|
|
* Buffer overrun: Access of memory outside of the bounds of the designated memory region. Sometimes this memory region was allocated by a function like `malloc`; sometimes we're talking about a memory region that is a subobject (i.e. part of a struct).
|
|
|
* Use after free: Referencing memory that has already been declared as free (and may thus be already in use by a different thread).
|
|
|
* Stack use after return/scope-end: Referencing memory of a stack-allocated variable that does not exist any more.
|
|
|
* Double-free: Freeing the same region of memory twice.
|
|
|
|
|
|
Available tools
|
|
|
===============
|
|
|
|
|
|
In all cases, build the program and, as far as you can, its libraries with debugging information. I.e. configure with `CFLAGS="-O1 -fno-omit-frame-pointer -ggdb"`. This ensures that stack traces of allocations will be more precise. If you want to use gdb for debugging later, use `CFLAGS="-O0 -fno-omit-frame-pointer -ggdb"`.
|
|
|
|
|
|
GCC or clang with Address Sanitizer
|
|
|
-----------------------------------
|
|
|
|
|
|
**Ubuntu package:** none needed
|
|
|
|
|
|
**Usage:**
|
|
|
|
|
|
1. Rebuild the program with `CC="gcc -fsanitize=address"` or `CC="clang -fsanitize=address"`.
|
|
|
|
|
|
2. Set the environment variable `ASAN_OPTIONS`.
|
|
|
```
|
|
|
ASAN_OPTIONS="detect_leaks=0 abort_on_error=1"
|
|
|
export ASAN_OPTIONS
|
|
|
```
|
|
|
Specifying `detect_leaks=0` avoids leak detection that is undesired in this context.
|
|
|
Specifying `abort_on_error=1` is necessary for debugging a memory bug with gdb.
|
|
|
|
|
|
3. Run the program.
|
|
|
Either
|
|
|
```
|
|
|
**PROGRAM** OPTIONS
|
|
|
```
|
|
|
or
|
|
|
```
|
|
|
gdb **PROGRAM**
|
|
|
(gdb) run OPTIONS
|
|
|
```
|
|
|
|
|
|
**Works on:** most platforms
|
|
|
|
|
|
**Advantages:**
|
|
|
- Does not require program modifications.
|
|
|
- Catches most kinds of memory bugs.
|
|
|
|
|
|
**Drawbacks:**
|
|
|
- Some of the stack traces are truncated.
|
|
|
|
|
|
**References:**
|
|
|
- https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
|
|
|
- https://clang.llvm.org/docs/AddressSanitizer.html
|
|
|
- https://github.com/google/sanitizers/wiki/AddressSanitizer
|
|
|
|
|
|
CHERI
|
|
|
-----
|
|
|
|
|
|
CHERI is an architecture that includes permissions and bounds in each pointer.
|
|
|
It requires special hardware. Free Software developers can access such a machine at cfarm240.cfarm.net in the [compile farm project](https://portal.cfarm.net/).
|
|
|
|
|
|
**Ubuntu package:** n/a
|
|
|
|
|
|
**Usage:**
|
|
|
Compile with `CC="cc"` and `CFLAGS="-ggdb"`.
|
|
|
|
|
|
**Works on:**
|
|
|
Specialized hardware only.
|
|
|
|
|
|
**Advantages:**
|
|
|
- It's a complete architecture, where pointers are given permissions.
|
|
|
- Speed.
|
|
|
|
|
|
**Drawbacks:**
|
|
|
- Detects buffer overruns, but not e.g. use-after-free bugs. [1](https://www.techrxiv.org/articles/preprint/Towards_a_Hybrid_Approach_to_Protect_Against_Memory_Safety_Vulnerabilities/14680185)
|
|
|
- Requires modifications of code that casts integers to pointers.
|
|
|
- The OS is a BSD derivate, not Linux.
|
|
|
|
|
|
**References:**
|
|
|
https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-947.pdf
|
|
|
|
|
|
valgrind
|
|
|
--------
|
|
|
|
|
|
**Ubuntu package:** valgrind
|
|
|
|
|
|
**Usage:**
|
|
|
```
|
|
|
valgrind --tool=memcheck --num-callers=20 COMMAND
|
|
|
```
|
|
|
|
|
|
**Works on:** Linux, macOS, Solaris
|
|
|
|
|
|
**Advantages:**
|
|
|
- Works with the unmodified binaries.
|
|
|
|
|
|
**Drawbacks:**
|
|
|
- Does not detect some kinds of buffer overruns.
|
|
|
- valgrind needs a lot of memory.
|
|
|
|
|
|
**References:**
|
|
|
- https://valgrind.org/docs/manual/mc-manual.html |