fix: improve path traversal check

The previous implementation would falsely detect a path traversal in a
filename such as "foo... bar".
This patch changes the check function so that it inspects `PathBuf`
components instead of substrings.
This commit is contained in:
owl 2025-05-08 22:16:11 +02:00
parent 1307148a05
commit f020673032
No known key found for this signature in database

View file

@ -3,7 +3,7 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
io::Read, io::Read,
net::SocketAddr, net::SocketAddr,
path::{Path, PathBuf}, path::{Component, Path, PathBuf},
sync::{atomic::AtomicUsize, Arc}, sync::{atomic::AtomicUsize, Arc},
time::Duration, time::Duration,
}; };
@ -994,8 +994,12 @@ impl Session {
if files.len() < 2 { if files.len() < 2 {
return Ok(None); return Ok(None);
} }
fn check_valid(name: &str) -> anyhow::Result<()> {
if name.contains("/") || name.contains("\\") || name.contains("..") { fn check_valid(pb: &PathBuf) -> anyhow::Result<()> {
if pb.components().into_iter().any(|x| match x {
Component::Normal(_) => false,
_ => true,
}) {
bail!("path traversal in torrent name detected") bail!("path traversal in torrent name detected")
} }
Ok(()) Ok(())
@ -1004,12 +1008,14 @@ impl Session {
if let Some(name) = &info.name { if let Some(name) = &info.name {
let s = let s =
std::str::from_utf8(name.as_slice()).context("invalid UTF-8 in torrent name")?; std::str::from_utf8(name.as_slice()).context("invalid UTF-8 in torrent name")?;
check_valid(s)?; let pb = PathBuf::from(s);
return Ok(Some(PathBuf::from(s))); check_valid(&pb)?;
return Ok(Some(pb));
}; };
if let Some(name) = magnet_name { if let Some(name) = magnet_name {
check_valid(name)?; let pb = PathBuf::from(name);
return Ok(Some(PathBuf::from(name))); check_valid(&pb)?;
return Ok(Some(pb));
} }
// Let the subfolder name be the longest filename // Let the subfolder name be the longest filename
let longest = files let longest = files