From c4bd7a61a599cb2675566741fa025904c7ac5260 Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:25:49 -0700 Subject: [PATCH] test: Fix a bug involving ZIP64 field parsing --- src/read.rs | 17 +++++++++++++---- src/write.rs | 8 +++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/read.rs b/src/read.rs index efbd34cb..9fcd7f12 100644 --- a/src/read.rs +++ b/src/read.rs @@ -20,6 +20,7 @@ use std::ffi::OsString; use std::fs::create_dir_all; use std::io::{self, copy, prelude::*, sink, SeekFrom}; use std::mem; +use std::mem::size_of; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; @@ -94,7 +95,7 @@ use crate::aes::PWD_VERIFY_LENGTH; use crate::extra_fields::UnicodeExtraField; #[cfg(feature = "lzma")] use crate::read::lzma::LzmaDecoder; -use crate::result::ZipError::{InvalidPassword, UnsupportedArchive}; +use crate::result::ZipError::{InvalidArchive, InvalidPassword, UnsupportedArchive}; use crate::spec::is_dir; use crate::types::ffi::S_IFLNK; use crate::unstable::{path_to_string, LittleEndianReadExt}; @@ -1233,17 +1234,25 @@ pub(crate) fn parse_single_extra_field( match kind { // Zip64 extended information extra field 0x0001 => { - if file.uncompressed_size == spec::ZIP64_BYTES_THR { + let mut consumed_len = 0; + if len >= 24 || file.uncompressed_size == spec::ZIP64_BYTES_THR { file.large_file = true; file.uncompressed_size = reader.read_u64_le()?; + consumed_len += size_of::(); } - if file.compressed_size == spec::ZIP64_BYTES_THR { + if len >= 24 || file.compressed_size == spec::ZIP64_BYTES_THR { file.large_file = true; file.compressed_size = reader.read_u64_le()?; + consumed_len += size_of::(); } - if file.header_start == spec::ZIP64_BYTES_THR { + if len >= 24 || file.header_start == spec::ZIP64_BYTES_THR { file.header_start = reader.read_u64_le()?; + consumed_len += size_of::(); } + let Some(leftover_len) = (len as usize).checked_sub(consumed_len) else { + return Err(InvalidArchive("ZIP64 extra-data field is the wrong length")); + }; + reader.read_exact(&mut vec![0u8; leftover_len])?; } 0x9901 => { // AES diff --git a/src/write.rs b/src/write.rs index 38dfd419..c99c67c4 100644 --- a/src/write.rs +++ b/src/write.rs @@ -325,11 +325,12 @@ impl ExtendedFileOptions { ))); } let mut data = Cursor::new(data); - while data.position() < len { + let mut pos = data.position(); + while pos < len { if len - data.position() < 4 { return Err(ZipError::Io(io::Error::new( io::ErrorKind::Other, - "Extra-data field doesn't have room for tag and length", + "Extra-data field doesn't have room for ID and length", ))); } #[cfg(not(feature = "unreserved"))] @@ -350,7 +351,8 @@ impl ExtendedFileOptions { } data.seek(SeekFrom::Current(-2))?; } - parse_single_extra_field(&mut ZipFileData::default(), &mut data, 0)?; + parse_single_extra_field(&mut ZipFileData::default(), &mut data, pos)?; + pos = data.position(); } Ok(()) }