From 25702c9541e928dba22ff1e1b7e657dfe7a74e56 Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 00:42:30 +0000 Subject: [PATCH] =?UTF-8?q?syslog:=20strip=20control=20chars=20(CR/LF)=20f?= =?UTF-8?q?rom=20the=20message=20before=20framing=20=E2=80=94=20a=20snotic?= =?UTF-8?q?e=20carrying=20user-influenced=20text=20(nick/realname/quit=20r?= =?UTF-8?q?eason)=20with=20an=20embedded=20newline=20could=20inject=20a=20?= =?UTF-8?q?forged=20syslog=20record;=20matches=20the=20CR/LF=20care=20the?= =?UTF-8?q?=20JSON=20log=20path=20already=20takes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/syslog.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/syslog.rs b/src/modules/syslog.rs index 08023a5..db329c8 100644 --- a/src/modules/syslog.rs +++ b/src/modules/syslog.rs @@ -83,7 +83,13 @@ pub fn tee(s: &Server, msg: &str) { let tag = s.conf("syslog_tag").unwrap_or("echoircd"); // severity "notice" (5); PRI = facility*8 + severity 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| { let mut slot = cell.borrow_mut(); // (re)open if the target changed or nothing is open yet