From f1b617d112bde3b9dfca01f52155d6e4b66f03f0 Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Thu, 20 Jun 2024 04:45:28 -0700 Subject: [PATCH] fix: Check number of files when deciding whether a CDE is the real one --- src/read.rs | 8 ++++++- src/write.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/read.rs b/src/read.rs index 9479b6a4..b9b8247b 100644 --- a/src/read.rs +++ b/src/read.rs @@ -771,7 +771,13 @@ impl ZipArchive { unsupported_errors.push(ZipError::UnsupportedArchive(e)) } Err(e) => invalid_errors.push(e), - Ok(o) => ok_results.push((footer.clone(), o)), + Ok(o) => { + if o.files.len() >= footer.number_of_files as usize { + ok_results.push((footer.clone(), o)) + } else { + invalid_errors.push(InvalidArchive("wrong number of files")) + } + } } } diff --git a/src/write.rs b/src/write.rs index 982bbf36..47fda291 100644 --- a/src/write.rs +++ b/src/write.rs @@ -167,7 +167,7 @@ pub(crate) mod zip_writer { f.write_fmt(format_args!( "ZipWriter {{files: {:?}, stats: {:?}, writing_to_file: {}, writing_raw: {}, comment: {:?}, flush_on_finish_file: {}}}", self.files, self.stats, self.writing_to_file, self.writing_raw, - String::from_utf8(self.comment.to_vec()), self.flush_on_finish_file)) + self.comment, self.flush_on_finish_file)) } } } @@ -3411,4 +3411,61 @@ mod test { let _ = writer.finish_into_readable()?; Ok(()) } + + #[test] + fn test_fuzz_crash_2024_06_19() -> ZipResult<()> { + let mut writer = ZipWriter::new(Cursor::new(Vec::new())); + writer.set_flush_on_finish_file(false); + let options = FileOptions { + compression_method: Stored, + compression_level: None, + last_modified_time: DateTime::from_date_and_time(1980, 3, 1, 19, 55, 58)?, + permissions: None, + large_file: false, + encrypt_with: None, + extended_options: ExtendedFileOptions { + extra_data: vec![].into(), + central_extra_data: vec![].into(), + }, + alignment: 256, + ..Default::default() + }; + writer.start_file_from_path( + "\0\0\0PK\u{5}\u{6}\0\0\0\0\u{1}\0\u{12}\u{6}\0\0\0\0\0\u{1}\0\0\0\0\0\0\0\0\0", + options, + )?; + writer.set_flush_on_finish_file(false); + writer.shallow_copy_file_from_path( + "\0\0\0PK\u{5}\u{6}\0\0\0\0\u{1}\0\u{12}\u{6}\0\0\0\0\0\u{1}\0\0\0\0\0\0\0\0\0", + "", + )?; + writer.set_flush_on_finish_file(false); + writer.deep_copy_file_from_path("", "copy")?; + writer.abort_file()?; + writer.set_flush_on_finish_file(false); + writer.set_raw_comment([255, 0].into()); + writer.abort_file()?; + assert_eq!(writer.get_raw_comment(), [255, 0]); + writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?; + assert_eq!(writer.get_raw_comment(), [255, 0]); + writer.set_flush_on_finish_file(false); + let options = FileOptions { + compression_method: Stored, + compression_level: None, + last_modified_time: DateTime::default(), + permissions: None, + large_file: false, + encrypt_with: None, + extended_options: ExtendedFileOptions { + extra_data: vec![].into(), + central_extra_data: vec![].into(), + }, + ..Default::default() + }; + writer.start_file_from_path("", options)?; + assert_eq!(writer.get_raw_comment(), [255, 0]); + let archive = writer.finish_into_readable()?; + assert_eq!(archive.comment(), [255, 0]); + Ok(()) + } }