Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Malformed string compression table causes panic/abort in parser #2

Closed
5225225 opened this issue May 22, 2021 · 3 comments
Closed

Malformed string compression table causes panic/abort in parser #2

5225225 opened this issue May 22, 2021 · 3 comments

Comments

@5225225
Copy link

5225225 commented May 22, 2021

The demo file is rather large and I couldn't minify it, but I've attached it anyways.

crash.zip

The crash is

let compressed_data = table_data.read_bytes(compressed_size as usize - 4)?;
, 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.

@icewind1991
Copy link
Contributor

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.

@5225225
Copy link
Author

5225225 commented May 22, 2021

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.

@icewind1991
Copy link
Contributor

Ah yes, I didn't think about the decompression step itself, bb79d26 adds some hard limits for compressed and decompressed size (10mb and 100mb)

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants