fix: address review feedback - use InvalidPacketError and abort on buffer overflow

- 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.
This commit is contained in:
Ievgen Bondarenko
2026-04-16 11:24:09 -07:00
parent 0a78e7506b
commit 444f43f6a3
3 changed files with 15 additions and 6 deletions

View File

@@ -42,7 +42,7 @@ from typing_extensions import TypeIs
from bumble import hci, l2cap, utils from bumble import hci, l2cap, utils
from bumble.colors import color from bumble.colors import color
from bumble.core import UUID, InvalidOperationError, ProtocolError from bumble.core import UUID, InvalidOperationError, InvalidPacketError, ProtocolError
from bumble.hci import HCI_Object from bumble.hci import HCI_Object
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -250,7 +250,7 @@ class ATT_PDU:
@classmethod @classmethod
def from_bytes(cls, pdu: bytes) -> ATT_PDU: def from_bytes(cls, pdu: bytes) -> ATT_PDU:
if not pdu: if not pdu:
raise ValueError("Empty ATT PDU") raise InvalidPacketError("Empty ATT PDU")
op_code = pdu[0] op_code = pdu[0]
subclass = ATT_PDU.pdu_classes.get(op_code) subclass = ATT_PDU.pdu_classes.get(op_code)

View File

@@ -68,6 +68,8 @@ class HfpProtocolError(ProtocolError):
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class HfpProtocol: class HfpProtocol:
MAX_BUFFER_SIZE: ClassVar[int] = 65536
dlc: rfcomm.DLC dlc: rfcomm.DLC
buffer: str buffer: str
lines: collections.deque lines: collections.deque
@@ -88,11 +90,17 @@ class HfpProtocol:
logger.debug(f'<<< Data received: {data}') logger.debug(f'<<< Data received: {data}')
# Drop incoming data if it would overflow the buffer; keep existing
# partial packet state intact so a future clean packet can still parse.
if len(self.buffer) + len(data) > self.MAX_BUFFER_SIZE:
logger.warning(
'HFP buffer overflow (>%d bytes), dropping incoming data',
self.MAX_BUFFER_SIZE,
)
return
# Add to the buffer and look for lines # Add to the buffer and look for lines
self.buffer += data self.buffer += data
if len(self.buffer) > 65536:
logger.warning("HFP buffer overflow, truncating")
self.buffer = self.buffer[-65536:]
while (separator := self.buffer.find('\r')) >= 0: while (separator := self.buffer.find('\r')) >= 0:
line = self.buffer[:separator].strip() line = self.buffer[:separator].strip()
self.buffer = self.buffer[separator + 1 :] self.buffer = self.buffer[separator + 1 :]

View File

@@ -36,6 +36,7 @@ from bumble.colors import color
from bumble.core import ( from bumble.core import (
AdvertisingData, AdvertisingData,
InvalidArgumentError, InvalidArgumentError,
InvalidPacketError,
PhysicalTransport, PhysicalTransport,
ProtocolError, ProtocolError,
) )
@@ -216,7 +217,7 @@ class SMP_Command:
@classmethod @classmethod
def from_bytes(cls, pdu: bytes) -> SMP_Command: def from_bytes(cls, pdu: bytes) -> SMP_Command:
if not pdu: if not pdu:
raise ValueError("Empty SMP PDU") raise InvalidPacketError("Empty SMP PDU")
code = CommandCode(pdu[0]) code = CommandCode(pdu[0])
subclass = SMP_Command.smp_classes.get(code) subclass = SMP_Command.smp_classes.get(code)