BurntSushi / rust-snappy

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

Integer overflow in bounds check on 32-bit targets #3

Closed stur closed 8 years ago

stur commented 8 years ago

On 64-bit there is no problem.

Cause of the bug: https://github.com/BurntSushi/rust-snappy/blob/99e7b31791c456df17bcbf5f2edada2b2c84383b/src/decompress.rs#L214

Code to produce panic in debug mode and segfault in release mode:

extern crate snap;

fn main()
{
    let mut decoder = snap::Decoder::new();
    let corrupt_data = generate_overflowing_compressed();
    let _decompressed = decoder.decompress_vec(corrupt_data.as_slice()).unwrap();
}

fn generate_overflowing_compressed() -> Vec<u8>
{
    let mut overflowing: Vec<u8> = Vec::new();

    // Header; output size doesn't matter
    write_varu64_to_vec(&mut overflowing, 1234);

    // We need one valid literal to trigger segfault
    overflowing.push(0x00);
    overflowing.push(0x00);

    // Invalid literal with length 2^32-1
    overflowing.push(0b11_11_11_00);
    overflowing.push(0xFE); // 1 will be added to length
    overflowing.push(0xFF);
    overflowing.push(0xFF);
    overflowing.push(0xFF);

    overflowing
}

fn write_varu64_to_vec(data: &mut Vec<u8>, mut n: u64)
{
    while n >= 0b1000_0000 {
        data.push((n as u8) | 0b1000_0000);
        n >>= 7;
    }
    data.push(n as u8);
}
BurntSushi commented 8 years ago

Great find. I've fixed this and released it to crates.io in snap 0.1.2.