relaymsg/showfile: reject whitespace/control chars in a RELAYMSG spoofed nick (defence-in-depth on top of the denylist), and cap the showfile read at 256 KiB so a large /RULES-style file can't stall the core loop

This commit is contained in:
Jean Chevronnet 2026-08-19 01:35:25 +00:00
parent c47fb9a80a
commit 98e5cf4d20
2 changed files with 10 additions and 4 deletions

View file

@ -71,7 +71,7 @@ impl Command for RelayMsg {
if s.find_nick(nick).is_some() || s.remote_nick.contains_key(&nick.to_ascii_lowercase()) { if s.find_nick(nick).is_some() || s.remote_nick.contains_key(&nick.to_ascii_lowercase()) {
return bad(s, "RELAYMSG spoofed nick is already in use"); return bad(s, "RELAYMSG spoofed nick is already in use");
} }
if nick.chars().any(|c| FORBIDDEN.contains(c)) { if nick.chars().any(|c| FORBIDDEN.contains(c) || c.is_whitespace() || c.is_control()) {
return bad(s, "Invalid characters in spoofed nick"); return bad(s, "Invalid characters in spoofed nick");
} }
let seps = s let seps = s

View file

@ -24,13 +24,19 @@ pub fn maybe_show(s: &mut Server, uid: Uid, cmd: &str) -> bool {
return false; return false;
}; };
let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default(); let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default();
match std::fs::read_to_string(&path) { // cap the blocking read so a huge (mis)configured file can't stall the core loop
Ok(body) => { let body = std::fs::File::open(&path).ok().and_then(|f| {
use std::io::Read;
let mut buf = String::new();
f.take(256 * 1024).read_to_string(&mut buf).ok().map(|_| buf)
});
match body {
Some(body) => {
for line in body.lines() { for line in body.lines() {
s.send(uid, format!(":{} NOTICE {nick} :{line}", s.name)); s.send(uid, format!(":{} NOTICE {nick} :{line}", s.name));
} }
} }
Err(_) => s.send( None => s.send(
uid, uid,
format!(":{} NOTICE {nick} :*** {cmd}: file not available.", s.name), format!(":{} NOTICE {nick} :*** {cmd}: file not available.", s.name),
), ),