CHAPTER 2 BACKGROUND
2.2 S OLUTIONS FOR BUFFER OVERFLOW ATTACKS
The tools for detecting buffer overflow operate either a static or dynamic manner.
Static tools used in development time analyze potential buffer overflow vulnerabilities without executing programs. These tools do not incur run-time overhead, but have theoretical and practical limits on accuracy. For example, precise analysis of arbitrary C programs depends on several undecidable problems, including path reachability and variable aliases [5], and static tools all have to face a tradeoff between precision and scalability. Dynamic tools used in runtime do not have the limits, but performance
overhead is a critical problem. Table 1 summarized the comparisons of static solution and variety of dynamic solutions. In the following section, we will introduce some static and dynamic tools.
Table 1. Techniques for buffer overflow detection
Dynamic Solutions
* The performance overhead is evaluated with Apache web server.
2.2.1 Static detector
Wanger et al. [9] formulated buffer overflow detection as an integer range analysis problem. The approach models a C string as a pair of integer ranges of allocated size and length. Vulnerable functions in the C standard library are modeled as their operations on the integer ranges. This tool checks whether its inferred string length is less than allocated size in each string operations. However, the tool is impractical to use since a lot of false positives are produced along with some false negatives due to imprecision in the range analysis. Splint [10] is an annotation-based analysis tool extended from LCLint [11] by introducing new annotations which allows the declaration of a set of preconditions and postconditions in each function.
The experiment result shows Splint still produce a number of false positives that is impossible to eliminate because of general undecidability of static analysis.
2.2.2 Dynamic detector
Dynamic approaches could be classified into bounds checking, pointer protection, and taint tracking, according to what technologies they use. A summary is shown in Table 1.
Table 2. Dynamic buffer overflow detector.
Class Tool Coverage Performance
overhead
StackGuard Adjacency overflowing in activation records
~0
LibsafePlus String function in C library when attacking activation records
0 – 1X
Pointer
protection
PointGuard Pointers integrity 0 – 0.2X TaintCheck Executing malicious code 25X
Taint
tracking
TaintTrace Executing malicious code 4XBound checking provides perfect protection against buffer overflows via complex analysis and patch on source codes, and thus the tools based on bounds checking incur a substantial cost in compatibility with existing codes and performance.
The tool proposed by Jones and Kelly [17] is based on the principle that an address computed from an in-bounds pointer must have the same referent object as the original pointer. Thus this tool maintains a run-time object table which collects all the base addresses and size information of all static, heap and stack objects. Performance overhead of this tool is high, approximately ten to thirty times slowdown. CCured [12] is a hybrid language designed to be a safer version of the C programming language. It transforms unsafe types of a C program into safe types through static
analysis. Programs that cannot be represented to safe types are instrumented with run-time checks in order to monitor the safety of executions. Performance overhead is still high at approximately two to three times. CRED [13] replaces every out-of-bounds (OOB) pointer value with the address of a special OOB object created for that value. The OOB object will maintain the actual pointer value and information on the referent object. Any pointer derived from the address is bounds checked before it can be dereferenced. CRED has the best performance among all bounds checking tools, but the slowdown can still achieve up to 1.2 times in some cases.
Pointer protection aims to confine pointer manipulation to a limit of range or modify the behavior of reference and dereference from a pointer. These tools have excellent performance that can be used in products, but they do not leave any useful clues for developer to patch the holes. The developer must spend much time on finding the bug to fix, and the victim program will remain vulnerable to the attack during this period, leading to denial of service. StackGuard [14] is perhaps the most well-referenced tools. The tool prevents stack smashing attack by placing a canary word prior to the return address, and verifying whether the canary word is changed before the subroutine returns to the original instruction location. PointGuard [16]
provides integrity for pointers by encrypting pointers when stored in memory, and decrypting them only when loaded into CPU. When an address is overwritten to a malicious address, it decrypts the address to a random value that reasonably crashes the program. LibsafePlus [17] uses a dynamic library which provides wrapper functions for unsafe C library functions. A wrapper function determines the source and the target buffer sizes, provided by GCC debugging option -g, and makes sure that invocation of the wrapper functions would not result in an overflow.
Taint tracking is the third dynamic technique against buffer overflow. This technique keeps track of the propagation of untrusted (taint) data during program
execution. Taint data represent any data from an untrusted source such as network or some specific devices. When a program executes a piece of code derived from an untrusted source, a tool based on this technique will produce an alarm to indicate a possible instance of malicious code execution. TaintCheck performs taint tracking for a program by running the program in an emulator Valgrind [18], which allows TaintCheck to monitor and control the program’s execution. Fig. 3 illustrated how TaintCheck keeps track of taint data and examines an attack code is executed. When the program was loaded into the emulator of Valgrind, the instrumentation will determine the kind of the instruction, and insert codes for taint information maintenance and instruction pointer examination if needed. However, this way to implement taint tracking imposes heavy overhead up to thirty times, which is possibly due to instrumentation at runtime, high frequency of checking malicious execution, and the emulator itself. Thus another solution, TaintTrace, is designed to decrease the overhead which leveraging DynamoRIO [19] which is a dynamic code modification system including a number of optimization techniques to keep low overhead, but the experiment shows it still brings over five times slowdown.
Fig. 3. System architecture of TaintCheck.