BurntSushi / rust-snappy

Snappy compression implemented in Rust (including the Snappy frame format).
BSD 3-Clause "New" or "Revised" License
444 stars 43 forks source link

Heap buffer overflow #12

Closed rikardfalkeborn closed 6 years ago

rikardfalkeborn commented 7 years ago

Found using cargo-fuzz:

To reproduce, add the following test case in src/tests.rs

// Crashes found with fuzzing
testerrored!(err_heap_buffer_overflow, &b"\x23\x00\x00\x04\x00\xff\x01\x03\x01\x03\x03\x03\x00\x00\x00\xfc\xc4\xff\x01\x03"[..],
             Error::Literal {
                 len: 50462661,
                 src_len: 0,
                 dst_len: 23,
             });

To run under Linux (this requires a nightly build): RUSTFLAGS="-Zsanitizer=address" ASAN_OPTIONS=detect_odr_violation=0 cargo test --target x86_64-unknown-linux-gnu Note that the test passes if not running with Address Sanitizer.

=================================================================

==6875==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x604000006033 at pc 0x559a2e2cf009 bp 0x7f94747fc790 sp 0x7f94747fbf40                                                                    
WRITE of size 16 at 0x604000006033 thread T40 (tests::err_heap)                                       
    #0 0x559a2e2cf008 in __asan_memmove /checkout/src/libcompiler_builtins/compiler-rt/lib/asan/asan_interceptors.cc:461
    #1 0x559a2db04bc7 in snap::decompress::{{impl}}::read_copy /home/rikard/code/rust-snappy/src/decompress.rs:317
    #2 0x559a2db04bc7 in snap::decompress::Decompress::decompress::h74fcb923230eef32 /home/rikard/code/rust-snappy/src/decompress.rs:143
    #3 0x559a2db02eb1 in snap::decompress::Decoder::decompress::h8d4cf6fc6f8a2c36 /home/rikard/code/rust-snappy/src/decompress.rs:98
    #4 0x559a2db32750 in snap::tests::err_heap_buffer_overflow::hf80b5d87bb01e9a2 /home/rikard/code/rust-snappy/src/tests.rs:114
    #5 0x559a2e1e4041 in test::run_test::{{closure}} /checkout/src/libtest/lib.rs:1478
    #6 0x559a2e1e4041 in core::ops::function::FnOnce::call_once<closure,(())> /checkout/src/libcore/ops/function.rs:223
    #7 0x559a2e1e4041 in _$LT$F$u20$as$u20$test..FnBox$LT$T$GT$$GT$::call_box::h4cd0226556414a83 /checkout/src/libtest/lib.rs:139
    #8 0x559a2e2228cc in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #9 0x559a2e1d524c in std::panicking::try<(),std::panic::AssertUnwindSafe<closure>> /checkout/src/libstd/panicking.rs:459
    #10 0x559a2e1d524c in std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()> /checkout/src/libstd/panic.rs:361
    #11 0x559a2e1d524c in test::run_test::run_test_inner::{{closure}} /checkout/src/libtest/lib.rs:1417
    #12 0x559a2e1d524c in std::sys_common::backtrace::__rust_begin_short_backtrace::h13ca8dac9b7f5353 /checkout/src/libstd/sys_common/backtrace.rs:136
    #13 0x559a2e1d6012 in std::thread::{{impl}}::spawn::{{closure}}::{{closure}}<closure,()> /checkout/src/libstd/thread/mod.rs:394
    #14 0x559a2e1d6012 in std::panic::{{impl}}::call_once<(),closure> /checkout/src/libstd/panic.rs:296
    #15 0x559a2e1d6012 in std::panicking::try::do_call::hd57949c7b5b244b9 /checkout/src/libstd/panicking.rs:480
    #16 0x559a2e2228cc in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #17 0x559a2e1ddd12 in std::panicking::try<(),std::panic::AssertUnwindSafe<closure>> /checkout/src/libstd/panicking.rs:459
    #18 0x559a2e1ddd12 in std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()> /checkout/src/libstd/panic.rs:361
    #19 0x559a2e1ddd12 in std::thread::{{impl}}::spawn::{{closure}}<closure,()> /checkout/src/libstd/thread/mod.rs:393
    #20 0x559a2e1ddd12 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::hcecece177889931b /checkout/src/liballoc/boxed.rs:682
    #21 0x559a2e21a83b in alloc::boxed::{{impl}}::call_once<(),()> /checkout/src/liballoc/boxed.rs:692
    #22 0x559a2e21a83b in std::sys_common::thread::start_thread /checkout/src/libstd/sys_common/thread.rs:21
    #23 0x559a2e21a83b in std::sys::imp::thread::Thread::new::thread_start::h8596ddab359bf413 /checkout/src/libstd/sys/unix/thread.rs:84
    #24 0x7f9477d87048 in start_thread (/usr/lib/libpthread.so.0+0x7048)
    #25 0x7f94778b0f0e in __GI___clone (/usr/lib/libc.so.6+0xedf0e)

