Skip to content

Commit

Permalink
chore: Fix another fuzz failure
Browse files Browse the repository at this point in the history
  • Loading branch information
Pr0methean committed Jun 17, 2024
1 parent 16aa9bc commit 64b5deb
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 21 deletions.
22 changes: 16 additions & 6 deletions fuzz/fuzz_targets/fuzz_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ pub struct FileOperation<'k> {
// 'abort' flag is separate, to prevent trying to copy an aborted file
}

impl <'k> FileOperation<'k> {
fn get_path(&self) -> Cow<PathBuf> {
if let BasicFileOperation::WriteDirectory(_) = self.basic {
Cow::Owned(self.path.join("/"))
} else {
Cow::Borrowed(&self.path)
}
}
}

impl <'k> Debug for FileOperation<'k> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.basic {
Expand All @@ -63,10 +73,10 @@ impl <'k> Debug for FileOperation<'k> {
options, self.path, target.to_owned()))?;
},
BasicFileOperation::ShallowCopy(base) => {
f.write_fmt(format_args!("{:?}writer.shallow_copy_file_from_path({:?}, {:?})?;\n", base, base.path, self.path))?;
f.write_fmt(format_args!("{:?}writer.shallow_copy_file_from_path({:?}, {:?})?;\n", base, base.get_path(), self.path))?;
},
BasicFileOperation::DeepCopy(base) => {
f.write_fmt(format_args!("{:?}writer.deep_copy_file_from_path({:?}, {:?})?;\n", base, base.path, self.path))?;
f.write_fmt(format_args!("{:?}writer.deep_copy_file_from_path({:?}, {:?})?;\n", base, base.get_path(), self.path))?;
},
BasicFileOperation::MergeWithOtherFile {operations} => {
f.write_str("let sub_writer = {\n\
Expand Down Expand Up @@ -177,15 +187,15 @@ where
*files_added += 1;
}
BasicFileOperation::ShallowCopy(base) => {
deduplicate_paths(&mut path, &base.path);
deduplicate_paths(&mut path, &base.get_path());
do_operation(writer, &base, false, flush_on_finish_file, files_added)?;
writer.shallow_copy_file_from_path(&base.path, &*path)?;
writer.shallow_copy_file_from_path(&*base.get_path(), &*path)?;
*files_added += 1;
}
BasicFileOperation::DeepCopy(base) => {
deduplicate_paths(&mut path, &base.path);
deduplicate_paths(&mut path, &base.get_path());
do_operation(writer, &base, false, flush_on_finish_file, files_added)?;
writer.deep_copy_file_from_path(&base.path, &*path)?;
writer.deep_copy_file_from_path(&*base.get_path(), &*path)?;
*files_added += 1;
}
BasicFileOperation::MergeWithOtherFile { operations } => {
Expand Down
25 changes: 12 additions & 13 deletions src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,21 @@ impl<R: Read> LittleEndianReadExt for R {}
pub fn path_to_string<T: AsRef<Path>>(path: T) -> Box<str> {
let mut maybe_original = None;
if let Some(original) = path.as_ref().to_str() {
if original.is_empty() {
if original.is_empty() || original == "." || original == ".." {
return String::new().into_boxed_str();
}
if (MAIN_SEPARATOR == '/' || !original[1..].contains(MAIN_SEPARATOR))
&& !original.ends_with('.')
&& !original.starts_with(['.', MAIN_SEPARATOR])
&& !original.starts_with(['.', '.', MAIN_SEPARATOR])
&& !original.contains([MAIN_SEPARATOR, MAIN_SEPARATOR])
&& !original.contains([MAIN_SEPARATOR, '.', MAIN_SEPARATOR])
&& !original.contains([MAIN_SEPARATOR, '.', '.', MAIN_SEPARATOR])
{
if original.starts_with(MAIN_SEPARATOR) {
if original.starts_with(MAIN_SEPARATOR) {
if original.len() == 1 {
return MAIN_SEPARATOR.to_string().into_boxed_str();
} else if (MAIN_SEPARATOR == '/' || !original[1..].contains(MAIN_SEPARATOR))
&& !original.ends_with('.')
&& !original.contains([MAIN_SEPARATOR, MAIN_SEPARATOR])
&& !original.contains([MAIN_SEPARATOR, '.', MAIN_SEPARATOR])
&& !original.contains([MAIN_SEPARATOR, '.', '.', MAIN_SEPARATOR]) {
maybe_original = Some(&original[1..]);
} else {
maybe_original = Some(original);
}
} else if !original.contains(MAIN_SEPARATOR) {
return original.into();
}
}
let mut recreate = maybe_original.is_none();
Expand All @@ -107,7 +106,7 @@ pub fn path_to_string<T: AsRef<Path>>(path: T) -> Box<str> {
Component::ParentDir => {
recreate = true;
normalized_components.pop();
}
},
_ => {
recreate = true;
}
Expand Down
96 changes: 95 additions & 1 deletion src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,9 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
src_path: T,
dest_path: U,
) -> ZipResult<()> {
self.deep_copy_file(&path_to_string(src_path), &path_to_string(dest_path))
let src = path_to_string(src_path);
let dest = path_to_string(dest_path);
self.deep_copy_file(&src, &dest)
}

/// Write the zip file into the backing stream, then produce a readable archive of that data.
Expand Down Expand Up @@ -1967,7 +1969,10 @@ mod test {
use crate::ZipArchive;
use std::io;
use std::io::{Cursor, Read, Write};
use std::marker::PhantomData;
use std::path::PathBuf;
use crate::write::EncryptWith::ZipCrypto;
use crate::zipcrypto::ZipCryptoKeys;

#[test]
fn write_empty_zip() {
Expand Down Expand Up @@ -2900,4 +2905,93 @@ mod test {
let _ = writer.finish_into_readable()?;
Ok(())
}

#[allow(deprecated)]
#[test]
fn test_fuzz_crash_2024_06_17() -> ZipResult<()> {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let sub_writer = {
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
writer.set_flush_on_finish_file(false);
let options = FileOptions { compression_method: CompressionMethod::Unsupported(65535), compression_level: Some(5), last_modified_time: DateTime::from_date_and_time(2107, 2, 8, 15, 0, 0)?, permissions: None, large_file: true, encrypt_with: Some(ZipCrypto(ZipCryptoKeys::of(0x63ff,0xc62d3103,0xfffe00ea), PhantomData::default())), extended_options: ExtendedFileOptions {extra_data: vec![].into(), central_extra_data: vec![].into()}, alignment: 255, ..Default::default() };

Check failure on line 2941 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct

Check failure on line 2941 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct
writer.add_symlink_from_path("1\0PK\u{6}\u{6}\u{b}\u{6}\u{6}\u{6}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u{1}\0\0\0\0\0\0\0\0\u{b}\0\0PK\u{1}\u{2},\0\0\0\0\0\0\0\0\0\0\0\u{10}\0\0\0K\u{6}\u{6}\0\0\0\0\0\0\0\0PK\u{2}\u{6}", "", options)?;
writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?;
let options = FileOptions { compression_method: Stored, compression_level: None, last_modified_time: DateTime::from_date_and_time(1992, 7, 3, 0, 0, 0)?, permissions: None, large_file: true, encrypt_with: None, extended_options: ExtendedFileOptions {extra_data: vec![].into(), central_extra_data: vec![].into()}, alignment: 43, ..Default::default() };
writer.start_file_from_path("\0\0\0\u{3}\0\u{1a}\u{1a}\u{1a}\u{1a}\u{1a}\u{1a}", options)?;
let options = FileOptions { compression_method: Stored, compression_level: None, last_modified_time: DateTime::from_date_and_time(2006, 3, 27, 2, 24, 26)?, permissions: None, large_file: false, encrypt_with: None, extended_options: ExtendedFileOptions {extra_data: vec![].into(), central_extra_data: vec![].into()}, alignment: 26, ..Default::default() };
writer.start_file_from_path("\0K\u{6}\u{6}\0PK\u{6}\u{7}PK\u{6}\u{6}\0\0\0\0\0\0\0\0PK\u{2}\u{6}", options)?;
writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?;
let options = FileOptions { compression_method: Stored, compression_level: Some(17), last_modified_time: DateTime::from_date_and_time(2103, 4, 10, 23, 15, 18)?, permissions: Some(3284386755), large_file: true, encrypt_with: Some(ZipCrypto(ZipCryptoKeys::of(0x8888c5bf,0x88888888,0xff888888), PhantomData::default())), extended_options: ExtendedFileOptions {extra_data: vec![3, 0, 1, 0, 255, 144, 136, 0, 0].into(), central_extra_data: vec![].into()}, alignment: 65535, ..Default::default() };

Check failure on line 2953 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct

Check failure on line 2953 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct
writer.add_symlink_from_path("", "\nu", options)?;
writer = ZipWriter::new_append(writer.finish()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer = ZipWriter::new_append(writer.finish()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer = ZipWriter::new_append(writer.finish_into_readable()?.into_inner())?;
writer.abort_file()?;
let options = FileOptions { compression_method: CompressionMethod::Unsupported(49603), compression_level: Some(20), last_modified_time: DateTime::from_date_and_time(2047, 4, 14, 3, 15, 14)?, permissions: Some(3284386755), large_file: true, encrypt_with: Some(ZipCrypto(ZipCryptoKeys::of( 0xc3, 0x0, 0x0), PhantomData::default())), extended_options: ExtendedFileOptions {extra_data: vec![].into(), central_extra_data: vec![].into()}, alignment: 0, ..Default::default() };

Check failure on line 2969 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct

Check failure on line 2969 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

use of `default` to create a unit struct
writer.add_directory_from_path("", options)?;
writer.deep_copy_file_from_path("/", "")?;
writer.shallow_copy_file_from_path("", "copy")?;
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
assert!(writer.shallow_copy_file_from_path("", "copy").is_err());
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
let _ = writer.finish_into_readable()?;
Ok(())
}
}
11 changes: 10 additions & 1 deletion src/zipcrypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Debug for ZipCryptoKeys {
}
#[cfg(any(test, fuzzing))]
return f.write_fmt(format_args!(
"ZipCryptoKeys({:#10x},{:#10x},{:#10x})",
"ZipCryptoKeys::of({:#10x},{:#10x},{:#10x})",
self.key_0, self.key_1, self.key_2
));
}
Expand All @@ -46,6 +46,15 @@ impl ZipCryptoKeys {
}
}

#[allow(unused)]
pub const fn of(key_0: u32, key_1: u32, key_2: u32) -> ZipCryptoKeys {
ZipCryptoKeys {
key_0: Wrapping(key_0),
key_1: Wrapping(key_1),
key_2: Wrapping(key_2),
}
}

fn update(&mut self, input: u8) {
self.key_0 = ZipCryptoKeys::crc32(self.key_0, input);
self.key_1 =
Expand Down

0 comments on commit 64b5deb

Please sign in to comment.