Compare commits

..

No commits in common. "rawhide" and "f45" have entirely different histories.

7 changed files with 1 additions and 341 deletions

View file

@ -1,75 +0,0 @@
From 431d5a9a5f7ac4ce61210f4e21ecc64e79c8b31a Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Mon, 27 Jul 2026 18:20:44 +0200
Subject: [PATCH] Restrict RPC dispatch to registered methods only
get_method_implementation() used unrestricted getattr() to resolve
attacker-controlled method names on handler objects. Since server.py
binds the full connection object as the RPC handler via
connect_rpc_interface('SETroubleshootServer', self), all inherited
internal methods (acquire_write_lock, close_connection, etc.) became
callable through crafted RPC requests.
An attacker could connect to the world-writable UNIX socket and invoke
acquire_write_lock as a signal, then send any RPC method call. The
response path calls send_data() which tries to acquire the same
non-reentrant threading.Lock, deadlocking the daemon and making it
unresponsive to all clients.
Validate the requested method name against interface_registry before
calling getattr(). The method must exist in the registry with an
rpc_def.type matching the expected RPC type ('method' or 'signal').
Unregistered names now fall through to the existing "not implemented"
error response instead of being dispatched. The expected_type parameter
defaults to None for backward compatibility with any callers outside
default_request_handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
src/setroubleshoot/rpc.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/setroubleshoot/rpc.py b/src/setroubleshoot/rpc.py
index aca2d7e..6a6f31a 100755
--- a/src/setroubleshoot/rpc.py
+++ b/src/setroubleshoot/rpc.py
@@ -869,10 +869,17 @@ class RpcChannel(ConnectionIO, RpcManage):
result_code, result_msg)
self.io_watch_remove()
- def get_method_implementation(self, interface, method):
+ def get_method_implementation(self, interface, method, expected_type=None):
handler_obj = self.rpc_handlers.get(interface, None)
if handler_obj is None:
return None
+ if expected_type is not None:
+ interface_dict = interface_registry.interfaces.get(interface)
+ if interface_dict is None:
+ return None
+ rpc_def = interface_dict.get(method)
+ if rpc_def is None or rpc_def.type != expected_type:
+ return None
method_ptr = getattr(handler_obj, method, None)
return method_ptr
@@ -971,7 +978,7 @@ class RpcChannel(ConnectionIO, RpcManage):
self.handle_return(type, rpc_id, body)
elif type == 'method':
interface, method, args = convert_rpc_xml_to_args(body)
- method_ptr = self.get_method_implementation(interface, method)
+ method_ptr = self.get_method_implementation(interface, method, 'method')
if method_ptr:
try:
return_args = method_ptr(*args)
@@ -990,7 +997,7 @@ class RpcChannel(ConnectionIO, RpcManage):
self.emit_rpc(rpc_id, 'error_return', rpc_error_def, method, err_code, err_msg)
elif type == 'signal':
interface, method, args = convert_rpc_xml_to_args(body)
- method_ptr = self.get_method_implementation(interface, method)
+ method_ptr = self.get_method_implementation(interface, method, 'signal')
if method_ptr:
try:
method_ptr(*args)
--
2.53.0

View file