0x604000006033 is located 0 bytes to the right of 35-byte region [0x604000006010,0x604000006033)
allocated by thread T40 (tests::err_heap) here:                                                       
    #0 0x559a2e2e539d in calloc /checkout/src/libcompiler_builtins/compiler-rt/lib/asan/asan_malloc_linux.cc:74
    #1 0x559a2e222c6a in alloc_system::platform::{{impl}}::alloc_zeroed /checkout/src/liballoc_system/lib.rs:149
    #2 0x559a2e222c6a in __rg_alloc_zeroed /checkout/src/librustc_asan/lib.rs:27
    #3 0x559a2daeb8c3 in _$LT$alloc..heap..Heap$u20$as$u20$alloc..allocator..Alloc$GT$::alloc_zeroed::h0bce0d66bdc59af2 /checkout/src/liballoc/heap.rs:134
    #4 0x559a2dad7f09 in _$LT$alloc..raw_vec..RawVec$LT$T$C$$u20$A$GT$$GT$::allocate_in::hf46d911cf2794885 /checkout/src/liballoc/raw_vec.rs:95
    #5 0x559a2dad4dc8 in alloc::raw_vec::{{impl}}::with_capacity_zeroed<u8> /checkout/src/liballoc/raw_vec.rs:147
    #6 0x559a2dad4dc8 in _$LT$u8$u20$as$u20$alloc..vec..SpecFromElem$GT$::from_elem::hddc89846c51d523b /checkout/src/liballoc/vec.rs:1467
    #7 0x559a2db326d1 in alloc::vec::from_elem<u8> /checkout/src/liballoc/vec.rs:1446
    #8 0x559a2db326d1 in snap::tests::err_heap_buffer_overflow::hf80b5d87bb01e9a2 /home/rikard/code/rust-snappy/src/tests.rs:114
    #9 0x559a2e1e4041 in test::run_test::{{closure}} /checkout/src/libtest/lib.rs:1478
    #10 0x559a2e1e4041 in core::ops::function::FnOnce::call_once<closure,(())> /checkout/src/libcore/ops/function.rs:223
    #11 0x559a2e1e4041 in _$LT$F$u20$as$u20$test..FnBox$LT$T$GT$$GT$::call_box::h4cd0226556414a83 /checkout/src/libtest/lib.rs:139
    #12 0x559a2e2228cc in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #13 0x559a2e1d524c in std::panicking::try<(),std::panic::AssertUnwindSafe<closure>> /checkout/src/libstd/panicking.rs:459
    #14 0x559a2e1d524c in std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()> /checkout/src/libstd/panic.rs:361
    #15 0x559a2e1d524c in test::run_test::run_test_inner::{{closure}} /checkout/src/libtest/lib.rs:1417
    #16 0x559a2e1d524c in std::sys_common::backtrace::__rust_begin_short_backtrace::h13ca8dac9b7f5353 /checkout/src/libstd/sys_common/backtrace.rs:136
    #17 0x559a2e1d6012 in std::thread::{{impl}}::spawn::{{closure}}::{{closure}}<closure,()> /checkout/src/libstd/thread/mod.rs:394
    #18 0x559a2e1d6012 in std::panic::{{impl}}::call_once<(),closure> /checkout/src/libstd/panic.rs:296
    #19 0x559a2e1d6012 in std::panicking::try::do_call::hd57949c7b5b244b9 /checkout/src/libstd/panicking.rs:480
    #20 0x559a2e2228cc in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #21 0x559a2e1ddd12 in std::panicking::try<(),std::panic::AssertUnwindSafe<closure>> /checkout/src/libstd/panicking.rs:459
    #22 0x559a2e1ddd12 in std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()> /checkout/src/libstd/panic.rs:361
    #23 0x559a2e1ddd12 in std::thread::{{impl}}::spawn::{{closure}}<closure,()> /checkout/src/libstd/thread/mod.rs:393
    #24 0x559a2e1ddd12 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::hcecece177889931b /checkout/src/liballoc/boxed.rs:682
    #25 0x559a2e21a83b in alloc::boxed::{{impl}}::call_once<(),()> /checkout/src/liballoc/boxed.rs:692
    #26 0x559a2e21a83b in std::sys_common::thread::start_thread /checkout/src/libstd/sys_common/thread.rs:21
    #27 0x559a2e21a83b in std::sys::imp::thread::Thread::new::thread_start::h8596ddab359bf413 /checkout/src/libstd/sys/unix/thread.rs:84
    #28 0x7f9477d87048 in start_thread (/usr/lib/libpthread.so.0+0x7048)

