cargo-fuzz icon indicating copy to clipboard operation
cargo-fuzz copied to clipboard

lazy_static triggers AddressSanitizer errors

Open dwrensha opened this issue 7 years ago • 11 comments

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.

dwrensha avatar Mar 19 '17 16:03 dwrensha

# 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: 

dwrensha avatar Mar 19 '17 16:03 dwrensha

@Manishearth has anyone reported the zero-sized issue upstream to LLVM?

shepmaster avatar Apr 29 '17 18:04 shepmaster

We would need a minimized test case in form of LLVM-IR or C if we want to report it upstream.

nagisa avatar Apr 29 '17 18:04 nagisa

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?

shepmaster avatar Apr 30 '17 00:04 shepmaster

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)

shepmaster avatar Apr 30 '17 00:04 shepmaster

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.

nagisa avatar Apr 30 '17 00:04 nagisa

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 avatar Apr 30 '17 01:04 shepmaster

@shepmaster maybe you can use bugpoint?

emberian avatar May 02 '17 03:05 emberian

FWIW, in my program that just hit this, running fuzzing the --release build indeed avoids the problem.

emberian avatar May 02 '17 03:05 emberian

@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"?

shepmaster avatar May 02 '17 11:05 shepmaster

Any idea if the LLVM folk would accept a testcase that is "please link against Rust's stdlib"?

Unlikely.

whitequark avatar Jun 24 '17 10:06 whitequark