Per @zxzxwu review on #918:
- bumble/avdtp.py: replace `if len(pdu) < 1:` with `if not pdu:`
- tests/avdtp_test.py: replace `assert completed == []` with
`assert not completed`
Both are idiomatic Python truthy checks; behavior identical.
A remote peer can send an AVDTP frame shorter than the assembler expects.
The current MessageAssembler.on_pdu() unconditionally accesses pdu[0],
pdu[1], and (for START packets) pdu[2], so a 0-, 1-, or 2-byte frame
raises IndexError. The exception propagates up through L2CAP's read loop
and tears down the channel — same DoS class as #912 (empty ATT PDU) and
#914 (unbounded SDP recursion).
Fix: validate length before each access. Empty PDUs and packets shorter
than the type-specific minimum are logged and dropped; the assembler
stays alive so the L2CAP channel is not torn down.
- bumble/avdtp.py: length guards in MessageAssembler.on_pdu before
accessing pdu[0], pdu[1], pdu[2].
- tests/avdtp_test.py: regression test covering empty PDU, 1-byte SINGLE,
1-byte START, 2-byte START — all four would have raised IndexError
pre-fix; assembler now drops without raising.
Pyright expects generic type parameters to be specified for the
Attribute class, otherwise it treats the type as Unknown which can
trigger reportUnknownMemberType errors.
This can be solved by using a generic type parameter for these methods
which also has the benefit of making sure that the value parameter has
the correct type for the attribute.
In some cases, a new local `value_as_bytes` variable is needed to avoid
type errors and makes the code less confusing by not overwriting the
original `value` variable.
Change regex match string to raw string to avoid syntax warning:
tests/sdp_test.py:218: SyntaxWarning: invalid escape sequence '\d'
assert not re.search("Expect \d+ bytes, got \d+", caplog.text)
In the future, this will become an error, so we should fix it now.
If an attribute does not contains a bytes value, it would crash with
something like:
AttributeError: 'NoneType' object has no attribute 'hex'
Clearly, the intention here was to use `value_str` to avoid this
possibility.
- bumble/sdp.py: replace raise ValueError with raise InvalidPacketError
in DataElement.list_from_bytes depth guard. InvalidPacketError
already imported at line 34 and extends ValueError so the existing
regression test continues to match.
- tests/sdp_test.py: remove duplicate 'import pytest' inside
test_nested_sequence_recursion_guard; pytest already imported at
module top (line 23).
Threading.local counter left as-is per zxzxwu's 'leave it here and
refactor later' comment on the PR.
DataElement.from_bytes -> list_from_bytes -> (SEQUENCE/ALTERNATIVE
constructor dispatches back to list_from_bytes) had no depth limit. A
malicious SDP peer could send a PDU of a few kilobytes containing ~1000
nested SEQUENCE tags and exhaust the Python recursion stack, crashing the
host with an unhandled RecursionError propagating out of the SDP handler.
Reachable via: any remote Bluetooth device that Bumble performs SDP
service discovery against (default during Classic connection setup).
Same family as PR #912 (ATT_PDU.from_bytes empty PDU IndexError) - remote
unchecked-input parser crash in the Bluetooth stack.
Fix: thread-local depth counter, cap nesting at 32 (well above anything a
legitimate service record uses). Added two regression tests covering the
deep-nesting reject path and normal 16-level-nested SEQUENCE parsing.
Reproducer (4.5 KB payload, deterministic crash on 0.0.228):
from bumble.sdp import DataElement
inner = b"\x35\x00"
for _ in range(1500):
size = len(inner)
if size < 65535:
inner = bytes([0x36, (size >> 8) & 0xFF, size & 0xFF]) + inner
DataElement.from_bytes(inner) # RecursionError before fix
Signed-off-by: ibondarenko1 <ibondarenko1@users.noreply.github.com>
- att.py: raise core.InvalidPacketError instead of generic ValueError
- smp.py: raise core.InvalidPacketError instead of generic ValueError
- hfp.py: add MAX_BUFFER_SIZE class constant (64KB)
- hfp.py: drop incoming data when it would overflow buffer instead of
truncating, preserving existing partial-packet state
Per review comments on PR #912 by @zxzxwu.
Add length checks in from_bytes() for ATT and SMP protocol parsers
to prevent IndexError crashes from empty PDUs sent by remote Bluetooth
devices. Also add buffer size limit and UTF-8 error handling in HFP
protocol to prevent memory exhaustion and decode crashes.
- bumble/att.py: validate PDU is non-empty before accessing pdu[0]
- bumble/smp.py: validate PDU is non-empty before accessing pdu[0]
- bumble/hfp.py: limit buffer to 64KB, handle invalid UTF-8 gracefully
These issues can be triggered by a remote Bluetooth device sending
malformed packets, causing denial of service on the host.
Prior to this, these web pages fail to load with
`ImportError: cannot import name 'TypeIs' from 'typing_extensions'
(/lib/python3.11/site-packages/typing_extensions.py)`
Prior to this, these web pages fail to load with
`ValueError: Can't find a pure Python 3 wheel for 'cryptography>=44.0.3;
platform_system == "Emscripten"'.`