sile / libflate

A Rust implementation of DEFLATE algorithm and related formats (ZLIB, GZIP)
https://docs.rs/libflate
MIT License
178 stars 35 forks source link

Decoder may expose contents of uninitialized memory in the output #33

Closed Shnatsel closed 5 years ago

Shnatsel commented 5 years ago

libflate might expose contents of uninitialized memory in the output when given a crafted input. This may be a devastating vulnerability in some contexts, e.g. if used as deflate backend for a PNG decoder. Details and impact analysis for similar bugs in PNG decoders in C can be found here.

I am confident that a private function is vulnerable, but I am not sure if this vulnerability can be exploiter by supplying a malformed input; there could be some non-local checks that prevent it.

I shall relay further details on the issue to the maintainer privately by email.

sile commented 5 years ago

I have received the email. Thanks!

Shnatsel commented 5 years ago

This was fixed by #38. The bug is in the following code: https://github.com/sile/libflate/blob/71d12d2b3451cfa9f8cd540f4b91c4e1292d21fe/src/deflate/decode.rs#L107-L127 This code never checks that distance is not 0. If it is and length is > 0, the following happens:

This may be a devastating vulnerability in some contexts, e.g. if used as deflate backend for a PNG decoder. Details and impact analysis for similar bugs in PNG decoders in C can be found here.

I am confident that this private function is vulnerable, but I am not sure if this vulnerability can be exploited by supplying a malformed input - there might be some non-local checks that prevent it.

Please fix the bug and check if it's possible to trigger it through a crafted input file, either via setting distance to 0 or via overflowing distance. If it is indeed possible, please file a security advisory at https://github.com/RustSec/advisory-db

sile commented 5 years ago

there might be some non-local checks that prevent it.

Yes. The value of distance is detemined by Decoder::decode_distance method (https://github.com/sile/libflate/blob/master/src/deflate/symbol.rs#L224). The method refers to DISTANCE_TABLE constant to look up the values of base (range: 1..=24_557) and extra_bits (range: 0..=13) variables, and returns base + ${read extra_bits from bits-stream) as the distance value. So the minimum value of distance is 1, and the maximum value is 24_577 + ((1<<13) - 1) = 32_768 < std::u16::MAX.

Shnatsel commented 5 years ago

Thanks! I'm closing this issue then.

sile commented 5 years ago

Thank you very much for your contribution!