diff options
| author | igorechek06 <me@igorek.dev> | 2024-08-10 17:18:03 +0900 |
|---|---|---|
| committer | igorechek06 <me@igorek.dev> | 2024-08-10 17:18:43 +0900 |
| commit | 866516ac50851e2827e6aff0a98c444268c566ff (patch) | |
| tree | 1134bf6f714d75a1050befa0f67bddd2d4b085c8 | |
| parent | 51f2737ca7af016e3dd3ad03673f48a754a1642e (diff) | |
| download | archivator-866516ac50851e2827e6aff0a98c444268c566ff.tar.gz archivator-866516ac50851e2827e6aff0a98c444268c566ff.zip | |
Add overlap checking
| -rw-r--r-- | src/utils/cursor.rs | 2 | ||||
| -rw-r--r-- | src/zip/driver.rs | 26 | ||||
| -rw-r--r-- | src/zip/encryption/aes.rs | 1 | ||||
| -rw-r--r-- | src/zip/encryption/weak.rs | 1 | ||||
| -rw-r--r-- | src/zip/error.rs | 17 |
5 files changed, 31 insertions, 16 deletions
diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index ee80474..cde846d 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs | |||
| @@ -6,7 +6,7 @@ pub struct IoCursor<Io> { | |||
| 6 | bounds: (u64, u64), | 6 | bounds: (u64, u64), |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | impl<Io: Seek> IoCursor<Io> { | 9 | impl<Io> IoCursor<Io> { |
| 10 | pub fn new(io: Io, cursor: u64, end: u64) -> Self { | 10 | pub fn new(io: Io, cursor: u64, end: u64) -> Self { |
| 11 | Self { | 11 | Self { |
| 12 | io, | 12 | io, |
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index b4217c8..9dccfd0 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; | 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; |
| 2 | use crate::utils::ReadUtils; | 2 | use crate::utils::{IoCursor, ReadUtils}; |
| 3 | use crate::zip::cp437::FromCp437; | 3 | use crate::zip::cp437::FromCp437; |
| 4 | use crate::zip::datetime::DosDateTime; | 4 | use crate::zip::datetime::DosDateTime; |
| 5 | use crate::zip::structs::{ | 5 | use crate::zip::structs::{ |
| @@ -106,12 +106,19 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 106 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; | 106 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; |
| 107 | let buf = io.read_arr::<56>()?; | 107 | let buf = io.read_arr::<56>()?; |
| 108 | if buf[0..4] != EOCDR64_SIGNATURE { | 108 | if buf[0..4] != EOCDR64_SIGNATURE { |
| 109 | return Err(ZipError::InvalidEOCDR64Signature); | 109 | return Err(ZipError::InvalidEocdr64Signature); |
| 110 | } | 110 | } |
| 111 | let eocdr64: Eocdr64 = deserialize(&buf[4..]).unwrap(); | 111 | let eocdr64: Eocdr64 = deserialize(&buf[4..]).unwrap(); |
| 112 | if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { | ||
| 113 | return Err(ZipError::Overlapping("Central directory records", "Zip64 end of central directory record")); | ||
| 114 | } | ||
| 112 | 115 | ||
| 113 | (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) | 116 | (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) |
| 114 | } else { | 117 | } else { |
| 118 | if (eocdr.cd_pointer + eocdr.cd_size) as u64 > pos { | ||
| 119 | return Err(ZipError::Overlapping("Central directory records", "End of central directory record")); | ||
| 120 | } | ||
| 121 | |||
| 115 | ( | 122 | ( |
| 116 | eocdr.cd_pointer as u64, | 123 | eocdr.cd_pointer as u64, |
| 117 | eocdr.cd_size as u64, | 124 | eocdr.cd_size as u64, |
| @@ -123,27 +130,30 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 123 | let mut indexes = Map::with_capacity(cd_records as usize); | 130 | let mut indexes = Map::with_capacity(cd_records as usize); |
| 124 | let mut files = Vec::with_capacity(cd_records as usize); | 131 | let mut files = Vec::with_capacity(cd_records as usize); |
| 125 | io.seek(SeekFrom::Start(cd_pointer))?; | 132 | io.seek(SeekFrom::Start(cd_pointer))?; |
| 126 | let mut buf_reader = BufReader::with_capacity(cd_size.min(131072) as usize, &mut io); | 133 | let mut cd_reader = BufReader::with_capacity( |
| 134 | cd_size.min(131072) as usize, | ||
| 135 | IoCursor::new(&mut io, cd_pointer, cd_pointer + cd_size), | ||
| 136 | ); | ||
| 127 | 137 | ||
| 128 | for i in 0..cd_records as usize { | 138 | for i in 0..cd_records as usize { |
| 129 | let buf = buf_reader.read_arr::<46>()?; | 139 | let buf = cd_reader.read_arr::<46>()?; |
| 130 | 140 | ||
| 131 | if buf[..4] != CDR_SIGNATURE { | 141 | if buf[..4] != CDR_SIGNATURE { |
| 132 | return Err(ZipError::InvalidCDRSignature); | 142 | return Err(ZipError::InvalidCdrSignature); |
| 133 | } | 143 | } |
| 134 | let cdr: Cdr = deserialize(&buf[4..46]).unwrap(); | 144 | let cdr: Cdr = deserialize(&buf[4..46]).unwrap(); |
| 135 | let bit_flag = BitFlag::new(cdr.bit_flag); | 145 | let bit_flag = BitFlag::new(cdr.bit_flag); |
| 136 | 146 | ||
| 137 | let name = buf_reader.read_vec(cdr.name_len as usize)?; | 147 | let name = cd_reader.read_vec(cdr.name_len as usize)?; |
| 138 | let name = if bit_flag.is_utf8() { | 148 | let name = if bit_flag.is_utf8() { |
| 139 | String::from_utf8(name).map_err(|_| ZipError::InvalidFileName)? | 149 | String::from_utf8(name).map_err(|_| ZipError::InvalidFileName)? |
| 140 | } else { | 150 | } else { |
| 141 | String::from_cp437(name) | 151 | String::from_cp437(name) |
| 142 | }; | 152 | }; |
| 143 | 153 | ||
| 144 | let extra_fields = buf_reader.read_vec(cdr.extra_field_len as usize)?; | 154 | let extra_fields = cd_reader.read_vec(cdr.extra_field_len as usize)?; |
| 145 | 155 | ||
| 146 | let comment = buf_reader.read_vec(cdr.comment_len as usize)?; | 156 | let comment = cd_reader.read_vec(cdr.comment_len as usize)?; |
| 147 | let comment = if bit_flag.is_utf8() { | 157 | let comment = if bit_flag.is_utf8() { |
| 148 | String::from_utf8(comment).map_err(|_| ZipError::InvalidFileComment)? | 158 | String::from_utf8(comment).map_err(|_| ZipError::InvalidFileComment)? |
| 149 | } else { | 159 | } else { |
diff --git a/src/zip/encryption/aes.rs b/src/zip/encryption/aes.rs index b690482..376d01e 100644 --- a/src/zip/encryption/aes.rs +++ b/src/zip/encryption/aes.rs | |||
| @@ -2,7 +2,6 @@ use aes::cipher::generic_array::GenericArray; | |||
| 2 | use aes::cipher::BlockEncrypt; | 2 | use aes::cipher::BlockEncrypt; |
| 3 | use std::io::{Read, Result as IoResult}; | 3 | use std::io::{Read, Result as IoResult}; |
| 4 | 4 | ||
| 5 | #[allow(dead_code)] | ||
| 6 | pub struct AesDecoder<Io: Read, Aes: BlockEncrypt> { | 5 | pub struct AesDecoder<Io: Read, Aes: BlockEncrypt> { |
| 7 | io: Io, | 6 | io: Io, |
| 8 | aes: Aes, | 7 | aes: Aes, |
diff --git a/src/zip/encryption/weak.rs b/src/zip/encryption/weak.rs index ebddb2d..3c35776 100644 --- a/src/zip/encryption/weak.rs +++ b/src/zip/encryption/weak.rs | |||
| @@ -55,7 +55,6 @@ impl Keys { | |||
| 55 | self.key2 = crc32((self.key1 >> 24) as u8, self.key2); | 55 | self.key2 = crc32((self.key1 >> 24) as u8, self.key2); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | #[allow(dead_code)] | ||
| 59 | pub fn encode_bytes(&mut self, byte: u8) -> u8 { | 58 | pub fn encode_bytes(&mut self, byte: u8) -> u8 { |
| 60 | let key = self.key2 | 2; | 59 | let key = self.key2 | 2; |
| 61 | self.update(byte); | 60 | self.update(byte); |
diff --git a/src/zip/error.rs b/src/zip/error.rs index 87cd9e9..dbb6bb5 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -9,9 +9,11 @@ pub enum ZipError { | |||
| 9 | Io(IoError), | 9 | Io(IoError), |
| 10 | 10 | ||
| 11 | EocdrNotFound, | 11 | EocdrNotFound, |
| 12 | InvalidEOCDR64Signature, | 12 | InvalidEocdr64Signature, |
| 13 | InvalidFileHeaderSignature, | 13 | InvalidFileHeaderSignature, |
| 14 | InvalidCDRSignature, | 14 | InvalidCdrSignature, |
| 15 | |||
| 16 | Overlapping(&'static str, &'static str), | ||
| 15 | 17 | ||
| 16 | UnsupportedCompressionMethod(u16), | 18 | UnsupportedCompressionMethod(u16), |
| 17 | UnsupportedEncryptionMethod, | 19 | UnsupportedEncryptionMethod, |
| @@ -53,8 +55,9 @@ impl Display for ZipError { | |||
| 53 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 55 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 54 | match self { | 56 | match self { |
| 55 | Self::Io(error) => write!(f, "{}", error), | 57 | Self::Io(error) => write!(f, "{}", error), |
| 58 | |||
| 56 | Self::EocdrNotFound => write!(f, "End of central directory record not found"), | 59 | Self::EocdrNotFound => write!(f, "End of central directory record not found"), |
| 57 | Self::InvalidEOCDR64Signature => { | 60 | Self::InvalidEocdr64Signature => { |
| 58 | write!( | 61 | write!( |
| 59 | f, | 62 | f, |
| 60 | "Invalid signature of zip64 end of central directory record" | 63 | "Invalid signature of zip64 end of central directory record" |
| @@ -63,12 +66,16 @@ impl Display for ZipError { | |||
| 63 | Self::InvalidFileHeaderSignature => { | 66 | Self::InvalidFileHeaderSignature => { |
| 64 | write!(f, "Invalid file header signature") | 67 | write!(f, "Invalid file header signature") |
| 65 | } | 68 | } |
| 66 | Self::InvalidCDRSignature => { | 69 | Self::InvalidCdrSignature => { |
| 67 | write!(f, "Invalid signature of central directory record") | 70 | write!(f, "Invalid signature of central directory record") |
| 68 | } | 71 | } |
| 69 | 72 | ||
| 73 | Self::Overlapping(struct1, struct2) => { | ||
| 74 | write!(f, "`{}` overlapt `{}`", struct1, struct2) | ||
| 75 | } | ||
| 76 | |||
| 70 | Self::UnsupportedCompressionMethod(id) => { | 77 | Self::UnsupportedCompressionMethod(id) => { |
| 71 | writeln!(f, "Unsupported compression method {}", id) | 78 | writeln!(f, "Unsupported compression method `{}`", id) |
| 72 | } | 79 | } |
| 73 | Self::UnsupportedEncryptionMethod => { | 80 | Self::UnsupportedEncryptionMethod => { |
| 74 | writeln!(f, "Unsupported encryption method") | 81 | writeln!(f, "Unsupported encryption method") |
