- Update GPL2 license texts to the latest version - Limit RPC request size in RequestReceiver to prevent memory exhaustion Resolves: RHEL-214326
81 lines
3.0 KiB
Diff
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
|
|
|