Skip to content

Commit

Permalink
fix panic on malformed xref stream width
Browse files Browse the repository at this point in the history
If the xref stream specifies an entry width of 9, read_u64_from_stream() will
try to bitshift the u64 by `<< 8 * 9` which is invalid. Don't accept width that
don't fit into a u64.

If the xref stream specifies a valid width, but data is exhausted,
read_u64_from_stream() will cause an out of bound access and panic. Check if
we have enough bytes before reading.

Fix the function doc comment, the width is in bytes, not bits.
  • Loading branch information
Orycterope authored and s3bk committed Aug 2, 2024
1 parent 22ff7fd commit 3187677
Showing 1 changed file with 12 additions and 6 deletions.
18 changes: 12 additions & 6 deletions pdf/src/parser/parse_xref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ fn parse_xref_section_from_stream(first_id: u32, mut num_entries: usize, width:
let _type = if w0 == 0 {
1
} else {
read_u64_from_stream(w0, data)
read_u64_from_stream(w0, data)?
};
let field1 = read_u64_from_stream(w1, data);
let field2 = read_u64_from_stream(w2, data);
let field1 = read_u64_from_stream(w1, data)?;
let field2 = read_u64_from_stream(w2, data)?;

let entry =
match _type {
Expand All @@ -45,16 +45,22 @@ fn parse_xref_section_from_stream(first_id: u32, mut num_entries: usize, width:
entries,
})
}
/// Helper to read an integer with a certain amount of bits `width` from stream.
fn read_u64_from_stream(width: usize, data: &mut &[u8]) -> u64 {
/// Helper to read an integer with a certain amount of bytes `width` from stream.
fn read_u64_from_stream(width: usize, data: &mut &[u8]) -> Result<u64> {
if width > std::mem::size_of::<u64>() {
return Err(PdfError::Other { msg: format!("xref stream entry has invalid width {}", width) });
}
if width > data.len() {
return Err(PdfError::Other { msg: format!("xref stream entry has width {} but only {} bytes left to read", width, data.len()) });
}
let mut result = 0;
for i in (0..width).rev() {
let base = 8 * i; // (width, 0]
let c: u8 = data[0];
*data = &data[1..]; // Consume byte
result += u64::from(c) << base;
}
result
Ok(result)
}


Expand Down

0 comments on commit 3187677

Please sign in to comment.