fix: Prevent panic after reading an invalid LZMA file
This commit is contained in:
parent
8868a11d23
commit
d13031cc14
1 changed files with 17 additions and 25 deletions
42
src/read.rs
42
src/read.rs
|
@ -13,7 +13,7 @@ use crate::types::{AesMode, AesVendorVersion, DateTime, System, ZipFileData};
|
||||||
use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator};
|
use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::{self, empty, Empty, prelude::*};
|
use std::io::{self, copy, prelude::*, sink};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
@ -171,13 +171,10 @@ impl<'a> Read for ZipFileReader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EMPTY: Empty = empty();
|
|
||||||
|
|
||||||
impl<'a> ZipFileReader<'a> {
|
impl<'a> ZipFileReader<'a> {
|
||||||
|
|
||||||
/// Consumes this decoder, returning the underlying reader.
|
/// Consumes this decoder, returning the underlying reader.
|
||||||
pub fn into_inner(self) -> io::Take<&'a mut dyn Read> {
|
pub fn drain(self) {
|
||||||
match self {
|
let mut inner = match self {
|
||||||
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
|
||||||
ZipFileReader::Raw(r) => r,
|
ZipFileReader::Raw(r) => r,
|
||||||
ZipFileReader::Stored(r) => r.into_inner().into_inner(),
|
ZipFileReader::Stored(r) => r.into_inner().into_inner(),
|
||||||
|
@ -191,10 +188,15 @@ impl<'a> ZipFileReader<'a> {
|
||||||
ZipFileReader::Zstd(r) => r.into_inner().finish().into_inner().into_inner(),
|
ZipFileReader::Zstd(r) => r.into_inner().finish().into_inner().into_inner(),
|
||||||
#[cfg(feature = "lzma")]
|
#[cfg(feature = "lzma")]
|
||||||
ZipFileReader::Lzma(r) => {
|
ZipFileReader::Lzma(r) => {
|
||||||
let _ = r.into_inner().finish();
|
// Lzma reader owns its buffer rather than mutably borrowing it, so we have to drop
|
||||||
Read::take(unsafe {((&EMPTY as *const Empty) as *mut Empty).as_mut()}.unwrap(), 0)
|
// it separately
|
||||||
|
if let Ok(mut remaining) = r.into_inner().finish() {
|
||||||
|
let _ = copy(&mut remaining, &mut sink());
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
let _ = copy(&mut inner, &mut sink());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,30 +1214,20 @@ impl<'a> Drop for ZipFile<'a> {
|
||||||
// self.data is Owned, this reader is constructed by a streaming reader.
|
// self.data is Owned, this reader is constructed by a streaming reader.
|
||||||
// In this case, we want to exhaust the reader so that the next file is accessible.
|
// In this case, we want to exhaust the reader so that the next file is accessible.
|
||||||
if let Cow::Owned(_) = self.data {
|
if let Cow::Owned(_) = self.data {
|
||||||
let mut buffer = [0; 1 << 16];
|
|
||||||
|
|
||||||
// Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped.
|
// Get the inner `Take` reader so all decryption, decompression and CRC calculation is skipped.
|
||||||
let mut reader: io::Take<&mut dyn Read> = match &mut self.reader {
|
match &mut self.reader {
|
||||||
ZipFileReader::NoReader => {
|
ZipFileReader::NoReader => {
|
||||||
let innerreader = self.crypto_reader.take();
|
let innerreader = self.crypto_reader.take();
|
||||||
innerreader.expect("Invalid reader state").into_inner()
|
let _ = copy(
|
||||||
|
&mut innerreader.expect("Invalid reader state").into_inner(),
|
||||||
|
&mut sink(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
reader => {
|
reader => {
|
||||||
let innerreader = std::mem::replace(reader, ZipFileReader::NoReader);
|
let innerreader = std::mem::replace(reader, ZipFileReader::NoReader);
|
||||||
innerreader.into_inner()
|
innerreader.drain();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(clippy::unused_io_amount)]
|
|
||||||
loop {
|
|
||||||
match reader.read(&mut buffer) {
|
|
||||||
Ok(0) => break,
|
|
||||||
Ok(_read) => (),
|
|
||||||
Err(e) => {
|
|
||||||
panic!("Could not consume all of the output of the current ZipFile: {e:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue