From 0126907574f52339f716067cde4e9fb41001ce5b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 17:11:29 +0800 Subject: [PATCH] fix(bt): enhanced packet length check for HCI module --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 4 ++++ components/bt/host/bluedroid/hci/hci_layer.c | 19 +++++++++++++++++++ .../bluedroid/hci/include/hci/hci_internals.h | 4 ++++ .../bt/host/bluedroid/hci/packet_fragmenter.c | 11 +++++++++++ 4 files changed, 38 insertions(+) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index cadf70005f..475af54302 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -481,6 +481,10 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) packet->len--; if (type == HCI_BLE_EVENT) { #if (!CONFIG_BT_STACK_NO_LOG) + if (packet->len < 1) { + osi_free(packet); + return; + } uint8_t len = 0; STREAM_TO_UINT8(len, stream); #endif diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index c6a6efa4ee..2ed3172c25 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -447,12 +447,26 @@ static bool filter_incoming_event(BT_HDR *packet) uint8_t event_code; command_opcode_t opcode; + if (packet == NULL) { + return true; + } + + if (packet->len < HCI_EVENT_PREAMBLE_SIZE) { + HCI_TRACE_WARNING("dropping too short HCI event (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(event_code, stream); STREAM_SKIP_UINT8(stream); // Skip the parameter total length field HCI_TRACE_DEBUG("Receive packet event_code=0x%x\n", event_code); if (event_code == HCI_COMMAND_COMPLETE_EVT) { + if (packet->len < HCI_EVENT_PREAMBLE_SIZE + HCI_CC_EVENT_MIN_PARAM_LEN) { + HCI_TRACE_WARNING("dropping too short Command Complete (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); @@ -481,6 +495,11 @@ static bool filter_incoming_event(BT_HDR *packet) goto intercepted; } else if (event_code == HCI_COMMAND_STATUS_EVT) { uint8_t status; + if (packet->len < HCI_EVENT_PREAMBLE_SIZE + HCI_CS_EVENT_MIN_PARAM_LEN) { + HCI_TRACE_WARNING("dropping too short Command Status (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(status, stream); STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_internals.h b/components/bt/host/bluedroid/hci/include/hci/hci_internals.h index 41c792cf3c..7d336e8a13 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_internals.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_internals.h @@ -27,5 +27,9 @@ #define HCI_SCO_PREAMBLE_SIZE 3 // 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4) #define HCI_EVENT_PREAMBLE_SIZE 2 +// 1 byte for Num_HCI_Command_Packets, 2 bytes for Commnad_Opcode (Volume 4, Part E, 7.7.14) +#define HCI_CC_EVENT_MIN_PARAM_LEN 3 +// 1 byte for status, 1 byte for Num_HCI_Command_Packets, 2 bytes for Commnad_Opcode (Volume 4, Part E, 7.7.15) +#define HCI_CS_EVENT_MIN_PARAM_LEN 4 #endif /* _HCI_INTERNALS_H_ */ diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index ccc220fbf1..0827ecb4fe 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -37,6 +37,7 @@ #define START_PACKET_BOUNDARY 2 #define CONTINUATION_PACKET_BOUNDARY 1 #define L2CAP_HEADER_SIZE 4 +#define L2CAP_LENGTH_SIZE 2 // TODO(zachoverflow): find good value for this #define NUMBER_OF_BUCKETS 42 @@ -81,6 +82,11 @@ static void fragment_and_dispatch(BT_HDR *packet) callbacks->fragmented(packet, true); return; } + if (packet->len < HCI_ACL_PREAMBLE_SIZE) { + HCI_TRACE_ERROR("ACL packet too short for preamble (len=%u)", packet->len); + callbacks->fragmented(packet, true); + return; + } max_data_size = SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ? @@ -143,6 +149,11 @@ static void reassemble_and_dispatch(BT_HDR *packet) uint16_t l2cap_length; uint16_t acl_length __attribute__((unused)); + if (packet->len < HCI_ACL_PREAMBLE_SIZE + L2CAP_LENGTH_SIZE) { + HCI_TRACE_ERROR("ACL packet too short (len=%u)\n", packet->len); + osi_free(packet); + return; + } STREAM_TO_UINT16(handle, stream); STREAM_TO_UINT16(acl_length, stream); STREAM_TO_UINT16(l2cap_length, stream);