diff options
| author | murilo ijanc | 2026-03-25 14:22:21 -0300 |
|---|---|---|
| committer | murilo ijanc | 2026-03-25 14:22:21 -0300 |
| commit | b9f813fb4b7de1042370b529b9ccc036b208465b (patch) | |
| tree | 488568d9216bf8ea62625eedc7dc718e8afbd690 /src/daemon.rs | |
| parent | 57176d45cacb98f1968daa8f8b2efd2735da2731 (diff) | |
| download | tesseras-paste-b9f813fb4b7de1042370b529b9ccc036b208465b.tar.gz | |
Fix critical data integrity and security issues
- Atomic writes in store (write-to-temp + rename) to prevent
corruption on crash
- Validate DHT results against requested content hash to reject
forged data from malicious nodes
- Limit protocol line size to 128 KiB on Unix socket to prevent
memory exhaustion
- Use saturating_add for TTL expiry to prevent u64 overflow
Diffstat (limited to 'src/daemon.rs')
| -rw-r--r-- | src/daemon.rs | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index 313a4aa..c578e5c 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -6,7 +6,7 @@ //! over a Unix socket using a line-oriented text protocol //! (see [`crate::protocol`]). -use std::io::{BufRead, BufReader, Write}; +use std::io::{BufRead, BufReader, Read, Write}; use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc; @@ -196,7 +196,7 @@ fn republish(node: &mut Node, store: &PasteStore) { .duration_since(std::time::UNIX_EPOCH) .unwrap_or_default() .as_secs(); - let expires = paste.created_at + paste.ttl_secs; + let expires = paste.created_at.saturating_add(paste.ttl_secs); let rem = expires.saturating_sub(now); std::cmp::min(rem, u16::MAX as u64) as u16 }; @@ -259,6 +259,10 @@ pub fn run_unix_listener( let _ = std::fs::remove_file(sock_path); } +/// Maximum protocol line size (128 KiB covers the 64 KiB paste +/// limit after base58 expansion plus command overhead). +const MAX_LINE_SIZE: usize = 128 * 1024; + /// Read requests line-by-line from a connected Unix socket /// client, forwarding each to the daemon main loop via `tx`. fn handle_client( @@ -268,11 +272,29 @@ fn handle_client( stream.set_nonblocking(false)?; stream.set_read_timeout(Some(Duration::from_secs(60)))?; - let reader = BufReader::new(&stream); + let mut reader = BufReader::new(&stream); let mut writer = &stream; - - for line in reader.lines() { - let line = line?; + let mut line = String::new(); + + loop { + line.clear(); + // Limit read to MAX_LINE_SIZE to prevent a client from + // exhausting memory with an unbounded request line. + let n = (&mut reader).take(MAX_LINE_SIZE as u64).read_line(&mut line)?; + if n == 0 { + break; + } + if !line.ends_with('\n') && n >= MAX_LINE_SIZE { + let resp = protocol::format_response(&Response::Err( + "request too large".into(), + )); + writer.write_all(resp.as_bytes())?; + // Drain remaining bytes until newline + let mut discard = String::new(); + let _ = reader.read_line(&mut discard); + continue; + } + let line = line.trim(); let cmd = match protocol::parse_request(&line) { Ok(c) => c, Err(e) => { |