Table of Contents
Fetching ...

SAND: Decoupling Sanitization from Fuzzing for Low Overhead

Ziqiao Kong, Shaohua Li, Heqing Huang, Zhendong Su

TL;DR

The paper tackles the high overhead of sanitizers in fuzzing by decoupling sanitization from the fuzzing loop. It introduces Sand, which fuzzes normally built binaries and only runs sanitizer-enabled inputs that exhibit unique execution patterns, as detected from the fuzzing bitmap via an inexpensive execution-pattern proxy. Through extensive evaluation on 20 real-world programs (implemented atop AFL++) with ASan, UBSan, and MSan, Sand finds more bugs than all baselines within 24 hours and does not miss any, while achieving near-native fuzzing throughput. The key contributions include the formalization of execution patterns, the design of conditional sanitization, and a practical, sanitizer-agnostic implementation with broad compatibility, offering a scalable path to deploying sanitizers in fuzzing without prohibitive overhead.

Abstract

Sanitizers provide robust test oracles for various software vulnerabilities. Fuzzing on sanitizer-enabled programs has been the best practice to find software bugs. Since sanitizers need to heavily instrument a target program to insert run-time checks, sanitizer-enabled programs have much higher overhead compared to normally built programs. In this paper, we present SAND, a new fuzzing framework that decouples sanitization from the fuzzing loop. SAND performs fuzzing on a normally built program and only invokes sanitizer-enabled programs when input is shown to be interesting. Since most of the generated inputs are not interesting, i.e., not bug-triggering, SAND allows most of the fuzzing time to be spent on the normally built program. To identify interesting inputs, we introduce execution pattern for a practical execution analysis on the normally built program. We realize SAND on top of AFL++ and evaluate it on 12 real-world programs. Our extensive evaluation highlights its effectiveness: in 24 hours, compared to all the baseline fuzzers, SAND significantly discovers more bugs while not missing any.

SAND: Decoupling Sanitization from Fuzzing for Low Overhead

TL;DR

The paper tackles the high overhead of sanitizers in fuzzing by decoupling sanitization from the fuzzing loop. It introduces Sand, which fuzzes normally built binaries and only runs sanitizer-enabled inputs that exhibit unique execution patterns, as detected from the fuzzing bitmap via an inexpensive execution-pattern proxy. Through extensive evaluation on 20 real-world programs (implemented atop AFL++) with ASan, UBSan, and MSan, Sand finds more bugs than all baselines within 24 hours and does not miss any, while achieving near-native fuzzing throughput. The key contributions include the formalization of execution patterns, the design of conditional sanitization, and a practical, sanitizer-agnostic implementation with broad compatibility, offering a scalable path to deploying sanitizers in fuzzing without prohibitive overhead.

Abstract

Sanitizers provide robust test oracles for various software vulnerabilities. Fuzzing on sanitizer-enabled programs has been the best practice to find software bugs. Since sanitizers need to heavily instrument a target program to insert run-time checks, sanitizer-enabled programs have much higher overhead compared to normally built programs. In this paper, we present SAND, a new fuzzing framework that decouples sanitization from the fuzzing loop. SAND performs fuzzing on a normally built program and only invokes sanitizer-enabled programs when input is shown to be interesting. Since most of the generated inputs are not interesting, i.e., not bug-triggering, SAND allows most of the fuzzing time to be spent on the normally built program. To identify interesting inputs, we introduce execution pattern for a practical execution analysis on the normally built program. We realize SAND on top of AFL++ and evaluate it on 12 real-world programs. Our extensive evaluation highlights its effectiveness: in 24 hours, compared to all the baseline fuzzers, SAND significantly discovers more bugs while not missing any.
Paper Structure (19 sections, 10 figures, 6 tables, 2 algorithms)

This paper contains 19 sections, 10 figures, 6 tables, 2 algorithms.

Figures (10)

  • Figure 1: A simplified Use-after-Free bug from libtiff in CVE-2023-26965. Line 17 triggers the bug because the freed buffer in line 1 is reallocated neither in line 5 nor in lines 8 and 11.
  • Figure 2: A simplified Buffer-Overflow bug from wav2swf in CVE-2017-11099. Line 8 triggers a buffer overflow when the for loops significantly change the buffer offset "pos2+j".
  • Figure 3: A simplified Integer-Overflow bug from xpdf (containing pdftotext) in CVE-2022-38171. Line 9 triggers an integer overflow in numSyms when the if branch in line 8 is evaluated to True many times.
  • Figure 4: Executions (left) are recorded by bitmap (middle), which are used in AFL++ to update the coverage map (right). Our execution patterns can be derived from these bitmaps.
  • Figure 4: Number of unique bugs found by each fuzzer. "Total" row shows the total number of unique bugs. "$\textsc{Sand}\xspace-$" means the number of bugs missed by Sand. "$\textsc{Sand}\xspace+$" means the number of bugs additionally covered by Sand.
  • ...and 5 more figures

Theorems & Definitions (2)

  • Definition 3.1: Execution Path
  • Definition 3.2: Execution Pattern