Closed 5225225 closed 3 years ago
I don't think a very large compressed_size
is an issue since the bitbuffer
will check that there are compressed_size - 4
bytes in the table data before allocating the buffer.
Looks like it's not bitbuffer, it's the compressed data. https://docs.rs/snap/1.0.5/snap/raw/struct.Decoder.html#method.decompress_vec is being used. Maybe instead we should use https://docs.rs/snap/1.0.5/snap/read/struct.FrameDecoder.html and limit the amount of bytes we're willing to read to something reasonable?
In any case, this will OOM it.
oom-6cba3d29efefe05228de10e9e770d6544a8eb1e9.zip
My copy of the fuzzer looks like
#![no_main]
use libfuzzer_sys::fuzz_target;
pub use tf_demo_parser::{Demo, DemoParser, Parse, ParseError, ParserState, Stream};
fuzz_target!(|data: &[u8]| {
let demo = Demo::new(&data);
let parser = DemoParser::new_all(demo.get_stream());
let _ = parser.parse();
});
and the stack trace for the OOM is
Running: oom-6cba3d29efefe05228de10e9e770d6544a8eb1e9
==3992646== ERROR: libFuzzer: out-of-memory (malloc(2164285209))
To change the out-of-memory limit use -rss_limit_mb=<N>
#0 0x5645b86b6241 in __sanitizer_print_stack_trace /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:86:3
#1 0x5645b9101cf8 in fuzzer::PrintStackTrace() (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe4ecf8)
#2 0x5645b90dccb7 in fuzzer::Fuzzer::HandleMalloc(unsigned long) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe29cb7)
#3 0x5645b90dcd21 in fuzzer::MallocHook(void const volatile*, unsigned long) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe29d21)
#4 0x5645b86bc547 in __sanitizer::RunMallocHooks(void const*, unsigned long) /rustc/llvm/src/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp:301:5
#5 0x5645b8633720 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_allocator.cpp:611:5
#6 0x5645b86338d9 in Calloc /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_allocator.cpp:748:17
#7 0x5645b86338d9 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_allocator.cpp:984:34
#8 0x5645b86adb23 in calloc /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:155:10
#9 0x5645b8b46c76 in snap::decompress::Decoder::decompress_vec::h810688ab8033e1b2 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x893c76)
#10 0x5645b8a2894c in _$LT$tf_demo_parser..demo..message..stringtable..CreateStringTableMessage$u20$as$u20$tf_demo_parser..demo..parser..Parse$GT$::parse::hb29ee8e106992416 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x77594c)
#11 0x5645b8a3e0d6 in tf_demo_parser::demo::message::Message::from_type::ha1f9ff6e4102b563 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x78b0d6)
#12 0x5645b8a5525c in tf_demo_parser::demo::packet::message::MessageIterator::next::h15af4754be65372f (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x7a225c)
#13 0x5645b86e1d79 in tf_demo_parser::demo::parser::handler::DemoHandler$LT$T$GT$::handle_packet::ha2db951a9c5c4263 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x42ed79)
#14 0x5645b86df2f4 in tf_demo_parser::demo::parser::DemoParser$LT$A$GT$::parse::h8ee8545cd567cbf6 (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x42c2f4)
#15 0x5645b8721c0f in rust_fuzzer_test_input (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x46ec0f)
#16 0x5645b90e6520 in __rust_try (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe33520)
#17 0x5645b90e617f in LLVMFuzzerTestOneInput (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe3317f)
#18 0x5645b90dd3c4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe2a3c4)
#19 0x5645b90d180a in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe1e80a)
#20 0x5645b90d5462 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0xe22462)
#21 0x5645b8631cf2 in main (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x37ecf2)
#22 0x7f6570b81b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
#23 0x5645b8631e9d in _start (/home/jess/.cache/cargo/target/x86_64-unknown-linux-gnu/release/fuzz_target_1+0x37ee9d)
SUMMARY: libFuzzer: out-of-memory
────────────────────────────────────────────────────────────────────────────────
Error: Fuzz target exited with exit code: 71
edit:
I did try fuzzing snap
directly with decompress_to_vec, and you can easily OOM with that. So you can only use that method if you trust the input data.
Ah yes, I didn't think about the decompression step itself, bb79d26 adds some hard limits for compressed and decompressed size (10mb and 100mb)
The demo file is rather large and I couldn't minify it, but I've attached it anyways.
crash.zip
The crash is
https://github.com/demostf/parser/blob/e2a631cef3462dcb299822c2671abc8e708646c6/src/demo/message/stringtable.rs#L57 , if
compressed_size
is less than 4, it will either panic on wraparound with debug assertions enabled, or tries to allocate a huge amount of memory in release mode, and aborts. (This could probably be used cause a denial of service by trying to allocate large buffers).The fix here IMO is to do a checked subtraction there, but also not to trust the value we got from the file for the compressed size. That might be a change in
bitbuffer
too, which should have tests that trying to read huge amounts of data doesn't crash, and instead returns an error, which it doesn't seem to be doing.