syslog: strip control chars (CR/LF) from the message before framing — a snotice carrying user-influenced text (nick/realname/quit reason) with an embedded newline could inject a forged syslog record; matches the CR/LF care the JSON log path already takes

This commit is contained in:
Jean Chevronnet 2026-08-19 00:42:30 +00:00
parent d9d5bd069b
commit 25702c9541

View file

@ -83,7 +83,13 @@ pub fn tee(s: &Server, msg: &str) {
let tag = s.conf("syslog_tag").unwrap_or("echoircd"); let tag = s.conf("syslog_tag").unwrap_or("echoircd");
// severity "notice" (5); PRI = facility*8 + severity // severity "notice" (5); PRI = facility*8 + severity
let pri = facility(s.conf("syslog_facility").unwrap_or("daemon")) as u16 * 8 + 5; let pri = facility(s.conf("syslog_facility").unwrap_or("daemon")) as u16 * 8 + 5;
let line = format!("<{pri}>{tag}[{}]: {msg}", std::process::id()); // Neutralise control chars (esp. CR/LF): an snotice can carry user-influenced
// text (nick/realname/quit reason), and a raw newline would forge a syslog record.
let safe: String = msg
.chars()
.map(|c| if (c as u32) < 0x20 || c == '\x7f' { ' ' } else { c })
.collect();
let line = format!("<{pri}>{tag}[{}]: {safe}", std::process::id());
SINK.with(|cell| { SINK.with(|cell| {
let mut slot = cell.borrow_mut(); let mut slot = cell.borrow_mut();
// (re)open if the target changed or nothing is open yet // (re)open if the target changed or nothing is open yet