From 4ffb87384c1c104f14db183b26d445c1685fb053 Mon Sep 17 00:00:00 2001 From: Vit Mojzis Date: Mon, 27 Jul 2026 17:06:52 +0200 Subject: [PATCH] Limit RPC request size in RequestReceiver to prevent memory exhaustion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A local attacker could connect to the world-writable setroubleshootd UNIX socket and send a crafted RPC header with an arbitrarily large content-length value, then continuously stream body data. Because RequestReceiver.feed() appended incoming data to feed_buf without any upper bound and parse_header() trusted the content-length value directly, memory usage would grow until the daemon was OOM-killed by the MemoryMax=1G cgroup limit. Add size limits at three levels: - Reject content-length values that are missing, negative, or exceed MAX_BODY_LEN (1 MiB) in parse_header() - Reject incomplete headers once feed_buf exceeds MAX_HEADER_LEN (8 KiB) without a terminator in process() - Cap total feed_buf size to MAX_HEADER_LEN + MAX_BODY_LEN in feed() as a catch-all safety net All ValueError exceptions propagate to the existing except handler in handle_client_io(), which logs the error and closes only the offending client connection — the daemon continues serving other clients. Co-Authored-By: Claude Opus 4.6 --- src/setroubleshoot/rpc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/setroubleshoot/rpc.py b/src/setroubleshoot/rpc.py index 2a874ae..aca2d7e 100755 --- a/src/setroubleshoot/rpc.py +++ b/src/setroubleshoot/rpc.py @@ -710,6 +710,8 @@ class ListeningServer(ConnectionIO): class RequestReceiver: + MAX_HEADER_LEN = 8192 + MAX_BODY_LEN = 1024 * 1024 def __init__(self, dispatchFunc): self.dispatchFunc = dispatchFunc @@ -736,6 +738,8 @@ class RequestReceiver: self.parse_header() continue else: + if len(self.feed_buf) > self.MAX_HEADER_LEN: + raise ValueError("RPC header too large") # Can't read header till more data arrives break if len(self.feed_buf) >= self.headerLen + self.bodyLen: @@ -754,6 +758,8 @@ class RequestReceiver: def feed(self, data): self.feed_buf += data + if len(self.feed_buf) > self.MAX_HEADER_LEN + self.MAX_BODY_LEN: + raise ValueError("RPC request exceeds maximum allowed size") self.process() def parse_header(self): @@ -768,7 +774,11 @@ class RequestReceiver: begin = match.end() else: break + if 'content-length' not in self.header: + raise ValueError("RPC request missing content-length") self.bodyLen = int(self.header['content-length']) + if self.bodyLen < 0 or self.bodyLen > self.MAX_BODY_LEN: + raise ValueError("RPC body length out of range") #----------------------------------------------------------------------------- -- 2.53.0