From 5da6dc5ba2929660f67bc067ee0fe38a0a55a297 Mon Sep 17 00:00:00 2001 From: Xavier Date: Fri, 8 Mar 2024 00:31:54 -0500 Subject: [PATCH] 128 mebibyte input limit for filesystem state data - Bug fix applied to transaction filter - Miscellaneous cleanup in filesystem module --- pacwrap-core/src/sync/filesystem.rs | 50 ++++++++++++++++++---------- pacwrap-core/src/sync/transaction.rs | 11 +++--- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/pacwrap-core/src/sync/filesystem.rs b/pacwrap-core/src/sync/filesystem.rs index f04a8d6..a6c2628 100644 --- a/pacwrap-core/src/sync/filesystem.rs +++ b/pacwrap-core/src/sync/filesystem.rs @@ -21,7 +21,7 @@ use std::{ collections::{HashMap, HashSet}, fmt::{Display, Error as FmtError, Formatter}, fs::{self, create_dir_all, hard_link, metadata, remove_dir_all, remove_file, File, Metadata}, - io::{copy, BufReader, ErrorKind as IOErrorKind, Read, Result as IOResult, Write}, + io::{copy, BufReader, Error as IOError, ErrorKind as IOErrorKind, Read, Result as IOResult, Write}, os::unix::{fs::symlink, prelude::MetadataExt}, path::Path, sync::{ @@ -30,6 +30,7 @@ use std::{ }, }; +use bincode::Options; use dialoguer::console::Term; use indexmap::IndexMap; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; @@ -51,8 +52,9 @@ use crate::{ ErrorTrait, }; -static VERSION: u32 = 2; -static MAGIC_NUMBER: u32 = 408948530; +const VERSION: u32 = 2; +const MAGIC_NUMBER: u32 = 408948530; +const BYTE_LIMIT: u64 = 134217728; #[derive(Serialize, Deserialize, Clone)] struct FileSystemState { @@ -90,7 +92,7 @@ impl Display for FilesystemStateError { } } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, PartialEq)] enum FileType { HardLink, SymLink, @@ -423,7 +425,12 @@ impl SyncType { } fn deserialize Deserialize<'de>>(instance: &str, reader: R) -> Result { - match bincode::deserialize_from::(reader) { + match bincode::options() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_limit(BYTE_LIMIT) + .deserialize_from::(reader) + { Ok(state) => Ok(state), Err(err) => err!(FilesystemStateError::DeserializationFailure(instance.into(), err.to_string())), } @@ -435,7 +442,12 @@ fn serialize(dep: Arc, ds: FileSystemState) -> Result<(), Error> { let mut hasher = Sha256::new(); let mut state_data = Vec::new(); - if let Err(err) = bincode::serialize_into(&mut state_data, &ds) { + if let Err(err) = bincode::options() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_limit(BYTE_LIMIT) + .serialize_into(&mut state_data, &ds) + { err!(FilesystemStateError::SerializationFailure(error_path.into(), err.as_ref().to_string()))? } @@ -449,8 +461,18 @@ fn decode_state<'a, R: Read>(mut stream: R) -> IOResult<(Vec, bool)> { stream.read_exact(&mut header_buffer.as_slice_mut())?; - let mut hash_buffer = vec![0; header_buffer.read_le_16() as usize]; - let mut state_buffer = vec![0; header_buffer.read_le_64() as usize]; + let hash_length = header_buffer.read_le_16(); + let state_length = header_buffer.read_le_64(); + + if state_length >= BYTE_LIMIT { + Err(IOError::new( + IOErrorKind::InvalidInput, + format!("Data length provided exceeded maximum {state_length} >= {BYTE_LIMIT}"), + ))?; + } + + let mut hash_buffer = vec![0; hash_length as usize]; + let mut state_buffer = vec![0; state_length as usize]; stream.read_exact(&mut hash_buffer)?; @@ -556,11 +578,7 @@ fn obtain_state(root: Arc, state: &mut FileSystemState) { } fn link_filesystem(state: &FileSystemState, root: &str) { - state.files.par_iter().for_each(|file| { - if let FileType::Directory = file.1 .0 { - return; - } - + state.files.par_iter().filter(|a| a.1 .0 != FileType::Directory).for_each(|file| { let path = &format!("{}{}", root, file.0); if let FileType::SymLink = file.1 .0 { @@ -579,13 +597,9 @@ fn delete_files(state: &FileSystemState, state_res: &FileSystemState, root: &str let (tx, rx) = mpsc::sync_channel(0); let tx_clone: mpsc::SyncSender<()> = tx.clone(); - state_res.files.par_iter().for_each(|file| { + state_res.files.par_iter().filter(|a| a.1 .0 != FileType::Directory).for_each(|file| { let _ = tx_clone; - if let FileType::Directory = file.1 .0 { - return; - } - if let None = state.files.get(file.0) { let path_str = &format!("{}{}", root, file.0); let path = Path::new(path_str); diff --git a/pacwrap-core/src/sync/transaction.rs b/pacwrap-core/src/sync/transaction.rs index 9fa96a8..3b1cf43 100644 --- a/pacwrap-core/src/sync/transaction.rs +++ b/pacwrap-core/src/sync/transaction.rs @@ -421,11 +421,14 @@ impl<'a> TransactionHandle<'a> { for pkg in packages .iter() - .filter(|a| { - !self.meta.ignored_pkgs.contains(a.name()) - && !(self.meta.mode == TransactionMode::Foreign && self.meta.foreign_pkgs.contains(a.name())) + .filter(|a| !self.meta.ignored_pkgs.contains(a.name())) + .filter_map(|a| { + if let (None, TransactionMode::Foreign) = (self.meta.foreign_pkgs.get(a.name()), self.meta.mode) { + None + } else { + Some(*a) + } }) - .map(|a| *a) .collect::>>() { if !self.agent && config.alpm().ignored().contains(&pkg.name()) {