Integrating libFuzzer with ASan and UBSan in Chromium
This article provides an overview of how the Chromium project combines libFuzzer with AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan) to automate vulnerability discovery. By integrating this coverage-guided fuzzing engine with compiler-based sanitizers at the build level, Chromium developers can continuously feed mutated inputs into specific browser components and immediately detect hidden memory corruption and undefined behavior before code reaches production.
The Synergy Between Fuzzing and Sanitizers
On its own, libFuzzer is an in-process, coverage-guided evolutionary fuzzing engine. It feeds massive amounts of random and mutated data into a specific function to see if the program crashes. However, many severe security bugs do not cause an immediate crash; a slight buffer over-read or a signed integer overflow might silently corrupt data and allow the program to continue running.
This is where ASan and UBSan are essential. By compiling the fuzz target with these sanitizers, silent bugs are turned into immediate, noisy crashes:
- libFuzzer navigates the code paths and generates the edge-case inputs.
- AddressSanitizer (ASan) monitors memory operations to catch out-of-bounds accesses, use-after-free bugs, and memory leaks.
- UndefinedBehaviorSanitizer (UBSan) monitors operations to catch illegal code behavior, such as using misaligned pointers, dividing by zero, or triggering signed integer overflows.
Build-Time Integration via Clang and GN
Because libFuzzer, ASan, and UBSan are all part of the LLVM compiler infrastructure, their integration in Chromium happens seamlessly at compile time using the Clang compiler and Chromium’s meta-build system, GN (Generate Ninja).
- Defining the Target: A Chromium developer writes a
fuzz target—a C++ function named
LLVMFuzzerTestOneInputthat accepts a raw byte array and passes it to the Chromium API being tested. In theBUILD.gnfile, this is defined using thefuzzer_testtemplate. - Configuring Build Flags: To integrate the tools,
the build environment is configured using GN arguments
(
args.gn). The build system setsuse_libfuzzer = truealongside eitheris_asan = trueoris_ubsan = true(or both). - Compiler Instrumentation: When Clang compiles the
target, it performs two types of instrumentation simultaneously. First,
it inserts
SanitizerCoveragecallbacks at the edges of basic blocks so libFuzzer can track which code paths are hit. Second, it inserts ASan's shadow-memory checks around every memory access and UBSan's runtime checks around potentially undefined arithmetic and type operations.
Runtime Execution Flow
Once the binary is compiled, the fuzzing engine and the sanitizers operate within the same process space. The execution follows a strict loop:
- Input Generation: libFuzzer generates a mutated
data buffer in memory and passes it to
LLVMFuzzerTestOneInput. - Code Execution and Coverage Tracking: As the
Chromium component processes the data, the
SanitizerCoverageinstrumentation reports back to libFuzzer which branches of code were executed. If the input triggers a newly discovered code path, libFuzzer saves that input to its corpus for future mutations. - Sanitizer Monitoring: During that exact same
execution, ASan replaces the standard
mallocandfreefunctions, surrounding allocated memory with poisoned "redzones." Simultaneously, UBSan validates that operations adhere to the C++ specification. - Fault Interception: If a mutated input causes the Chromium code to touch an ASan redzone or violate a UBSan rule, the respective sanitizer immediately halts execution.
Crash Reporting and ClusterFuzz
When ASan or UBSan halts the program, it intercepts the crash Signal
(like SIGSEGV or SIGABRT) and outputs a
detailed symbolized stack trace pointing to the exact line of offending
code.
Because libFuzzer shares the process, its internal signal handlers
catch the sanitizer's abort routine. libFuzzer then takes the exact byte
array that was in memory at the moment of the sanitizer violation and
writes it to the disk as a crash artifact (e.g.,
crash-1a2b3c...).
In the Chromium ecosystem, this entire process is automated at scale
using ClusterFuzz, Google’s distributed fuzzing
infrastructure. ClusterFuzz compiles thousands of Chromium
fuzzer_test targets with ASan and UBSan enabled, runs them
continuously on virtual machines, collects the crash artifacts generated
by the libFuzzer-sanitizer integration, deduplicates the findings, and
automatically files detailed bug reports in the Chromium issue
tracker.