Thread T40 (tests::err_heap) created by T0 here:
    #0 0x559a2e23ccf1 in __interceptor_pthread_create /checkout/src/libcompiler_builtins/compiler-rt/lib/asan/asan_interceptors.cc:305
    #1 0x559a2e21a505 in std::sys::imp::thread::Thread::new::h839f712eddd9ed31 /checkout/src/libstd/sys/unix/thread.rs:72
    #2 0x559a2e1f48d4 in std::thread::{{impl}}::spawn<closure,()> /checkout/src/libstd/thread/mod.rs:404
    #3 0x559a2e1f48d4 in test::run_test::run_test_inner::ha06748790ed0239c /checkout/src/libtest/lib.rs:1441
    #4 0x559a2e1f349a in test::run_test::h04d610473c4005ff /checkout/src/libtest/lib.rs:1477
    #5 0x559a2e1ec3b3 in test::run_tests<closure> /checkout/src/libtest/lib.rs:1133
    #6 0x559a2e1ec3b3 in test::run_tests_console::h176cb26f5f786689 /checkout/src/libtest/lib.rs:961
    #7 0x559a2e1e43bc in test::test_main::h6f6a791440c5d636 /checkout/src/libtest/lib.rs:288
    #8 0x559a2e1e4a95 in test::test_main_static::he789761c24fac0b3 /checkout/src/libtest/lib.rs:324
    #9 0x559a2e2228cc in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #10 0x559a2e21c05b in std::panicking::try<(),closure> /checkout/src/libstd/panicking.rs:459
    #11 0x559a2e21c05b in std::panic::catch_unwind<closure,()> /checkout/src/libstd/panic.rs:361
    #12 0x559a2e21c05b in std::rt::lang_start::hc026c6b655c62503 /checkout/src/libstd/rt.rs:61
    #13 0x7f94777e34c9 in __libc_start_main (/usr/lib/libc.so.6+0x204c9)

SUMMARY: AddressSanitizer: heap-buffer-overflow /checkout/src/libcompiler_builtins/compiler-rt/lib/asan/asan_interceptors.cc:461 in __asan_memmove
Shadow bytes around the buggy address:
  0x0c087fff8bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c087fff8c00: fa fa 00 00 00 00[03]fa fa fa fa fa fa fa fa fa
  0x0c087fff8c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff8c50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
==6875==ABORTING
BurntSushi commented 6 years ago

Fixed by #14