cargo-fuzz
cargo-fuzz copied to clipboard
lazy_static triggers AddressSanitizer errors
In https://github.com/BurntSushi/rust-snappy/issues/5, it looks like the error is coming from Lazy::get()
.
This possibly has the same root cause as #81, but I don't know enough about how lazy_static
works to be able to say for sure.
# Cargo.toml
[package]
name = "lazy_static_asan"
version = "0.0.0"
[dependencies]
lazy_static = "0.2.4"
libfuzzer-sys = {git = "https://github.com/rust-fuzz/libfuzzer-sys.git"}
[[bin]]
name = "read_lazy_static"
path = "read_lazy_static.rs"
// read_lazy_static.rs
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref FOO: usize = 100;
}
fuzz_target!(|_data| {
*FOO;
});
$ RUSTFLAGS=" -Cpasses=sancov -C llvm-args=-sanitizer-coverage-level=3 -Z sanitizer=address" ASAN_OPTIONS=detect_odr_violation=0 cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/read_lazy_static`
INFO: Seed: 2346919122
INFO: Loaded 0 modules (0 guards):
INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus
#0 READ units: 1
=================================================================
==29177==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd05da7e48 at pc 0x562a48d2c797 bp 0x7ffd05da7e10 sp 0x7ffd05da7e08
ACCESS of size 0 at 0x7ffd05da7e48 thread T0
#0 0x562a48d2c796 in lazy_static::lazy::{{impl}}::get<usize,fn() -> usize> /home/dwrensha/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-0.2.4/src/lazy.rs:15
#1 0x562a48d2c796 in read_lazy_static::{{impl}}::deref::__stability /home/dwrensha/Desktop/test-standalone-lazy-static/<__lazy_static_internal macros>:21
#2 0x562a48d2c796 in _$LT$read_lazy_static..FOO$u20$as$u20$core..ops..Deref$GT$::deref::hef6f026c6ae9fad2 /home/dwrensha/Desktop/test-standalone-lazy-static/<__lazy_static_internal macros>:22
#3 0x562a48d2cc11 in rust_fuzzer_test_input /home/dwrensha/Desktop/test-standalone-lazy-static/read_lazy_static.rs:16
#4 0x562a48d5554a in libfuzzer_sys::test_input_wrap::_$u7b$$u7b$closure$u7d$$u7d$::h01afe675cf6a0c88 /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/src/lib.rs:13
#5 0x562a48d534bf in std::panicking::try::do_call::hfeac5113da58e53b /checkout/src/libstd/panicking.rs:454
#6 0x562a48d7aa3a in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
#7 0x562a48d52b4b in std::panicking::try::h6164876e479a9388 /checkout/src/libstd/panicking.rs:433
#8 0x562a48d525ec in std::panic::catch_unwind::h696c6b58c620fbac /checkout/src/libstd/panic.rs:361
#9 0x562a48d5500b in LLVMFuzzerTestOneInput /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/src/lib.rs:11
#10 0x562a48d4af44 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/llvm/lib/Fuzzer/FuzzerLoop.cpp:550
#11 0x562a48d4a942 in fuzzer::Fuzzer::ShuffleAndMinimize(std::vector<std::vector<unsigned char, std::allocator<unsigned char> >, std::allocator<std::vector<unsigned char, std::allocator<unsigned char> > > >*) /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/llvm/lib/Fuzzer/FuzzerLoop.cpp:477
#12 0x562a48d3138b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/llvm/lib/Fuzzer/FuzzerDriver.cpp:565
#13 0x562a48d2cfae in main /home/dwrensha/.cargo/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/36a3928/llvm/lib/Fuzzer/FuzzerMain.cpp:20
#14 0x7fcaba6ba400 in __libc_start_main (/lib64/libc.so.6+0x20400)
#15 0x562a48d28e19 in _start (/home/dwrensha/Desktop/test-standalone-lazy-static/target/debug/read_lazy_static+0xee19)
Address 0x7ffd05da7e48 is located in stack of thread T0 at offset 40 in frame
#0 0x562a48d2a7df in _$LT$lazy_static..lazy..Lazy$LT$T$GT$$GT$::get::hddf7c5d5397fb854 /home/dwrensha/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-0.2.4/src/lazy.rs:10
This frame has 3 object(s):
[32, 40) 'arg' <== Memory access at offset 40 is inside this variable
[64, 72) '_8'
[96, 104) 'r'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/dwrensha/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-0.2.4/src/lazy.rs:15 in lazy_static::lazy::{{impl}}::get<usize,fn() -> usize>
Shadow bytes around the buggy address:
0x100020bacf70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacf90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacfa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacfb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100020bacfc0: 00 00 00 00 f1 f1 f1 f1 00[f2]f2 f2 00 f2 f2 f2
0x100020bacfd0: 00 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacfe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100020bacff0: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
0x100020bad000: 00 00 f2 f2 00 00 f3 f3 00 00 00 00 00 00 00 00
0x100020bad010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==29177==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000
artifact_prefix='./'; Test unit written to ./crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
Base64:
@Manishearth has anyone reported the zero-sized issue upstream to LLVM?
We would need a minimized test case in form of LLVM-IR or C if we want to report it upstream.
in form of LLVM-IR
I'm mildly comfortable with LLVM IR; but always in very constrained environments like microcontrollers. Any suggestions on how to take a piece of IR and and run it through ASan?
Interestingly, running the fuzzer with optimizations on (cargo fuzz run --release fuzzer_script_1
) appears to avoid the first few cases of this that I've run into (presumably the zero-sized loads disappear)
No idea, sorry. I guess you’d start by finding a minimal rust program which results in the issue when fuzzed/sanitised. Taking LLVM-IR of that and running it through opt
and/or llc
with instrumentation pass enabled would produce instrumented LLVM-IR/object file which then could be used to reproduce the issue.
a minimal rust program which results in the issue when fuzzed/sanitised
Minimal is the tricky part. I can get the IR corresponding to the example here compiled with via the fuzzer options (so it's pre-instrumented), but that wants to link against the Rust standard library (and the fuzzer dylib). As-is, that's ~300k of LLVM IR, which isn't really minimal.
@shepmaster maybe you can use bugpoint?
FWIW, in my program that just hit this, running fuzzing the --release build indeed avoids the problem.
@cmr perhaps! I've only used bugpoint to debug issues earlier in the LLVM pipeline (transforming LLVM IR to machine code) so that having an actual runnable program was never a concern :-)
The other issue is that I'm guessing part of the error occurs due to code in the standard library (lazy_static uses atomics and InitOnce
, IIRC), which is unlikely to show up in the resulting IR. All that said, it's worth a try.
Any idea if the LLVM folk would accept a testcase that is "please link against Rust's stdlib"?
Any idea if the LLVM folk would accept a testcase that is "please link against Rust's stdlib"?
Unlikely.