Merge pull request #912 from ibondarenko1/fix/empty-pdu-crash

fix: add input validation to prevent remote crash from empty/malforme…
This commit is contained in:
Josh Wu
2026-04-20 14:36:48 +08:00
committed by GitHub
3 changed files with 18 additions and 2 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
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -249,6 +249,8 @@ class ATT_PDU:
@classmethod @classmethod
def from_bytes(cls, pdu: bytes) -> ATT_PDU: def from_bytes(cls, pdu: bytes) -> ATT_PDU:
if not 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
@@ -84,10 +86,19 @@ class HfpProtocol:
def feed(self, data: bytes | str) -> None: def feed(self, data: bytes | str) -> None:
# Convert the data to a string if needed # Convert the data to a string if needed
if isinstance(data, bytes): if isinstance(data, bytes):
data = data.decode('utf-8') data = data.decode('utf-8', errors='replace')
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
while (separator := self.buffer.find('\r')) >= 0: while (separator := self.buffer.find('\r')) >= 0:

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,
) )
@@ -215,6 +216,8 @@ class SMP_Command:
@classmethod @classmethod
def from_bytes(cls, pdu: bytes) -> SMP_Command: def from_bytes(cls, pdu: bytes) -> SMP_Command:
if not 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)