Skip to content

Commit 3187677

Browse files
Orycteropes3bk
authored andcommitted
fix panic on malformed xref stream width
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.
1 parent 22ff7fd commit 3187677

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

pdf/src/parser/parse_xref.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ fn parse_xref_section_from_stream(first_id: u32, mut num_entries: usize, width:
2626
let _type = if w0 == 0 {
2727
1
2828
} else {
29-
read_u64_from_stream(w0, data)
29+
read_u64_from_stream(w0, data)?
3030
};
31-
let field1 = read_u64_from_stream(w1, data);
32-
let field2 = read_u64_from_stream(w2, data);
31+
let field1 = read_u64_from_stream(w1, data)?;
32+
let field2 = read_u64_from_stream(w2, data)?;
3333

3434
let entry =
3535
match _type {
@@ -45,16 +45,22 @@ fn parse_xref_section_from_stream(first_id: u32, mut num_entries: usize, width:
4545
entries,
4646
})
4747
}
48-
/// Helper to read an integer with a certain amount of bits `width` from stream.
49-
fn read_u64_from_stream(width: usize, data: &mut &[u8]) -> u64 {
48+
/// Helper to read an integer with a certain amount of bytes `width` from stream.
49+
fn read_u64_from_stream(width: usize, data: &mut &[u8]) -> Result<u64> {
50+
if width > std::mem::size_of::<u64>() {
51+
return Err(PdfError::Other { msg: format!("xref stream entry has invalid width {}", width) });
52+
}
53+
if width > data.len() {
54+
return Err(PdfError::Other { msg: format!("xref stream entry has width {} but only {} bytes left to read", width, data.len()) });
55+
}
5056
let mut result = 0;
5157
for i in (0..width).rev() {
5258
let base = 8 * i; // (width, 0]
5359
let c: u8 = data[0];
5460
*data = &data[1..]; // Consume byte
5561
result += u64::from(c) << base;
5662
}
57-
result
63+
Ok(result)
5864
}
5965

6066

0 commit comments

Comments
 (0)