diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c index 7fb74fdfa8..cfa0ff9091 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -283,6 +283,11 @@ tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid, tBTA_JV_API_START_DISCOVERY *p_msg; APPL_TRACE_API( "BTA_JvStartDiscovery"); + if ((num_uuid > BTA_JV_MAX_UUIDS) || ((num_uuid > 0) && (p_uuid_list == NULL))) { + APPL_TRACE_ERROR("invalid uuid list: num_uuid=%u", num_uuid); + return BTA_JV_FAILURE; + } + if ((p_msg = (tBTA_JV_API_START_DISCOVERY *)osi_malloc(sizeof(tBTA_JV_API_START_DISCOVERY))) != NULL) { p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT; bdcpy(p_msg->bd_addr, bd_addr); diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 31a71992dc..3426688edd 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -652,7 +652,11 @@ static void btc_spp_start_discovery(btc_spp_args_t *arg) ret = ESP_SPP_NEED_INIT; break; } - BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); + tBTA_JV_STATUS status = BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); + if (status != BTA_JV_SUCCESS) { + BTC_TRACE_ERROR("%s SPP failed to start discovery\n", __func__); + ret = ESP_SPP_NO_RESOURCE; + } } while (0); if (ret != ESP_SPP_SUCCESS) { diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 8282d32e5f..bfb0f8b44b 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); diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c index cae87a2a9e..0e967877fb 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c @@ -106,46 +106,54 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */ - BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); - if (len != (p_result->get_cur_app_val.num_attr + 1)) { + if (len < 1) { status = AVRC_STS_INTERNAL_ERR; - break; - } - p_u8 = p_result->get_cur_app_val.attrs; - for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) { - /* only report the valid player app attributes */ - if (AVRC_IsValidPlayerAttr(*p)) { - p_u8[yy++] = *p; + } else { + BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); + if (len != (p_result->get_cur_app_val.num_attr + 1)) { + status = AVRC_STS_INTERNAL_ERR; + break; + } + p_u8 = p_result->get_cur_app_val.attrs; + for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) { + /* only report the valid player app attributes */ + if (AVRC_IsValidPlayerAttr(*p)) { + p_u8[yy++] = *p; + } + p++; + } + p_result->get_cur_app_val.num_attr = yy; + if (yy == 0) { + status = AVRC_STS_BAD_PARAM; } - p++; - } - p_result->get_cur_app_val.num_attr = yy; - if (yy == 0) { - status = AVRC_STS_BAD_PARAM; } break; case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */ - BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); - size_needed = sizeof(tAVRC_APP_SETTING); - if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) { - p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; - p_app_set = p_result->set_app_val.p_vals; - for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) { - p_app_set[xx].attr_id = *p++; - p_app_set[xx].attr_val = *p++; - if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) { - status = AVRC_STS_BAD_PARAM; - } - } - if (xx != p_result->set_app_val.num_val) { - AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", - xx, p_result->set_app_val.num_val); - p_result->set_app_val.num_val = xx; - } - } else { - AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); + if (len < 1) { status = AVRC_STS_INTERNAL_ERR; + } else { + BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); + size_needed = sizeof(tAVRC_APP_SETTING); + if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) { + p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; + p_app_set = p_result->set_app_val.p_vals; + for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) { + p_app_set[xx].attr_id = *p++; + p_app_set[xx].attr_val = *p++; + if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) { + status = AVRC_STS_BAD_PARAM; + } + } + if (xx != p_result->set_app_val.num_val) { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", + xx, p_result->set_app_val.num_val); + p_result->set_app_val.num_val = xx; + } + } else { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); + status = AVRC_STS_INTERNAL_ERR; + } } break; diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c index 43e3664baf..d36b4115c9 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_server.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_server.c @@ -118,6 +118,10 @@ void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg) UINT8 pdu_id; UINT16 trans_num, param_len; + if (p_msg->len < 5) { + SDP_TRACE_WARNING("SDP - short request received: len=%u\n", p_msg->len); + return; + } /* Start inactivity timer */ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); @@ -187,6 +191,11 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, return; } + if (p_req + 2 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); + return; + } + /* Get the max replies we can send. Cap it at our max anyways. */ BE_STREAM_TO_UINT16 (max_replies, p_req); @@ -194,7 +203,6 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, max_replies = SDP_MAX_RECORDS; } - if ((!p_req) || (p_req > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); return; @@ -322,14 +330,13 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, BOOLEAN is_cont = FALSE; UINT16 attr_len; - /* Extract the record handle */ - BE_STREAM_TO_UINT32 (rec_handle, p_req); - - if (p_req > p_req_end) { + if (p_req + 4 + 2 > p_req_end) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE); return; } + /* Extract the record handle */ + BE_STREAM_TO_UINT32 (rec_handle, p_req); /* Get the max list length we can send. Cap it at MTU size minus overhead */ BE_STREAM_TO_UINT16 (max_list_len, p_req); @@ -371,7 +378,7 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) { + if ((*p_req++ != SDP_CONTINUATION_LEN) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; } diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c index 469d3efbae..79a330b97e 100644 --- a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -590,7 +590,7 @@ hci_driver_uart_dma_deinit(void) ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port)); hci_driver_uart_dma_memory_deinit(); - if (!s_hci_driver_uart_dma_env.process_sem) { + if (s_hci_driver_uart_dma_env.process_sem) { vSemaphoreDelete(s_hci_driver_uart_dma_env.process_sem); }