@ -1,34 +0,0 @@
From 920ca71562e462ed4d1d02f3ce1b35dec33bd1bb Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Fri, 7 Aug 2026 14:57:21 +0200
Subject: [PATCH] Reject logon() when peer credentials are unavailable
get_credentials() returns uid=None for non-Unix client sockets (e.g. an
INET/TCP listener). logon() then compared the supplied username against
get_identity(None), which falls back to os.getuid() -- the daemon's own
uid -- letting any caller authenticate as the 'setroubleshoot' account
without a valid password on such a listener. Refuse logon outright when
peer credentials could not be obtained.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
src/setroubleshoot/server.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/setroubleshoot/server.py b/src/setroubleshoot/server.py
index cf0f345..bc38fa3 100755
--- a/src/setroubleshoot/server.py
+++ b/src/setroubleshoot/server.py
@@ -324,6 +324,9 @@ class SetroubleshootdClientConnectionHandler(ClientConnectionHandler,
def logon(self, type, username, password):
log_debug("logon(%s) type=%s username=%s" % (self, type, username))
+ if self.uid is None:
+ raise ProgramError(ERR_USER_LOOKUP, detail="peer credentials unavailable; refusing logon on non-unix socket")
+
if username != get_identity(self.uid):
raise ProgramError(ERR_USER_LOOKUP, detail="uid=%s does not match logon username (%s)" % (self.uid, username))
--
2.53.0

View file

@ -1,73 +0,0 @@
From 49f3d79ff621e7cf3876cea759ded665cd192528 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Fri, 7 Aug 2026 14:58:20 +0200
Subject: [PATCH] Fix port handling
- Cast parsed port to int in SocketAddress.parse_inet_addr()
An explicit port in an {inet} address (e.g. "{inet}127.0.0.1:16983") was
kept as the raw regex-matched string instead of being converted to int.
socket.bind() requires an int port for AF_INET, so any configured
INET/TCP listener with an explicit port failed with TypeError, silently
swallowed by ListeningServer.open()'s exception handler, leaving the
daemon running with no client listener at all.
- Forward the configured default port in get_socket_list_from_config()
parse_socket_address_list() defaults its default_port parameter to None,
and get_socket_list_from_config() called it without passing one through,
so any {inet} address with no explicit port (e.g. "{inet}127.0.0.1") ended
up with SocketAddress.port = None instead of the configured
connection.default_port, causing socket.bind() to fail with TypeError.
- Fix invalid default connection.default_port value
The shipped default was '69783' with a comment acknowledging it was a
placeholder ("FIXME: figure out defined port"). 69783 exceeds the valid
TCP port range (0-65535), so any {inet} listen_for_client/client_connect_to
address with no explicit port failed with OverflowError on bind()/connect().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
src/config.py.in | 2 +-
src/setroubleshoot/rpc.py | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/config.py.in b/src/config.py.in
index d8e7e35..603a107 100644
--- a/src/config.py.in
+++ b/src/config.py.in
@@ -182,7 +182,7 @@ An empty string implies no limit''',
},
'connection': {
'default_port': {
- 'value': '69783', # FIXME: figure out defined port,
+ 'value': '16983',
'description': '',
},
},
diff --git a/src/setroubleshoot/rpc.py b/src/setroubleshoot/rpc.py
index 6a6f31a..142228f 100755
--- a/src/setroubleshoot/rpc.py
+++ b/src/setroubleshoot/rpc.py
@@ -100,7 +100,7 @@ def get_default_port():
def get_socket_list_from_config(cfg_section):
addr_string = get_config(cfg_section, 'address_list')
- socket_addresses = parse_socket_address_list(addr_string)
+ socket_addresses = parse_socket_address_list(addr_string, get_default_port())
return socket_addresses
@@ -577,6 +577,8 @@ class SocketAddress(object):
port = match.group(3)
if port is None:
port = self.default_port
+ else:
+ port = int(port)
if addr == 'hostname':
addr = get_hostname()
--
2.53.0

View file

@ -1,50 +0,0 @@
From 66942f3b55339e59f768952312548e7eab3d19ca Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Fri, 7 Aug 2026 17:44:46 +0200
Subject: [PATCH] Require root to delete alerts via D-Bus
delete_alert() removed an alert from the shared host database without
checking the caller's identity, and the shipped D-Bus policy allowed any
local user to invoke it. An unprivileged local user could enumerate alerts
with get_all_alerts and delete entries other users/administrators rely on.
Reject non-root callers in delete_alert() itself, and drop delete_alert
from the default D-Bus policy context as defense in depth (root already
has full access via the existing <policy user="root"> rule).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
org.fedoraproject.Setroubleshootd.conf | 3 ---
src/setroubleshoot/server.py | 2 ++
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/org.fedoraproject.Setroubleshootd.conf b/org.fedoraproject.Setroubleshootd.conf
index 65a0daa..910958a 100644
--- a/org.fedoraproject.Setroubleshootd.conf
+++ b/org.fedoraproject.Setroubleshootd.conf
@@ -35,9 +35,6 @@
<allow send_destination="org.fedoraproject.Setroubleshootd"
send_interface="org.fedoraproject.SetroubleshootdIface"
send_member="set_filter"/>
- <allow send_destination="org.fedoraproject.Setroubleshootd"
- send_interface="org.fedoraproject.SetroubleshootdIface"
- send_member="delete_alert"/>
<allow send_destination="org.fedoraproject.Setroubleshootd"
send_interface="org.freedesktop.DBus.Introspectable"/>
</policy>
diff --git a/src/setroubleshoot/server.py b/src/setroubleshoot/server.py
index bc38fa3..dc29f63 100755
--- a/src/setroubleshoot/server.py
+++ b/src/setroubleshoot/server.py
@@ -665,6 +665,8 @@ Deletes an alert from the database.
* `success(b)`:
"""
+ if self.connection.get_unix_user(sender) != 0:
+ return False
try:
database = get_host_database()
alert = self._get_alert(local_id, database)
--
2.53.0

View file

@ -1,55 +0,0 @@
From c30163055995cff80222899a35722819d8286417 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Fri, 7 Aug 2026 18:03:16 +0200
Subject: [PATCH] Protect against malicious socket blocking
Set a timeout (socket.timeout config, 5s default) on accepted client
sockets so a stuck send() eventually times out instead of hanging forever
(send_data() already had a Socket.timeout handler for this). As a second,
independent layer, skip clients that have not completed logon() in both
places that fan data out to the 'sealert' pool: send_alert_notification()
and ClientNotifier.signatures_updated().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
src/setroubleshoot/rpc.py | 1 +
src/setroubleshoot/server.py | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/src/setroubleshoot/rpc.py b/src/setroubleshoot/rpc.py
index 142228f..ecfd062 100755
--- a/src/setroubleshoot/rpc.py
+++ b/src/setroubleshoot/rpc.py
@@ -687,6 +687,7 @@ class ListeningServer(ConnectionIO):
try:
client_socket, client_address = socket.accept()
fcntl.fcntl(client_socket.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
+ client_socket.settimeout(RpcChannel.socket_timeout)
client_handler = self.client_connection_handler_class(self.socket_address)
client_handler.open(client_socket, client_address)
self.connection_state.update(0, ConnectionState.PROBLEM_FLAGS)
diff --git a/src/setroubleshoot/server.py b/src/setroubleshoot/server.py
index dc29f63..6adc0c2 100755
--- a/src/setroubleshoot/server.py
+++ b/src/setroubleshoot/server.py
@@ -149,6 +149,8 @@ def send_alert_notification(siginfo):
system_bus.send_message(alert)
for client in connection_pool.clients('sealert'):
+ if not (client.connection_state.flags & ConnectionState.AUTHENTICATED):
+ continue
client.alert(siginfo)
#------------------------------ Variables -------------------------------
@@ -445,6 +447,8 @@ class ClientNotifier(object):
def signatures_updated(self, type, item):
for client in self.connection_pool.clients('sealert'):
+ if not (client.connection_state.flags & ConnectionState.AUTHENTICATED):
+ continue
client.signatures_updated(type, item)
--
2.53.0

View file

@ -1,38 +0,0 @@
From 271fcfc09a53fba13b0e31df18acdc5d2605cf05 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Fri, 7 Aug 2026 18:05:56 +0200
Subject: [PATCH] Require privileged access to change email alert recipients
set_email_recipients() only checked that the RPC connection was
authenticated, not that the caller was privileged. Since logon() grants
authenticated state to any local user allowed to run the sealert client
(client_users='*' by default) and never verifies the supplied password,
any such user could overwrite the daemon-wide email_alert_recipients file
that controls where SELinux alert emails are sent.
Reuse the existing fix_cmd privilege model (already used to gate running
alert fix commands as root) to restrict this to root and users listed in
fix_cmd_users.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---
src/setroubleshoot/server.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/setroubleshoot/server.py b/src/setroubleshoot/server.py
index 6adc0c2..bf7a294 100755
--- a/src/setroubleshoot/server.py
+++ b/src/setroubleshoot/server.py
@@ -364,6 +364,9 @@ class SetroubleshootdClientConnectionHandler(ClientConnectionHandler,
if not (self.connection_state.flags & ConnectionState.AUTHENTICATED):
raise ProgramError(ERR_NOT_AUTHENTICATED)
+ if self.uid != 0 and not self.access.user_allowed('fix_cmd', self.username):
+ raise ProgramError(ERR_USER_PROHIBITED)
+
email_recipients = recipients
email_recipients.write_recipient_file(email_recipients_filepath)
--
2.53.0

View file

@ -6,10 +6,9 @@
Summary: Helps troubleshoot SELinux problems
Name: setroubleshoot
Version: 3.3.37
Release: 6%{?dist}
Release: 5%{?dist}
License: GPL-2.0-or-later
URL: https://gitlab.com/setroubleshoot/setroubleshoot
VCS: git:https://gitlab.com/setroubleshoot/setroubleshoot.git
Source0: https://gitlab.com/-/project/24478376/uploads/cbdfc2a87b350583c32b168fd9aad9fd/setroubleshoot-3.3.37.tar.gz
Source1: %{name}.tmpfiles
Source2: %{name}.sysusers
@ -17,12 +16,6 @@ Source2: %{name}.sysusers
# for j in 00*patch; do printf "Patch: %s\n" $j; done
Patch: 0001-Update-GPL2-license-texts-to-the-latest-version.patch
Patch: 0002-Limit-RPC-request-size-in-RequestReceiver-to-prevent.patch
Patch: 0003-Restrict-RPC-dispatch-to-registered-methods-only.patch
Patch: 0004-Reject-logon-when-peer-credentials-are-unavailable.patch
Patch: 0005-Fix-port-handling.patch
Patch: 0006-Require-root-to-delete-alerts-via-D-Bus.patch
Patch: 0007-Protect-against-malicious-socket-blocking.patch
Patch: 0008-Require-privileged-access-to-change-email-alert-reci.patch
BuildRequires: gcc
BuildRequires: make
BuildRequires: libcap-ng-devel
@ -201,14 +194,6 @@ to user preference. The same tools can be run on existing log files.
%doc AUTHORS COPYING ChangeLog DBUS.md NEWS README TODO
%changelog
* Fri Aug 07 2026 Vit Mojzis <vmojzis@redhat.com> - 3.3.37-6
- Require privileged access to change email alert recipients
- Protect against malicious socket blocking
- Require root to delete alerts via D-Bus
- Fix port handling
- Reject logon() when peer credentials are unavailable
- Restrict RPC dispatch to registered methods only
* Wed Jul 29 2026 Vit Mojzis <vmojzis@redhat.com> - 3.3.37-5
- Update GPL2 license texts to the latest version
- Limit RPC request size in RequestReceiver to prevent memory exhaustion