Problem
_read_header reads _body_len and _header_len as untrusted uint32 values directly from the wire (lines 772-790), then computes self._msg_len = self._header_len + (-self._header_len & 7) + self._body_len. _read_body then calls self._read_to_pos(HEADER_SIGNATURE_SIZE + self._msg_len) (line 800), which feeds an attacker-controlled missing_bytes (up to ~8 GiB) into socket.recvmsg(missing_bytes, ...) in _read_sock_with_fds (line 379), or grows self._buf until it reaches that size in _read_sock_without_fds/_read_stream. The TODO at message.py:324 ("maximum message size is 134217728 (128 MiB)") confirms the spec-mandated 128 MiB cap is not enforced. Anyone able to send messages to a victim's connection (and on a shared system bus, any unprivileged peer can broadcast signals to subscribers) can deliver a single 28-byte forged header claiming body_len=0xFFFFFFFF and force the victim to attempt to buffer ~4 GiB before any validation.
Why This Matters
Remote DoS against any dbus-fast consumer — including privileged daemons that subscribe to signals on the system bus (BlueZ-adjacent services, NetworkManager clients, etc.). A single hostile message kills the process or freezes the host via OOM.
Suggested Fix
Enforce the D-Bus spec limits immediately after reading the header in _read_header:
MAX_BODY_LEN = 134_217_728 # 128 MiB
MAX_HEADER_LEN = 134_217_728 # spec: array length <= 64 MiB; 128 MiB is a safe ceiling
if self._body_len > MAX_BODY_LEN or self._header_len > MAX_HEADER_LEN:
raise InvalidMessageError(
f"message size exceeds maximum: header={self._header_len}, body={self._body_len}"
)
Place this before computing _msg_len so no allocation/recv is ever attempted with attacker-chosen sizes.
Details
|
|
| Severity |
🟠 High |
| Category |
dos |
| Location |
src/dbus_fast/_private/unmarshaller.py:751-800 (and 401-422, 369-399) |
| Effort |
⚡ Quick fix |
🤖 Created by Kōan from audit session
Problem
_read_headerreads_body_lenand_header_lenas untrusteduint32values directly from the wire (lines 772-790), then computesself._msg_len = self._header_len + (-self._header_len & 7) + self._body_len._read_bodythen callsself._read_to_pos(HEADER_SIGNATURE_SIZE + self._msg_len)(line 800), which feeds an attacker-controlledmissing_bytes(up to ~8 GiB) intosocket.recvmsg(missing_bytes, ...)in_read_sock_with_fds(line 379), or growsself._bufuntil it reaches that size in_read_sock_without_fds/_read_stream. The TODO atmessage.py:324("maximum message size is 134217728 (128 MiB)") confirms the spec-mandated 128 MiB cap is not enforced. Anyone able to send messages to a victim's connection (and on a shared system bus, any unprivileged peer can broadcast signals to subscribers) can deliver a single 28-byte forged header claimingbody_len=0xFFFFFFFFand force the victim to attempt to buffer ~4 GiB before any validation.Why This Matters
Remote DoS against any dbus-fast consumer — including privileged daemons that subscribe to signals on the system bus (BlueZ-adjacent services, NetworkManager clients, etc.). A single hostile message kills the process or freezes the host via OOM.
Suggested Fix
Enforce the D-Bus spec limits immediately after reading the header in
_read_header:Place this before computing
_msg_lenso no allocation/recv is ever attempted with attacker-chosen sizes.Details
src/dbus_fast/_private/unmarshaller.py:751-800 (and 401-422, 369-399)🤖 Created by Kōan from audit session