🔒 Fix potential memory exhaustion in socket reads (#59)

Addresses a security vulnerability where the daemon or client could be
forced to allocate up to 10MB of memory per malformed socket message,
potentially leading to Out-Of-Memory (OOM) crashes.

Changes:
- Introduced a central `MAX_MESSAGE_SIZE` constant of 128KB in `src/types/socket.rs`.
- Enforced the 128KB limit on incoming requests in `src/bin/daemon.rs`.
- Enforced the 128KB limit on incoming responses in `src/utils/daemon.rs`.
- Preserved detailed `eprintln!` logging when messages are rejected.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
Tarasov Aleksandr
2026-04-17 13:56:29 +03:00
committed by GitHub
parent 5367a3daae
commit 70c7e3789b
3 changed files with 13 additions and 3 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
use pwsp::{ use pwsp::{
types::socket::{Request, Response}, types::socket::{Request, Response, MAX_MESSAGE_SIZE},
utils::{ utils::{
commands::parse_command, commands::parse_command,
daemon::{ daemon::{
@@ -109,7 +109,7 @@ async fn commands_loop(listener: UnixListener) -> Result<(), Box<dyn Error>> {
let request_len = u32::from_le_bytes(len_bytes) as usize; let request_len = u32::from_le_bytes(len_bytes) as usize;
if request_len > 10 * 1024 * 1024 { if request_len > MAX_MESSAGE_SIZE {
eprintln!( eprintln!(
"Failed to read message from client: request too large ({} bytes)!", "Failed to read message from client: request too large ({} bytes)!",
request_len request_len
+2
View File
@@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
pub const MAX_MESSAGE_SIZE: usize = 128 * 1024;
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Request { pub struct Request {
pub name: String, pub name: String,
+9 -1
View File
@@ -2,7 +2,7 @@ use crate::{
types::{ types::{
audio_player::AudioPlayer, audio_player::AudioPlayer,
config::DaemonConfig, config::DaemonConfig,
socket::{Request, Response}, socket::{Request, Response, MAX_MESSAGE_SIZE},
}, },
utils::pipewire::{create_link, get_device}, utils::pipewire::{create_link, get_device},
}; };
@@ -135,6 +135,14 @@ pub async fn make_request(request: Request) -> Result<Response, Box<dyn Error +
} }
let response_len = u32::from_le_bytes(len_bytes) as usize; let response_len = u32::from_le_bytes(len_bytes) as usize;
if response_len > MAX_MESSAGE_SIZE {
eprintln!(
"Failed to read response from daemon: response too large ({} bytes)!",
response_len
);
return Err("Response too large".into());
}
let mut buffer = vec![0u8; response_len]; let mut buffer = vec![0u8; response_len];
if stream.read_exact(&mut buffer).await.is_err() { if stream.read_exact(&mut buffer).await.is_err() {
return Err("Failed to read response".into()); return Err("Failed to read response".into());