Test allowing ZIP64 magic with the sanity checks
This commit is contained in:
parent
70db61c26e
commit
546693a6c7
5 changed files with 21 additions and 55 deletions
|
@ -118,10 +118,3 @@
|
||||||
|
|
||||||
- Added experimental [`zip_next::unstable::write::FileOptions::with_deprecated_encryption`] API to enable encrypting
|
- Added experimental [`zip_next::unstable::write::FileOptions::with_deprecated_encryption`] API to enable encrypting
|
||||||
files with PKWARE encryption.
|
files with PKWARE encryption.
|
||||||
|
|
||||||
## [0.7.5]
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Two magic strings are no longer allowed in filenames, because they can make files impossible to read correctly.
|
|
||||||
- Archives containing these magic files can still be opened in many cases.
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ pbkdf2 = {version = "0.12.1", optional = true }
|
||||||
sha1 = {version = "0.10.5", optional = true }
|
sha1 = {version = "0.10.5", optional = true }
|
||||||
time = { version = "0.3.21", optional = true, default-features = false, features = ["std"] }
|
time = { version = "0.3.21", optional = true, default-features = false, features = ["std"] }
|
||||||
zstd = { version = "0.12.3", optional = true }
|
zstd = { version = "0.12.3", optional = true }
|
||||||
visibility = "0.0.1"
|
|
||||||
|
|
||||||
[target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies]
|
[target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies]
|
||||||
crossbeam-utils = "0.8.15"
|
crossbeam-utils = "0.8.15"
|
||||||
|
|
|
@ -51,9 +51,6 @@ impl FileOperation {
|
||||||
fn do_operation<T>(writer: &mut RefCell<zip_next::ZipWriter<T>>,
|
fn do_operation<T>(writer: &mut RefCell<zip_next::ZipWriter<T>>,
|
||||||
operation: &FileOperation) -> Result<(), Box<dyn std::error::Error>>
|
operation: &FileOperation) -> Result<(), Box<dyn std::error::Error>>
|
||||||
where T: Read + Write + Seek {
|
where T: Read + Write + Seek {
|
||||||
if zip_next::write::validate_name(&operation.get_name()).is_err() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
match operation {
|
match operation {
|
||||||
FileOperation::Write {file, mut options, ..} => {
|
FileOperation::Write {file, mut options, ..} => {
|
||||||
if file.contents.iter().map(Vec::len).sum::<usize>() >= u32::MAX as usize {
|
if file.contents.iter().map(Vec::len).sum::<usize>() >= u32::MAX as usize {
|
||||||
|
|
41
src/read.rs
41
src/read.rs
|
@ -357,10 +357,9 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let supported = if footer64.disk_number != footer64.disk_with_central_directory {
|
let supported = if (footer64.disk_number != footer64.disk_with_central_directory)
|
||||||
unsupported_zip_error("Support for multi-disk files is not implemented")
|
|| (!footer.record_too_small()
|
||||||
} else if !footer.record_too_small()
|
&& footer.disk_number as u32 != locator64.disk_with_central_directory)
|
||||||
&& footer.disk_number as u32 != locator64.disk_with_central_directory
|
|
||||||
{
|
{
|
||||||
unsupported_zip_error("Support for multi-disk files is not implemented")
|
unsupported_zip_error("Support for multi-disk files is not implemented")
|
||||||
} else {
|
} else {
|
||||||
|
@ -371,7 +370,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
archive_offset,
|
archive_offset,
|
||||||
directory_start,
|
directory_start,
|
||||||
footer64.number_of_files as usize,
|
footer64.number_of_files as usize,
|
||||||
supported
|
supported,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,37 +382,39 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
cde_start_pos: u64,
|
cde_start_pos: u64,
|
||||||
) -> ZipResult<(u64, u64, usize)> {
|
) -> ZipResult<(u64, u64, usize)> {
|
||||||
// Check if file has a zip64 footer
|
// Check if file has a zip64 footer
|
||||||
let (archive_offset_64, directory_start_64, number_of_files_64,
|
let (archive_offset_64, directory_start_64, number_of_files_64, supported_64) =
|
||||||
supported_64) =
|
|
||||||
match Self::get_directory_counts_zip64(reader, footer, cde_start_pos) {
|
match Self::get_directory_counts_zip64(reader, footer, cde_start_pos) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(_) => return Self::get_directory_counts_zip32(footer, cde_start_pos)
|
Err(_) => return Self::get_directory_counts_zip32(footer, cde_start_pos),
|
||||||
};
|
};
|
||||||
// Check if it also has a zip32 footer
|
// Check if it also has a zip32 footer
|
||||||
let (archive_offset_32, directory_start_32, number_of_files_32) =
|
let (archive_offset_32, directory_start_32, number_of_files_32) =
|
||||||
match Self::get_directory_counts_zip32(footer, cde_start_pos) {
|
match Self::get_directory_counts_zip32(footer, cde_start_pos) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
supported_64?;
|
supported_64?;
|
||||||
return Ok((archive_offset_64, directory_start_64, number_of_files_64))
|
return Ok((archive_offset_64, directory_start_64, number_of_files_64));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// It has both, so check if the zip64 footer is valid; if not, assume zip32
|
// It has both, so check if the zip64 footer is valid; if not, assume zip32
|
||||||
if archive_offset_64 < u32::MAX as u64 && archive_offset_64 != archive_offset_32
|
if archive_offset_64 < u32::MAX as u64 && archive_offset_64 != archive_offset_32
|
||||||
|| archive_offset_32 != u32::MAX as u64 {
|
|| archive_offset_32 != u32::MAX as u64
|
||||||
|
{
|
||||||
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
||||||
}
|
}
|
||||||
if directory_start_64 < u32::MAX as u64 && directory_start_64 != directory_start_32
|
if directory_start_64 < u32::MAX as u64 && directory_start_64 != directory_start_32
|
||||||
|| directory_start_32 != u32::MAX as u64 {
|
|| directory_start_32 != u32::MAX as u64
|
||||||
|
{
|
||||||
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
||||||
}
|
}
|
||||||
if number_of_files_64 < u32::MAX as usize && number_of_files_64 != number_of_files_32
|
if number_of_files_64 < u32::MAX as usize && number_of_files_64 != number_of_files_32
|
||||||
|| number_of_files_32 != u32::MAX as usize {
|
|| number_of_files_32 != u32::MAX as usize
|
||||||
|
{
|
||||||
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
return Ok((archive_offset_32, directory_start_32, number_of_files_32));
|
||||||
}
|
}
|
||||||
// It is, so we assume a zip64
|
// It is, so we assume a zip64
|
||||||
supported_64?;
|
supported_64?;
|
||||||
return Ok((archive_offset_64, directory_start_64, number_of_files_64))
|
Ok((archive_offset_64, directory_start_64, number_of_files_64))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a ZIP archive, collecting the files it contains
|
/// Read a ZIP archive, collecting the files it contains
|
||||||
|
|
24
src/write.rs
24
src/write.rs
|
@ -439,7 +439,6 @@ impl<W: Write + Seek> ZipWriter<W> {
|
||||||
{
|
{
|
||||||
let header_start = self.inner.get_plain().stream_position()?;
|
let header_start = self.inner.get_plain().stream_position()?;
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
validate_name(&name)?;
|
|
||||||
|
|
||||||
let permissions = options.permissions.unwrap_or(0o100644);
|
let permissions = options.permissions.unwrap_or(0o100644);
|
||||||
let file = ZipFileData {
|
let file = ZipFileData {
|
||||||
|
@ -1034,29 +1033,6 @@ impl<W: Write + Seek> ZipWriter<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(fuzzing, visibility::make(pub))]
|
|
||||||
#[cfg_attr(fuzzing, allow(missing_docs))]
|
|
||||||
pub(crate) fn validate_name(name: &String) -> ZipResult<()> {
|
|
||||||
let bytes = name.as_bytes();
|
|
||||||
let mut current_window = [0u8; 4];
|
|
||||||
for window in bytes.windows(4) {
|
|
||||||
current_window.copy_from_slice(window);
|
|
||||||
let magic_number = u32::from_le_bytes(current_window);
|
|
||||||
match magic_number {
|
|
||||||
spec::ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE => {
|
|
||||||
return Err(InvalidArchive("Filename can't contain ZIP64 end signature"));
|
|
||||||
}
|
|
||||||
spec::ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE => {
|
|
||||||
return Err(InvalidArchive(
|
|
||||||
"Filename can't contain ZIP64 end-locator signature",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write + Seek> Drop for ZipWriter<W> {
|
impl<W: Write + Seek> Drop for ZipWriter<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.inner.is_closed() {
|
if !self.inner.is_closed() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue