From 27da50f9d157927ec56dae8316d0edc34eaa244d Mon Sep 17 00:00:00 2001 From: Tolmachev Igor Date: Tue, 27 Aug 2024 18:03:30 +0900 Subject: Rewrite Eocdr64Locator search algorithm --- src/zip/driver.rs | 70 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'src/zip/driver.rs') diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 7758479..0502c85 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs @@ -79,7 +79,7 @@ impl ArchiveRead for Zip { // Search eocdr let limit = 65557.min(io.seek(SeekFrom::End(0))?) as i64; let start = io.seek(SeekFrom::End(-limit))?; - let pos = start + let eocdr_pos = start + io.read_vec( (limit as usize) .checked_sub(18) @@ -90,46 +90,50 @@ impl ArchiveRead for Zip { .ok_or(ZipError::StructNotFound("Eocdr"))? as u64; // Read eocdr - io.seek(SeekFrom::Start(pos + 4))?; + io.seek(SeekFrom::Start(eocdr_pos + 4))?; let buf = io.read_arr::<18>()?; let eocdr: Eocdr = deserialize(&buf).unwrap(); let comment = String::from_cp437(io.read_vec(eocdr.comment_len as usize)?); + let mut cd_pointer = eocdr.cd_pointer as u64; + let mut cd_size = eocdr.cd_size as u64; + let mut cd_records = eocdr.cd_records as u64; + // Try to find eocdr64locator - io.seek(SeekFrom::Start(pos.saturating_sub(20)))?; - let buf = io.read_arr::<20>()?; - let (cd_pointer, cd_size, cd_records) = if buf[..4] == EOCDR64_LOCATOR_SIGNATURE { - // Locator found - let eocdr64locator: Eocdr64Locator = deserialize(&buf[4..]).unwrap(); - - io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; - if io.read_arr()? != EOCDR64_SIGNATURE { - return Err(ZipError::InvalidSignature("Eocdr64")); - } + if eocdr_pos >= 20 { + io.seek(SeekFrom::Start(eocdr_pos - 20))?; + let buf = io.read_arr::<20>()?; - let eocdr64: Eocdr64 = deserialize(&io.read_arr::<52>()?).unwrap(); - if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { - return Err(ZipError::Overlapping( - "Central directory records", - "Zip64 end of central directory record", - )); - } + if buf[..4] == EOCDR64_LOCATOR_SIGNATURE { + let locator: Eocdr64Locator = deserialize(&buf[4..]).unwrap(); + io.seek(SeekFrom::Start(locator.eocdr64_pointer))?; - (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) - } else { - if (eocdr.cd_pointer + eocdr.cd_size) as u64 > pos { - return Err(ZipError::Overlapping( - "Central directory records", - "End of central directory record", - )); - } + if io.read_arr()? != EOCDR64_SIGNATURE { + return Err(ZipError::InvalidSignature("Eocdr64")); + } + + if locator.eocdr64_pointer + 76 > eocdr_pos { + return Err(ZipError::Overlapping("Eocdr64", "Eocdr64Locator")); + } - ( - eocdr.cd_pointer as u64, - eocdr.cd_size as u64, - eocdr.cd_records as u64, - ) - }; + let eocdr64: Eocdr64 = deserialize(&io.read_arr::<54>()?).unwrap(); + if locator.eocdr64_pointer + eocdr64.eocdr64_size + 32 > eocdr_pos { + return Err(ZipError::Overlapping("Eocdr64", "Eocdr64Locator")); + } + + cd_pointer = eocdr64.cd_pointer; + cd_size = eocdr64.cd_size; + cd_records = eocdr64.cd_records; + + if cd_pointer + cd_size > locator.eocdr64_pointer { + return Err(ZipError::Overlapping("Cdr", "Eocdr64")); + } + } else if cd_pointer + cd_size > eocdr_pos { + return Err(ZipError::Overlapping("Cdr", "Eocdr")); + } + } else if cd_pointer + cd_size > eocdr_pos { + return Err(ZipError::Overlapping("Cdr", "Eocdr")); + } // Read cd records let mut indexes = Map::with_capacity(cd_records as usize); -- cgit v1.2.3