diff --git a/src/config/capability_map.rs b/src/config/capability_map.rs index 490a34b5..e173ea8f 100644 --- a/src/config/capability_map.rs +++ b/src/config/capability_map.rs @@ -67,9 +67,16 @@ impl CapabilityMapConfig { where P: AsRef, { - let mut file = std::fs::File::open(path)?; + let file = std::fs::File::open(path)?; + + // Read up to a defined maximum size to prevent denial of service + const MAX_SIZE: usize = 512 * 1024; + let mut reader = file.take(MAX_SIZE as u64); let mut content = String::default(); - file.read_to_string(&mut content)?; + let bytes_read = reader.read_to_string(&mut content)?; + if bytes_read == MAX_SIZE { + return Err(LoadError::MaximumSizeReached(MAX_SIZE)); + } Self::from_yaml(content) } diff --git a/src/config/mod.rs b/src/config/mod.rs index aded39c2..f7399547 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,7 @@ pub mod capability_map; pub mod config_test; pub mod path; -use std::io; +use std::io::{self, Read}; use ::procfs::CpuInfo; use capability_map::CapabilityConfig; @@ -28,6 +28,8 @@ pub enum LoadError { IoError(#[from] io::Error), #[error("Unable to deserialize: {0}")] DeserializeError(#[from] serde_yaml::Error), + #[error("Config too large, reached maximum size of {0} bytes")] + MaximumSizeReached(usize), } #[derive(Debug, Deserialize, Serialize, Clone)] @@ -51,8 +53,16 @@ impl DeviceProfile { /// Load a [CapabilityProfile] from the given YAML file pub fn from_yaml_file(path: String) -> Result { let file = std::fs::File::open(path)?; - let device: DeviceProfile = serde_yaml::from_reader(file)?; - Ok(device) + + // Read up to a defined maximum size to prevent denial of service + const MAX_SIZE: usize = 512 * 1024; + let mut reader = file.take(MAX_SIZE as u64); + let mut content = String::default(); + let bytes_read = reader.read_to_string(&mut content)?; + if bytes_read == MAX_SIZE { + return Err(LoadError::MaximumSizeReached(MAX_SIZE)); + } + Self::from_yaml(content) } } @@ -372,7 +382,7 @@ pub struct CompositeDeviceConfig { impl CompositeDeviceConfig { /// Load a [CompositeDevice] from the given YAML string - pub fn _from_yaml(content: String) -> Result { + pub fn from_yaml(content: String) -> Result { let device: CompositeDeviceConfig = serde_yaml::from_str(content.as_str())?; Ok(device) } @@ -380,8 +390,16 @@ impl CompositeDeviceConfig { /// Load a [CompositeDevice] from the given YAML file pub fn from_yaml_file(path: String) -> Result { let file = std::fs::File::open(path)?; - let device: CompositeDeviceConfig = serde_yaml::from_reader(file)?; - Ok(device) + + // Read up to a defined maximum size to prevent denial of service + const MAX_SIZE: usize = 512 * 1024; + let mut reader = file.take(MAX_SIZE as u64); + let mut content = String::default(); + let bytes_read = reader.read_to_string(&mut content)?; + if bytes_read == MAX_SIZE { + return Err(LoadError::MaximumSizeReached(MAX_SIZE)); + } + Self::from_yaml(content) } /// Returns an array of all defined hidraw source devices diff --git a/src/dbus/interface/manager.rs b/src/dbus/interface/manager.rs index e7c3c10f..4c1d375c 100644 --- a/src/dbus/interface/manager.rs +++ b/src/dbus/interface/manager.rs @@ -5,7 +5,7 @@ use zbus::{fdo, message::Header, Connection}; use zbus_macros::interface; use crate::{ - config::CompositeDeviceConfig, + config::{CompositeDeviceConfig, LoadError}, constants::BUS_PREFIX, dbus::{interface::Unregisterable, polkit::check_polkit}, input::{manager::ManagerCommand, target::TargetDeviceTypeId}, @@ -148,8 +148,13 @@ impl ManagerInterface { "org.shadowblip.InputPlumber.CreateCompositeDevice", ) .await?; - let device = CompositeDeviceConfig::from_yaml_file(config_path) - .map_err(|err| fdo::Error::Failed(err.to_string()))?; + let device = CompositeDeviceConfig::from_yaml_file(config_path).map_err(|e| match e { + LoadError::IoError(error) => fdo::Error::Failed(error.to_string()), + LoadError::MaximumSizeReached(error) => fdo::Error::Failed(error.to_string()), + LoadError::DeserializeError(_) => { + fdo::Error::InvalidFileContent("Failed to parse file".to_string()) + } + })?; self.tx .send_timeout( ManagerCommand::CreateCompositeDevice { config: device }, diff --git a/src/input/composite_device/mod.rs b/src/input/composite_device/mod.rs index f47d95ea..0b52664d 100644 --- a/src/input/composite_device/mod.rs +++ b/src/input/composite_device/mod.rs @@ -19,7 +19,7 @@ use zbus::{object_server::Interface, Connection}; use crate::{ config::{ capability_map::CapabilityMapConfig, path::get_profiles_path, CompositeDeviceConfig, - DeviceProfile, ProfileMapping, + DeviceProfile, LoadError, ProfileMapping, }, dbus::interface::{ composite_device::CompositeDeviceInterface, force_feedback::ForceFeedbackInterface, @@ -446,7 +446,14 @@ impl CompositeDevice { let profile = match DeviceProfile::from_yaml_file(path.clone()) { Ok(p) => p, Err(e) => { - if let Err(er) = sender.send(Err(e.to_string())).await { + let err = match e { + LoadError::IoError(_) => e.to_string(), + LoadError::MaximumSizeReached(_) => e.to_string(), + LoadError::DeserializeError(_) => { + "Failed to parse file".to_string() + } + }; + if let Err(er) = sender.send(Err(err)).await { log::error!("Failed to send failed to load profile: {er:?}"); } continue;