-
Notifications
You must be signed in to change notification settings - Fork 106
Fix subtraction overflow in ExtendedTimestamp::try_from_reader #697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -53,21 +53,27 @@ impl ExtendedTimestamp { | |||||
| // allow unsupported/undocumented flags | ||||||
|
|
||||||
| let mod_time = if (flags & 0b0000_0001_u8 == 0b0000_0001_u8) || len == 5 { | ||||||
| bytes_to_read -= size_of::<u32>(); | ||||||
| bytes_to_read = bytes_to_read | ||||||
| .checked_sub(size_of::<u32>()) | ||||||
| .ok_or(invalid!("Extended timestamp field too short for mod_time"))?; | ||||||
| Some(reader.read_u32_le()?) | ||||||
| } else { | ||||||
| None | ||||||
| }; | ||||||
|
|
||||||
| let ac_time = if flags & 0b0000_0010_u8 == 0b0000_0010_u8 && len > 5 { | ||||||
| bytes_to_read -= size_of::<u32>(); | ||||||
| bytes_to_read = bytes_to_read | ||||||
| .checked_sub(size_of::<u32>()) | ||||||
| .ok_or(invalid!("Extended timestamp field too short for ac_time"))?; | ||||||
| Some(reader.read_u32_le()?) | ||||||
| } else { | ||||||
| None | ||||||
| }; | ||||||
|
|
||||||
| let cr_time = if flags & 0b0000_0100_u8 == 0b0000_0100_u8 && len > 5 { | ||||||
| bytes_to_read -= size_of::<u32>(); | ||||||
| bytes_to_read = bytes_to_read | ||||||
| .checked_sub(size_of::<u32>()) | ||||||
| .ok_or(invalid!("Extended timestamp field too short for cr_time"))?; | ||||||
| Some(reader.read_u32_le()?) | ||||||
| } else { | ||||||
| None | ||||||
|
Comment on lines
55
to
79
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While the change is correct, there is significant code duplication in parsing the const MOD_TIME_FLAG: u8 = 1;
const AC_TIME_FLAG: u8 = 2;
const CR_TIME_FLAG: u8 = 4;
let mut read_timestamp = |field_name: &'static str| -> ZipResult<u32> {
bytes_to_read = bytes_to_read
.checked_sub(std::mem::size_of::<u32>())
.ok_or(invalid!(
"Extended timestamp field too short for {}",
field_name
))?;
reader.read_u32_le()
};
let mod_time = if (flags & MOD_TIME_FLAG != 0) || len == 5 {
Some(read_timestamp("mod_time")?)
} else {
None
};
let ac_time = if (flags & AC_TIME_FLAG != 0) && len > 5 {
Some(read_timestamp("ac_time")?)
} else {
None
};
let cr_time = if (flags & CR_TIME_FLAG != 0) && len > 5 {
Some(read_timestamp("cr_time")?)
} else {
None
} |
||||||
|
|
@@ -120,4 +126,21 @@ mod test { | |||||
| .is_err() | ||||||
| ); | ||||||
| } | ||||||
|
|
||||||
| #[test] | ||||||
| /// Ensure that a truncated extended timestamp (len too short for flags) | ||||||
| /// returns an error instead of panicking from a subtraction overflow. | ||||||
| fn test_extended_timestamp_overflow() { | ||||||
| use super::ExtendedTimestamp; | ||||||
| use std::io::Cursor; | ||||||
|
|
||||||
| // flags = 0x01 indicates mod_time is present, which requires 4 bytes, | ||||||
| // but len = 2 only provides 1 byte after the flags byte. | ||||||
| // The validation check catches this before the subtraction, but even | ||||||
| // if validation were removed, checked_sub would catch it. | ||||||
| let data: &[u8] = &[0x01, 0x00, 0x00, 0x00]; | ||||||
|
||||||
| let data: &[u8] = &[0x01, 0x00, 0x00, 0x00]; | |
| let data: &[u8] = &[0x01, 0x00]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_of::<u32>()is used here butsize_ofisn’t in scope in this module, which will fail to compile. Import it (e.g.,use core::mem::size_of;) or fully-qualify the calls (e.g.,core::mem::size_of::<u32>()).