setroubleshoot/0002-Limit-RPC-request-size-in-RequestReceiver-to-prevent.patch
Vit Mojzis bd46fc11c7 setroubleshoot-3.3.37-2
- Update GPL2 license texts to the latest version
- Limit RPC request size in RequestReceiver to prevent memory exhaustion

Resolves: RHEL-214326
2026-07-29 13:12:10 +02:00

81 lines
3.0 KiB
Diff

From 4ffb87384c1c104f14db183b26d445c1685fb053 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
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 <noreply@anthropic.com>
---
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