Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions src/decompress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,20 +187,27 @@ impl<'s, 'd> Decompress<'s, 'd> {
// When the length is bigger than 60, it indicates that we need to read
// an additional 1-4 bytes to get the real length of the literal.
if len >= 61 {
// If there aren't at least 4 bytes left to read then we know this
// is corrupt because the literal must have length >=61.
if self.s as u64 + 4 > self.src.len() as u64 {
let byte_count = len as usize - 60;
// Only require the number of length bytes selected by the tag.
if self.src.len() - self.s < byte_count {
return Err(Error::Literal {
len: 4,
len: byte_count as u64,
src_len: (self.src.len() - self.s) as u64,
dst_len: (self.dst.len() - self.d) as u64,
});
}
// Since we know there are 4 bytes left to read, read a 32 bit LE
// integer and mask away the bits we don't need.
let byte_count = len as usize - 60;
len = bytes::read_u32_le(&self.src[self.s..]) as u64;
len = (len & (WORD_MASK[byte_count] as u64)) + 1;
// Keep the fast 32-bit load when it is in bounds. Near the end of
// the input, read only the selected 1-4 little-endian bytes.
if self.src.len() - self.s >= 4 {
len = bytes::read_u32_le(&self.src[self.s..]) as u64;
len = (len & (WORD_MASK[byte_count] as u64)) + 1;
} else {
len = 0;
for i in 0..byte_count {
len |= (self.src[self.s + i] as u64) << (8 * i);
}
len += 1;
}
self.s += byte_count;
}
// If there's not enough buffer left to load or store this literal,
Expand Down Expand Up @@ -361,7 +368,9 @@ impl Header {
#[inline(always)]
fn read(input: &[u8]) -> Result<Header> {
let (decompress_len, header_len) = bytes::read_varu64(input);
if header_len == 0 {
// The uncompressed length is a uint32 varint, which uses at most 5
// bytes in the reference implementation.
if header_len == 0 || header_len > 5 {
return Err(Error::Header);
}
if decompress_len > MAX_INPUT_SIZE {
Expand Down
5 changes: 2 additions & 3 deletions test/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,11 @@ testerrored!(
&b"\x02\xechi"[..],
Error::Literal { len: 60, src_len: 2, dst_len: 2 }
);
// A literal whose length is too big, requires 1 extra byte to be read, and
// src is too short to read that byte.
// A literal whose extended length byte declares more data than is available.
testerrored!(
err_lit_big2a,
&b"\x02\xf0hi"[..],
Error::Literal { len: 4, src_len: 2, dst_len: 2 }
Error::Literal { len: 105, src_len: 1, dst_len: 2 }
);
// A literal whose length is too big, requires 1 extra byte to be read,
// src is too short to read the full literal.
Expand Down
Loading