From 866516ac50851e2827e6aff0a98c444268c566ff Mon Sep 17 00:00:00 2001 From: igorechek06 Date: Sat, 10 Aug 2024 17:18:03 +0900 Subject: Add overlap checking --- src/zip/driver.rs | 26 ++++++++++++++++++-------- src/zip/encryption/aes.rs | 1 - src/zip/encryption/weak.rs | 1 - src/zip/error.rs | 17 ++++++++++++----- 4 files changed, 30 insertions(+), 15 deletions(-) (limited to 'src/zip') diff --git a/src/zip/driver.rs b/src/zip/driver.rs index b4217c8..9dccfd0 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs @@ -1,5 +1,5 @@ use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; -use crate::utils::ReadUtils; +use crate::utils::{IoCursor, ReadUtils}; use crate::zip::cp437::FromCp437; use crate::zip::datetime::DosDateTime; use crate::zip::structs::{ @@ -106,12 +106,19 @@ impl ArchiveRead for Zip { io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; let buf = io.read_arr::<56>()?; if buf[0..4] != EOCDR64_SIGNATURE { - return Err(ZipError::InvalidEOCDR64Signature); + return Err(ZipError::InvalidEocdr64Signature); } let eocdr64: Eocdr64 = deserialize(&buf[4..]).unwrap(); + if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { + return Err(ZipError::Overlapping("Central directory records", "Zip64 end of central directory record")); + } (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")); + } + ( eocdr.cd_pointer as u64, eocdr.cd_size as u64, @@ -123,27 +130,30 @@ impl ArchiveRead for Zip { let mut indexes = Map::with_capacity(cd_records as usize); let mut files = Vec::with_capacity(cd_records as usize); io.seek(SeekFrom::Start(cd_pointer))?; - let mut buf_reader = BufReader::with_capacity(cd_size.min(131072) as usize, &mut io); + let mut cd_reader = BufReader::with_capacity( + cd_size.min(131072) as usize, + IoCursor::new(&mut io, cd_pointer, cd_pointer + cd_size), + ); for i in 0..cd_records as usize { - let buf = buf_reader.read_arr::<46>()?; + let buf = cd_reader.read_arr::<46>()?; if buf[..4] != CDR_SIGNATURE { - return Err(ZipError::InvalidCDRSignature); + return Err(ZipError::InvalidCdrSignature); } let cdr: Cdr = deserialize(&buf[4..46]).unwrap(); let bit_flag = BitFlag::new(cdr.bit_flag); - let name = buf_reader.read_vec(cdr.name_len as usize)?; + let name = cd_reader.read_vec(cdr.name_len as usize)?; let name = if bit_flag.is_utf8() { String::from_utf8(name).map_err(|_| ZipError::InvalidFileName)? } else { String::from_cp437(name) }; - let extra_fields = buf_reader.read_vec(cdr.extra_field_len as usize)?; + let extra_fields = cd_reader.read_vec(cdr.extra_field_len as usize)?; - let comment = buf_reader.read_vec(cdr.comment_len as usize)?; + let comment = cd_reader.read_vec(cdr.comment_len as usize)?; let comment = if bit_flag.is_utf8() { String::from_utf8(comment).map_err(|_| ZipError::InvalidFileComment)? } else { diff --git a/src/zip/encryption/aes.rs b/src/zip/encryption/aes.rs index b690482..376d01e 100644 --- a/src/zip/encryption/aes.rs +++ b/src/zip/encryption/aes.rs @@ -2,7 +2,6 @@ use aes::cipher::generic_array::GenericArray; use aes::cipher::BlockEncrypt; use std::io::{Read, Result as IoResult}; -#[allow(dead_code)] pub struct AesDecoder { io: Io, aes: Aes, diff --git a/src/zip/encryption/weak.rs b/src/zip/encryption/weak.rs index ebddb2d..3c35776 100644 --- a/src/zip/encryption/weak.rs +++ b/src/zip/encryption/weak.rs @@ -55,7 +55,6 @@ impl Keys { self.key2 = crc32((self.key1 >> 24) as u8, self.key2); } - #[allow(dead_code)] pub fn encode_bytes(&mut self, byte: u8) -> u8 { let key = self.key2 | 2; self.update(byte); diff --git a/src/zip/error.rs b/src/zip/error.rs index 87cd9e9..dbb6bb5 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs @@ -9,9 +9,11 @@ pub enum ZipError { Io(IoError), EocdrNotFound, - InvalidEOCDR64Signature, + InvalidEocdr64Signature, InvalidFileHeaderSignature, - InvalidCDRSignature, + InvalidCdrSignature, + + Overlapping(&'static str, &'static str), UnsupportedCompressionMethod(u16), UnsupportedEncryptionMethod, @@ -53,8 +55,9 @@ impl Display for ZipError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Io(error) => write!(f, "{}", error), + Self::EocdrNotFound => write!(f, "End of central directory record not found"), - Self::InvalidEOCDR64Signature => { + Self::InvalidEocdr64Signature => { write!( f, "Invalid signature of zip64 end of central directory record" @@ -63,12 +66,16 @@ impl Display for ZipError { Self::InvalidFileHeaderSignature => { write!(f, "Invalid file header signature") } - Self::InvalidCDRSignature => { + Self::InvalidCdrSignature => { write!(f, "Invalid signature of central directory record") } + Self::Overlapping(struct1, struct2) => { + write!(f, "`{}` overlapt `{}`", struct1, struct2) + } + Self::UnsupportedCompressionMethod(id) => { - writeln!(f, "Unsupported compression method {}", id) + writeln!(f, "Unsupported compression method `{}`", id) } Self::UnsupportedEncryptionMethod => { writeln!(f, "Unsupported encryption method") -- cgit v1.2.3