From 6b93d358d5c709639f39ef419cb68645bdabbe2c Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:11:32 -0700 Subject: [PATCH] chore: Fix more errors when parsing multiple extra fields --- src/read.rs | 19 +++---------------- src/write.rs | 14 ++++++++------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/read.rs b/src/read.rs index 1839d68e..1aa4a1cb 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1216,12 +1216,7 @@ pub(crate) fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> { /* TODO: codify this structure into Zip64ExtraFieldBlock fields! */ while (reader.position() as usize) < len { - let len_left = parse_single_extra_field(file, &mut reader)?; - - // We could also check for < 0 to check for errors - if len_left > 0 { - reader.seek(io::SeekFrom::Current(len_left))?; - } + parse_single_extra_field(file, &mut reader)?; } Ok(()) } @@ -1229,26 +1224,22 @@ pub(crate) fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> { pub(crate) fn parse_single_extra_field( file: &mut ZipFileData, reader: &mut R, -) -> ZipResult { +) -> ZipResult<()> { let kind = reader.read_u16_le()?; let len = reader.read_u16_le()?; - let mut len_left = len as i64; match kind { // Zip64 extended information extra field 0x0001 => { if file.uncompressed_size == spec::ZIP64_BYTES_THR { file.large_file = true; file.uncompressed_size = reader.read_u64_le()?; - len_left -= 8; } if file.compressed_size == spec::ZIP64_BYTES_THR { file.large_file = true; file.compressed_size = reader.read_u64_le()?; - len_left -= 8; } if file.header_start == spec::ZIP64_BYTES_THR { file.header_start = reader.read_u64_le()?; - len_left -= 8; } } 0x9901 => { @@ -1280,7 +1271,6 @@ pub(crate) fn parse_single_extra_field( _ => return Err(ZipError::InvalidArchive("Invalid AES encryption strength")), }; file.compression_method = compression_method; - len_left -= 7; } 0x5455 => { // extended timestamp @@ -1289,9 +1279,6 @@ pub(crate) fn parse_single_extra_field( file.extra_fields.push(ExtraField::ExtendedTimestamp( ExtendedTimestamp::try_from_reader(reader, len)?, )); - - // the reader for ExtendedTimestamp consumes `len` bytes - len_left = 0; } 0x6375 => { // Info-ZIP Unicode Comment Extra Field @@ -1315,7 +1302,7 @@ pub(crate) fn parse_single_extra_field( // Other fields are ignored } } - Ok(len_left) + Ok(()) } /// Methods for retrieving information on zip files diff --git a/src/write.rs b/src/write.rs index bc863b65..37999e7f 100644 --- a/src/write.rs +++ b/src/write.rs @@ -318,14 +318,16 @@ impl ExtendedFileOptions { fn validate_extra_data(&self) -> ZipResult<()> { let mut data = self.extra_data.to_vec(); data.extend(self.central_extra_data.iter()); - if data.len() > u16::MAX as usize { + let len = data.len() as u64; + if len > u16::MAX as u64 { return Err(ZipError::Io(io::Error::new( io::ErrorKind::Other, "Extra-data field can't exceed u16::MAX bytes", ))); } - while !data.is_empty() { - if data.len() < 2 { + let mut data = Cursor::new(data); + while data.position() < len { + if len - data.position() < 2 { return Err(ZipError::Io(io::Error::new( io::ErrorKind::Other, "Extra-data field needs 2 tag bytes", @@ -333,7 +335,8 @@ impl ExtendedFileOptions { } #[cfg(not(feature = "unreserved"))] { - let header_id = u16::from_le_bytes([data[0], data[1]]); + use crate::unstable::LittleEndianReadExt; + let header_id = data.read_u16_le()?; if header_id <= 31 || EXTRA_FIELD_MAPPING .iter() @@ -347,8 +350,7 @@ impl ExtendedFileOptions { ))); } } - let len_left = parse_single_extra_field(&mut ZipFileData::default(), &mut Cursor::new(data.to_vec()))?; - data = data[(data.len() - len_left as usize)..].to_owned() + parse_single_extra_field(&mut ZipFileData::default(), &mut data)?; } Ok(()) }