340 likes | 480 Views
Dynamic Test Generation To Find Integer Bugs in x86 Binary Linux Programs David Molnar Xue Cong Li David Wagner. Related-Static & Runtime check. Poor fit with traditional runtime, static analysis – Static analysis: false positives – Runtime analysis: “benign” overflow problem
E N D
Dynamic Test Generation To FindInteger Bugs in x86 Binary LinuxProgramsDavid MolnarXue Cong LiDavid Wagner
Related-Static & Runtime check • Poor fit with traditional runtime, static analysis – Static analysis: false positives – Runtime analysis: “benign” overflow problem many overflows are benign and harmless. Throwing 1. an exception in such cases prevents the application from functioning and thus causes false positives. 2. Occasionally the code intentionally relies upon overflow semantics; e.g., cryptographic code or fast hash functions.
Related-Dynamic • SAGE: most related, dynamic test generation with bug-seeking queries for integer overflow, underflow, and some narrowing conversion errors. • SmartFuzz(ours): looks at a wider range of narrowing conversion errors, and we consider signed/unsigned conversion while their work does not.
Related-Dynamic(2) • KLEE: focuses on scaling dynamic test generation, but in a different way. KLEE focuses on high code coverage for over 450 smaller programs, as measured by trace size and source lines of code. • Ours: focus on a few “large” programs • KLEE & EXE: also use integer overflow to prioritize different test cases in dynamic test generation, but they do not break out results on the number of bugs found due to this heuristic. • These previous works also do not address the problem of type inference for integer types in binary traces.
Related-Dynamic(3) • IntScope : is a static binary analysis tool for finding integer overflow bugs [28]. • IntScope translates binaries to an intermediate representation, then it checks lazily for potentially harmful integer overflows by using symbolic execution for data that flows into “taint sinks” defined by the tool, such as memory allocation functions. • Smart-Fuzz: in contrast, eagerlyattempts to generate new test cases that cause an integer bug at the point in the program where such behavior could occur. • This difference is due in part to the fact that IntScope reports errors to a programmer directly, while SmartFuzz filters test cases using a tool such as memcheck. • Finally, IntScope focuses only on integer overflow errors, while SmartFuzz covers underflow,narrowing conversion, and signed/unsigned conversion bugs in addition.
Related-Dynamic(4) • BitBlaze [5]: • Also performs symbolic execution of x86 binaries, but their focus is on malware and signature signature generation, not on test generation.
What’s new • new methods for finding integer bugs in dynamic test generation • Extended integer bugs • bug bucketing-fuzzy stack hash: report techniques for reducing the amount of human time required to process test cases generated by fuzzing and improve the quality of our error reports to developers
Components • SmartFuzz: test case generation, bug finding. • Metafuzz: bug report
Architecture • symbolic execution • solving to obtain new test cases • triage to determine whether to report a bug or score the test case for addition to the pool of unexplored test cases.
First, we add one or more test cases to a pool(seed). Each test case in the pool receives a score given by the number of new basic blocks seen when running the target program on the test case.
In each iteration of test generation, we choose a highscoring test case, execute the program on that input, and use symbolic execution to generate a set of constraints that record how each intermediate value computed by the program relates to the inputs(tainted) in the test case.
For each symbolic branch, SmartFuzz adds a constraint that tries to force the program down a different path. • We then query the constraint solver to see whether there exists any solution to the resulting set of constraints; • if there is, the solution describes a new test case. We refer to these as coverage queriesto the constraint solver.
Queries • coverage queries find new test case cover more basic blocks. • bug-seeking queries SmartFuzz also injects constraints that are satisfied if a condition causing an error or potential error is satisfied (e.g., to force an arithmetic calculation to overflow).We then query the constraint solver; a solution describes a test case likely to cause an error. • A single symbolic execution therefore leads to many coverage and bug-seeking queries to the constraint solver, which may result in many new test cases.
Determine if it exhibits a bug. If so, we report the bug; otherwise, we add the test case to the pool for scoring and possible symbolic execution. • Valgrind memcheck on the target program with each test case, which is a tool that observes concrete execution looking for common programming errors [26]. We record any test case that causes the program to crash or triggers a memcheck warning.
Integer Bugs • Overflow/Underflow • Width Conversions • Signed/Unsigned Conversions • Memcpy: additional monitor “memcpy”’s length argument (unsigned constraint)
Overflow/Underflow • char *badalloc(int sz, int n) { • return (char *) malloc(sz * n); • } • If the multiplication sz * n overflows, the allocated buffer may be smaller than expected, which can lead to a buffer overflow later.
Width Conversions • void badcpy(Int16 n, char *p, char *q) { • UInt32 m = n; //n is negative • memcpy(p, q, m); • } • Converting a value of one integral type to a wider (or narrower) integral type which has a different range of values can introduce width conversion bugs.
Signed/Unsigned Conversion void bad(int x,char * src,char * dst) { if (x > 800) What if x == -1 ? { return; } else { copy_bytes(unsigned int x,... copy_bytes(x,src, dst); } }
memcpy • SmartFuzz also add unsigned type constraints to values used as the length argument of memcpy function. • which we can detect because we know the calling convention for x86 and we have debugging symbols for glibc.
Techniques for Finding Integer Bugs Unknown/Top • Idea: • 1. Keep track of type for every tainted program value(For x86 binaries, the sources of type constraints are signed and unsigned comparison operators) • 2. Use solver to force values with type “Bottom” to equal • -1(negative values behave differently in signed andunsigned comparisons, and so they are likely to exhibit an error if one exists.) Signed Unsigned Potential Bug/Bottom
Metafuzz: Triage and reporting at scale • Existing report way: computed a stack hash as a hash of the sequence of instruction pointers in the backtrace. • Problem: • 1. it is sensitive to address space layout randomization (ASLR), because different runs of the same program may load the stack or dynamically linked libraries at different addresses, leading to different hash values for call stacks that are semantically the same. • 2. a single bug might be triggered at multiple call stacks that were similar but not identical. For example,a buggy function can be called in several different places in the code. Each call site then yields a different stack hash. • 3. any slight change to the target software can change instruction pointers and thus cause the same bug to receive a different stack hash.
Fuzzy stack hash • The name of the function called, the line number in source code (debug symbol information) • name of the object file for each frame in the call stack • then hash all of this information for the three(trade-off) functions at the top of the call stack
Results • Test Programs.: • mplayer version SVN-r28403-4.1.2, ffmpeg version SVN-r16903, • exiv2 version SVN-r1735, • gzip version 1.3.12, • bzip2 version 1.0.5, • ImageMagick convert version 6.4.8-10, which are all widely used media and compression programs.
Size information of program • source lines of code • size of one of our seed files • total number of branches • x86 instructions • Valgrind IR statements • STP assert statements • STP query statements
The number of each type of query for each test program after a single 24-hour run.
The number of bugs found, by query type, over all test runs. The fourth column shows the number of distinct bugs found from test cases produced by the given type of query, as classified using our fuzzy stack hash.
The number of bugs, after fuzzy stack hashing, found by SmartFuzz (the number on the left in each column) and zzuf (the number on the right). We also report the cost per bug, assuming $0:10 per small compute-hour, $0:40 per large compute-hour, and 3 runs of 24 hours each per target for each tool. • Different bugs found by SmartFuzz and zzuf
Coverage metrics: the initial number of basic blocks, before testing; the number of blocks added during testing; and the percentage of blocks added. • Zzuf added a higher percentage of new blocks than Smart-Fuzz in 13 of the test runs, while SmartFuzz added a higher percentage of new blocks in 4 of the test runs
The percentage of time spent in each of the phases of SmartFuzz.
Solver Statistics • Solver optimization: just select the tainted variable. • average query size before and after related constraint optimization for each test program.
ECD( empirical cumulative distribution) function of STP solver times over all our test runs. For about 70% of the test cases, the solver takes at most one second. The maximum solver time was about 10.89 seconds.
Other Design Choice • Intermediate Representation :on-the-fly • Online Constraint Generation: not aware of off-line. • Memory Model: concrete value->symbolic • Only Tainted Data is Symbolic: small size • Focus on Fuzzing Files: Single Threaded Program.
Conclusion • new methods for finding integer bugs in dynamic test generation • reported on our experiences building the web site metafuzz.com and using it to manage test case generation at scale. • Smart-Fuzz finds bugs not found by zzuf and vice versa • Can find integer bugs without the false positives inherent to static analysis or runtime checking approaches • scale to commodity Linux media playing software