128 mebibyte input limit for filesystem state data

- Bug fix applied to transaction filter
- Miscellaneous cleanup in filesystem module
This commit is contained in:
Xavier Moffett 2024-03-08 00:31:54 -05:00
parent 03ce77c235
commit 5da6dc5ba2
2 changed files with 39 additions and 22 deletions

View file

@ -21,7 +21,7 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt::{Display, Error as FmtError, Formatter}, fmt::{Display, Error as FmtError, Formatter},
fs::{self, create_dir_all, hard_link, metadata, remove_dir_all, remove_file, File, Metadata}, 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}, os::unix::{fs::symlink, prelude::MetadataExt},
path::Path, path::Path,
sync::{ sync::{
@ -30,6 +30,7 @@ use std::{
}, },
}; };
use bincode::Options;
use dialoguer::console::Term; use dialoguer::console::Term;
use indexmap::IndexMap; use indexmap::IndexMap;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
@ -51,8 +52,9 @@ use crate::{
ErrorTrait, ErrorTrait,
}; };
static VERSION: u32 = 2; const VERSION: u32 = 2;
static MAGIC_NUMBER: u32 = 408948530; const MAGIC_NUMBER: u32 = 408948530;
const BYTE_LIMIT: u64 = 134217728;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
struct FileSystemState { struct FileSystemState {
@ -90,7 +92,7 @@ impl Display for FilesystemStateError {
} }
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone, PartialEq)]
enum FileType { enum FileType {
HardLink, HardLink,
SymLink, SymLink,
@ -423,7 +425,12 @@ impl SyncType {
} }
fn deserialize<R: Read, T: for<'de> Deserialize<'de>>(instance: &str, reader: R) -> Result<T, Error> { fn deserialize<R: Read, T: for<'de> Deserialize<'de>>(instance: &str, reader: R) -> Result<T, Error> {
match bincode::deserialize_from::<R, T>(reader) { match bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(BYTE_LIMIT)
.deserialize_from::<R, T>(reader)
{
Ok(state) => Ok(state), Ok(state) => Ok(state),
Err(err) => err!(FilesystemStateError::DeserializationFailure(instance.into(), err.to_string())), Err(err) => err!(FilesystemStateError::DeserializationFailure(instance.into(), err.to_string())),
} }
@ -435,7 +442,12 @@ fn serialize(dep: Arc<str>, ds: FileSystemState) -> Result<(), Error> {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
let mut state_data = Vec::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()))? 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<u8>, bool)> {
stream.read_exact(&mut header_buffer.as_slice_mut())?; stream.read_exact(&mut header_buffer.as_slice_mut())?;
let mut hash_buffer = vec![0; header_buffer.read_le_16() as usize]; let hash_length = header_buffer.read_le_16();
let mut state_buffer = vec![0; header_buffer.read_le_64() as usize]; 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)?; stream.read_exact(&mut hash_buffer)?;
@ -556,11 +578,7 @@ fn obtain_state(root: Arc<str>, state: &mut FileSystemState) {
} }
fn link_filesystem(state: &FileSystemState, root: &str) { fn link_filesystem(state: &FileSystemState, root: &str) {
state.files.par_iter().for_each(|file| { state.files.par_iter().filter(|a| a.1 .0 != FileType::Directory).for_each(|file| {
if let FileType::Directory = file.1 .0 {
return;
}
let path = &format!("{}{}", root, file.0); let path = &format!("{}{}", root, file.0);
if let FileType::SymLink = file.1 .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, rx) = mpsc::sync_channel(0);
let tx_clone: mpsc::SyncSender<()> = tx.clone(); 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; let _ = tx_clone;
if let FileType::Directory = file.1 .0 {
return;
}
if let None = state.files.get(file.0) { if let None = state.files.get(file.0) {
let path_str = &format!("{}{}", root, file.0); let path_str = &format!("{}{}", root, file.0);
let path = Path::new(path_str); let path = Path::new(path_str);

View file

@ -421,11 +421,14 @@ impl<'a> TransactionHandle<'a> {
for pkg in packages for pkg in packages
.iter() .iter()
.filter(|a| { .filter(|a| !self.meta.ignored_pkgs.contains(a.name()))
!self.meta.ignored_pkgs.contains(a.name()) .filter_map(|a| {
&& !(self.meta.mode == TransactionMode::Foreign && self.meta.foreign_pkgs.contains(a.name())) if let (None, TransactionMode::Foreign) = (self.meta.foreign_pkgs.get(a.name()), self.meta.mode) {
None
} else {
Some(*a)
}
}) })
.map(|a| *a)
.collect::<Vec<Package<'_>>>() .collect::<Vec<Package<'_>>>()
{ {
if !self.agent && config.alpm().ignored().contains(&pkg.name()) { if !self.agent && config.alpm().ignored().contains(&pkg.name()) {