From e3f03bb165239e20a7ece7f4d4d9675bdcd310bf Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Thu, 27 Nov 2025 20:10:50 +0800 Subject: [PATCH 01/20] fix(ble/bluedroid): Fix potential CVE-2020-0022 in reassemble_and_dispatch - Reference: https://nvd.nist.gov/vuln/detail/CVE-2020-0022 (cherry picked from commit 1f7fd91b5a3b6a753bc0d93df1f3f0cb9fb8a21a) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/hci/packet_fragmenter.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index d8f2ff918f..9b444ab69c 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -161,6 +161,13 @@ static void reassemble_and_dispatch(BT_HDR *packet) osi_free(partial_packet); } + /* Check for integer overflow in length calculation */ + if (l2cap_length > (UINT16_MAX - L2CAP_HEADER_SIZE - HCI_ACL_PREAMBLE_SIZE)) { + HCI_TRACE_ERROR("L2CAP length too large: %u", l2cap_length); + osi_free(packet); + return; + } + uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE; if (full_length <= packet->len) { if (full_length < packet->len) { @@ -200,6 +207,20 @@ static void reassemble_and_dispatch(BT_HDR *packet) packet->offset += HCI_ACL_PREAMBLE_SIZE; // skip ACL preamble packet->len -= HCI_ACL_PREAMBLE_SIZE; + + // CVE-2020-0022 (BlueFrag) Fix: Prevent integer underflow + if (partial_packet->offset > partial_packet->len) { + HCI_TRACE_ERROR("%s offset exceeds expected length. Dropping packet.\n", __func__); + osi_free(packet); + return; + } + + if (packet->len > UINT16_MAX - partial_packet->offset) { + HCI_TRACE_ERROR("%s: packet->len too large, would overflow. Dropping packet.\n", __func__); + osi_free(packet); + return; + } + uint16_t projected_offset = partial_packet->offset + packet->len; if (projected_offset > partial_packet->len) { // len stores the expected length HCI_TRACE_ERROR("%s got packet which would exceed expected length of %d. Truncating.\n", __func__, partial_packet->len); From 1d22e44e51526651f7fb285e27f9e39ff72f9f44 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Thu, 27 Nov 2025 20:11:01 +0800 Subject: [PATCH 02/20] fix(ble/bluedroid): Fix potential CVE-2024-0039 out-of-bounds write in attp_build_value_cmd - Reference: https://source.android.com/docs/security/bulletin/2024-03-01?hl=zh-cn (cherry picked from commit e1d39f630f7a5a8a3390429c42cd53329c4d0bb3) Co-authored-by: zhanghaipeng --- .../host/bluedroid/stack/gatt/att_protocol.c | 112 +++++++++++------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c index 310a9756ef..b336aecc38 100644 --- a/components/bt/host/bluedroid/stack/gatt/att_protocol.c +++ b/components/bt/host/bluedroid/stack/gatt/att_protocol.c @@ -285,57 +285,89 @@ BT_HDR *attp_build_opcode_cmd(UINT8 op_code) ** Returns None. ** *******************************************************************************/ -BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle, - UINT16 offset, UINT16 len, UINT8 *p_data) +BT_HDR *attp_build_value_cmd(UINT16 payload_size, UINT8 op_code, + UINT16 handle, UINT16 offset, + UINT16 len, UINT8 *p_data) { - BT_HDR *p_buf = NULL; - UINT8 *p, *pp, pair_len, *p_pair_len; + BT_HDR *p_buf = NULL; + UINT8 *p = NULL, *pp = NULL, *p_pair_len = NULL; + size_t pair_len = 0; + size_t size_now = 1; /* track current buffer size including op_code */ - if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) { - p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; +#define CHECK_SIZE() \ + do { \ + if (size_now > payload_size) { \ + GATT_TRACE_ERROR("payload size too small"); \ + osi_free(p_buf); \ + return NULL; \ + } \ + } while (0) - UINT8_TO_STREAM (p, op_code); - p_buf->offset = L2CAP_MIN_OFFSET; - p_buf->len = 1; + /* allocate buffer with extra space for L2CAP offset */ + p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET); + if (!p_buf) return NULL; - if (op_code == GATT_RSP_READ_BY_TYPE) { - p_pair_len = p; - pair_len = len + 2; - UINT8_TO_STREAM (p, pair_len); - p_buf->len += 1; - } - if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) { - UINT16_TO_STREAM (p, handle); - p_buf->len += 2; + p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + CHECK_SIZE(); + UINT8_TO_STREAM(p, op_code); + p_buf->offset = L2CAP_MIN_OFFSET; + + /* handle Read By Type response: reserve space for pair_len */ + if (op_code == GATT_RSP_READ_BY_TYPE) { + p_pair_len = p++; + pair_len = len + 2; /* handle(2 bytes) + value length */ + size_now += 1; + CHECK_SIZE(); + /* pair_len will be backfilled after value is written */ + } + + /* write handle if needed */ + if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && + op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) { + size_now += 2; + CHECK_SIZE(); + UINT16_TO_STREAM(p, handle); + } + + /* write offset for prepare write requests */ + if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) { + size_now += 2; + CHECK_SIZE(); + UINT16_TO_STREAM(p, offset); + } + + /* write value data, ensure it does not exceed payload_size */ + if (len > 0 && p_data != NULL) { + if (payload_size - size_now < len) { + len = payload_size - size_now; + if (op_code == GATT_RSP_READ_BY_TYPE) { + pair_len = len + 2; + } + GATT_TRACE_WARNING("attribute value too long, truncated to %d", len); } - if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE ) { - UINT16_TO_STREAM (p, offset); - p_buf->len += 2; - } + size_now += len; + CHECK_SIZE(); - if(payload_size < GATT_DEF_BLE_MTU_SIZE || payload_size > GATT_MAX_MTU_SIZE) { - GATT_TRACE_ERROR("invalid payload_size %d", payload_size); + ARRAY_TO_STREAM(p, p_data, len); + } + + /* backfill pair_len for Read By Type response */ + if (op_code == GATT_RSP_READ_BY_TYPE) { + if (pair_len > UINT8_MAX) { + GATT_TRACE_ERROR("pair_len > UINT8_MAX"); osi_free(p_buf); return NULL; } - - if (len > 0 && p_data != NULL) { - /* ensure data not exceed MTU size */ - if (payload_size - p_buf->len < len) { - len = payload_size - p_buf->len; - /* update handle value pair length */ - if (op_code == GATT_RSP_READ_BY_TYPE) { - *p_pair_len = (len + 2); - } - - GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len); - } - - ARRAY_TO_STREAM (p, p_data, len); - p_buf->len += len; - } + *p_pair_len = (UINT8)pair_len; } + + /* update buffer length */ + p_buf->len = (UINT16)size_now; + +#undef CHECK_SIZE + return p_buf; } From 316c5a589a0b92b7a56cb51c699e9ead1ab82d56 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Thu, 27 Nov 2025 20:11:02 +0800 Subject: [PATCH 03/20] fix(ble/bluedroid): Fix potential out-of-bounds issue - add length check in hci_hal_h4_hdl_rx_packet to prevent OOB - add adv data length check in btm_ble_cache_adv_data - add indicate data length check in BTA_GATTS_HandleValueIndication - add report length check in bta_hh_parse_keybd_rpt - add report length check in BTA_HdSendReport - add descriptor length check in BTA_HdRegisterApp - prevent buffer overflow in attribute processing (cherry picked from commit 71efec78c59ccc3894012797ff6354435e8ed7b9) Co-authored-by: zhanghaipeng --- .../host/bluedroid/bta/gatt/bta_gatts_api.c | 10 ++++++++- .../bt/host/bluedroid/bta/hd/bta_hd_api.c | 21 +++++++++++++++++++ .../bt/host/bluedroid/bta/hh/bta_hh_utils.c | 14 ++++++++++++- components/bt/host/bluedroid/hci/hci_hal_h4.c | 7 ++++--- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 7 +++++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c index 4e1f76f636..b712da9b79 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c @@ -241,7 +241,7 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_u p_buf->attr_val.attr_max_len = attr_val->attr_max_len; p_buf->attr_val.attr_val = (uint8_t *)osi_malloc(len); if(p_buf->attr_val.attr_val != NULL){ - memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len); + memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, len); } } @@ -411,6 +411,14 @@ void BTA_GATTS_StopService(UINT16 service_id) void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len, UINT8 *p_data, BOOLEAN need_confirm) { + + /* Validate data length against buffer size */ + if (data_len > BTA_GATT_MAX_ATTR_LEN) { + APPL_TRACE_ERROR("GATT indication data too large: %u > %u", + data_len, BTA_GATT_MAX_ATTR_LEN); + return; + } + tBTA_GATTS_API_INDICATION *p_buf; UINT16 len = sizeof(tBTA_GATTS_API_INDICATION); diff --git a/components/bt/host/bluedroid/bta/hd/bta_hd_api.c b/components/bt/host/bluedroid/bta/hd/bta_hd_api.c index 33875b957a..36aa540d29 100644 --- a/components/bt/host/bluedroid/bta/hd/bta_hd_api.c +++ b/components/bt/host/bluedroid/bta/hd/bta_hd_api.c @@ -89,6 +89,20 @@ void BTA_HdDisable(void) ******************************************************************************/ extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos) { + + /* Validate descriptor length before copying */ + if (p_app_info->descriptor.dl_len > BTA_HD_APP_DESCRIPTOR_LEN) { + APPL_TRACE_ERROR("HID descriptor too large: %u > %u", + p_app_info->descriptor.dl_len, BTA_HD_APP_DESCRIPTOR_LEN); + return; + } + + /* Validate descriptor data pointer */ + if (p_app_info->descriptor.dl_len > 0 && p_app_info->descriptor.dsc_list == NULL) { + APPL_TRACE_ERROR("HID descriptor data NULL but length > 0: %u", p_app_info->descriptor.dl_len); + return; + } + tBTA_HD_REGISTER_APP *p_buf; APPL_TRACE_API("%s", __func__); if ((p_buf = (tBTA_HD_REGISTER_APP *)osi_malloc(sizeof(tBTA_HD_REGISTER_APP))) != NULL) { @@ -158,6 +172,13 @@ extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report) __func__, p_report->len, BTA_HD_REPORT_LEN); return; } + + /* Validate report data pointer */ + if (p_report->len > 0 && p_report->p_data == NULL) { + APPL_TRACE_ERROR("HID report data pointer NULL but length > 0: %d", p_report->len); + return; + } + if ((p_buf = (tBTA_HD_SEND_REPORT *)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) != NULL) { p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT; p_buf->use_intr = p_report->use_intr; diff --git a/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c b/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c index 6dc3ec02dd..7c89ed004d 100644 --- a/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c +++ b/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c @@ -263,6 +263,18 @@ void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, UINT8 *p_report, UINT16 xx, yy, key_idx = 0; UINT8 this_report[BTA_HH_MAX_RPT_CHARS]; + /* Validate report length before processing */ + if (report_len > BTA_HH_MAX_RPT_CHARS) { + APPL_TRACE_ERROR("HID report length exceeds maximum: %u > %u", + report_len, BTA_HH_MAX_RPT_CHARS); + return; + } + + if (report_len == 0 || p_report == NULL) { + APPL_TRACE_ERROR("Invalid HID report data"); + return; + } + #if BTA_HH_DEBUG APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called", p_report, report_len); @@ -463,7 +475,7 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) if (bta_hh_cb.p_cback) { (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status); - /* all connections are down, no waiting for diconnect */ + /* all connections are down, no waiting for disconnect */ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); } } diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 5baf97fc08..f91a2260d9 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -508,9 +508,10 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) STREAM_TO_UINT8(length, stream); } - if ((length + hdr_size) != packet->len) { - HCI_TRACE_ERROR("Wrong packet length type=%d hdr_len=%d pd_len=%d " - "pkt_len=%d", type, hdr_size, length, packet->len); + // Prevents integer wrap-around when calculating (length + hdr_size). + if (length != (packet->len - hdr_size)) { + HCI_TRACE_ERROR("%s: SECURITY: parameter length (%d) exceeds packet bounds (%d)", + __func__, length, packet->len - hdr_size); osi_free(packet); return; } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index faf2e1848f..973f32754a 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -3112,6 +3112,13 @@ void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len p_cur->scan_rsp_len = 0; } + /* Additional validation to prevent potential integer overflow */ + if (data_len > BTM_BLE_CACHE_ADV_DATA_MAX) { + BTM_TRACE_ERROR("BLE advertising data length exceeds maximum: %u > %u", + data_len, BTM_BLE_CACHE_ADV_DATA_MAX); + return; + } + if (data_len > 0) { p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len]; if((data_len + p_le_inq_cb->adv_len) <= BTM_BLE_CACHE_ADV_DATA_MAX) { From 9112b87c1913bb3f23ce4d317671278b3e46c757 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:15 +0800 Subject: [PATCH 04/20] fix(ble/bluedroid): Add bounds check in ble_ancs example (cherry picked from commit 7e876249dfbc2da5b652665637d5e2f8dcdff811) Co-authored-by: zhanghaipeng --- .../bluedroid/ble/ble_ancs/main/ble_ancs.c | 14 ++++++-- .../ble/ble_ancs/main/ble_ancs_demo.c | 34 ++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c index 379d1ceda5..813a677b51 100644 --- a/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c +++ b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -126,14 +126,24 @@ void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len) switch (Command_id) { case CommandIDGetNotificationAttributes: { + // Security fix: Check minimum message length before accessing message[1..4] + if (message_len < 5) { + ESP_LOGE(BLE_ANCS_TAG, "Message too short for NotificationAttributes"); + break; + } uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24); uint32_t remian_attr_len = message_len - 5; uint8_t *attrs = &message[5]; ESP_LOGI(BLE_ANCS_TAG, "recevice Notification Attributes response Command_id %d NotificationUID %" PRIu32, Command_id, NotificationUID); while(remian_attr_len > 0) { + // Security fix: Need at least 3 bytes for AttributeID(1) + len(2) + if (remian_attr_len < 3) { + ESP_LOGE(BLE_ANCS_TAG, "Incomplete attribute header"); + break; + } uint8_t AttributeID = attrs[0]; uint16_t len = attrs[1] | (attrs[2] << 8); - if(len > (remian_attr_len -3)) { + if(len > (remian_attr_len - 3)) { ESP_LOGE(BLE_ANCS_TAG, "data error"); break; } diff --git a/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c index 04994799e8..4dfb0bd4b1 100644 --- a/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -31,6 +31,8 @@ #define ADV_CONFIG_FLAG (1 << 0) #define SCAN_RSP_CONFIG_FLAG (1 << 1) #define INVALID_HANDLE 0 +#define ANCS_CMD_BUFFER_MAX_SIZE 600 + static uint8_t adv_config_done = 0; static bool get_service = false; static esp_gattc_char_elem_t *char_elem_result = NULL; @@ -168,15 +170,26 @@ esp_noti_attr_list_t p_attr[8] = { void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr, esp_noti_attr_list_t *p_attr) { - uint8_t cmd[600] = {0}; + uint8_t cmd[ANCS_CMD_BUFFER_MAX_SIZE] = {0}; uint32_t index = 0; + cmd[0] = CommandIDGetNotificationAttributes; index ++; memcpy(&cmd[index], notificationUID, ESP_NOTIFICATIONUID_LEN); index += ESP_NOTIFICATIONUID_LEN; while(num_attr > 0) { + // Security fix: Check buffer boundary before writing + if (index >= ANCS_CMD_BUFFER_MAX_SIZE) { + ESP_LOGE(BLE_ANCS_TAG, "Command buffer overflow in get_notification_attributes"); + return; + } cmd[index ++] = p_attr->noti_attribute_id; if (p_attr->attribute_len > 0) { + // Need 2 more bytes for attribute_len + if ((index + 2) > ANCS_CMD_BUFFER_MAX_SIZE) { + ESP_LOGE(BLE_ANCS_TAG, "Command buffer overflow in get_notification_attributes"); + return; + } cmd[index ++] = p_attr->attribute_len; cmd[index ++] = (p_attr->attribute_len << 8); } @@ -195,8 +208,15 @@ void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr, void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len, uint8_t num_attr, uint8_t *p_app_attrs) { - uint8_t buffer[600] = {0}; + uint8_t buffer[ANCS_CMD_BUFFER_MAX_SIZE] = {0}; uint32_t index = 0; + + // Security fix: Check buffer boundary before memcpy + if ((1 + appidentifier_len + num_attr) > ANCS_CMD_BUFFER_MAX_SIZE) { + ESP_LOGE(BLE_ANCS_TAG, "Buffer overflow in get_app_attributes"); + return; + } + buffer[0] = CommandIDGetAppAttributes; index ++; memcpy(&buffer[index], appidentifier, appidentifier_len); @@ -215,7 +235,7 @@ void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len, void esp_perform_notification_action(uint8_t *notificationUID, uint8_t ActionID) { - uint8_t buffer[600] = {0}; + uint8_t buffer[ANCS_CMD_BUFFER_MAX_SIZE] = {0}; uint32_t index = 0; buffer[0] = CommandIDPerformNotificationAction; index ++; @@ -517,6 +537,12 @@ static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ esp_get_notification_attributes(notificationUID, sizeof(p_attr)/sizeof(esp_noti_attr_list_t), p_attr); } } else if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].data_source_handle) { + if ((data_buffer.len + param->notify.value_len) > sizeof(data_buffer.buffer)) { + ESP_LOGE(BLE_ANCS_TAG, "Data source buffer overflow detected, discarding data"); + memset(data_buffer.buffer, 0, sizeof(data_buffer.buffer)); + data_buffer.len = 0; + break; + } memcpy(&data_buffer.buffer[data_buffer.len], param->notify.value, param->notify.value_len); data_buffer.len += param->notify.value_len; if (param->notify.value_len == (gl_profile_tab[PROFILE_A_APP_ID].MTU_size - 3)) { From 7ca7eb47c49c852cef7ee23bec31c6a9704ef969 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:15 +0800 Subject: [PATCH 05/20] fix(ble/bluedroid): Use snprintf in ble_eddystone example (cherry picked from commit 24e023e307062c668dd85178b66947dddd534ea8) Co-authored-by: zhanghaipeng --- .../main/esp_eddystone_api.c | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/examples/bluetooth/bluedroid/ble/ble_eddystone_receiver/main/esp_eddystone_api.c b/examples/bluetooth/bluedroid/ble/ble_eddystone_receiver/main/esp_eddystone_api.c index 2832116506..e3051316e9 100644 --- a/examples/bluetooth/bluedroid/ble/ble_eddystone_receiver/main/esp_eddystone_api.c +++ b/examples/bluetooth/bluedroid/ble/ble_eddystone_receiver/main/esp_eddystone_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -21,6 +21,7 @@ #include "esp_eddystone_protocol.h" #include "esp_eddystone_api.h" +#define EDDYSTONE_URL_BUF_SIZE 100 /* Declare static functions */ static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res); @@ -101,18 +102,33 @@ static esp_err_t esp_eddystone_uid_received(const uint8_t* buf, uint8_t len, esp static char* esp_eddystone_resolve_url_scheme(const uint8_t *url_start, const uint8_t *url_end) { int pos = 0; - static char url_buf[100] = {0}; + static char url_buf[EDDYSTONE_URL_BUF_SIZE] = {0}; const uint8_t *p = url_start; + int written; - pos += sprintf(&url_buf[pos], "%s", eddystone_url_prefix[*p++]); + // Security fix: Use snprintf instead of sprintf to prevent buffer overflow + written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%s", eddystone_url_prefix[*p++]); + if (written < 0 || written >= (EDDYSTONE_URL_BUF_SIZE - pos)) { + url_buf[EDDYSTONE_URL_BUF_SIZE - 1] = '\0'; + return url_buf; + } + pos += written; for (; p <= url_end; p++) { - if (esp_eddystone_is_char_invalid((*p))) { - pos += sprintf(&url_buf[pos], "%s", eddystone_url_encoding[*p]); - } else { - pos += sprintf(&url_buf[pos], "%c", *p); + if (pos >= EDDYSTONE_URL_BUF_SIZE - 1) { + break; } + if (esp_eddystone_is_char_invalid((*p))) { + written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%s", eddystone_url_encoding[*p]); + } else { + written = snprintf(&url_buf[pos], EDDYSTONE_URL_BUF_SIZE - pos, "%c", *p); + } + if (written < 0 || written >= (EDDYSTONE_URL_BUF_SIZE - pos)) { + break; + } + pos += written; } + url_buf[EDDYSTONE_URL_BUF_SIZE - 1] = '\0'; return url_buf; } From 45835b025fd770ced104c078f3903637afba8d75 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:16 +0800 Subject: [PATCH 06/20] fix(ble/bluedroid): Use calloc in gatt_server example (cherry picked from commit e26b60090d0452523ca7fb730dd2cebb047c1997) Co-authored-by: zhanghaipeng --- examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c index a6d8912fff..a8b8254bc4 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c @@ -282,7 +282,8 @@ void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare } } - esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t)); + // Security fix: Use calloc to ensure memory is zero-initialized + esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)calloc(1, sizeof(esp_gatt_rsp_t)); if (gatt_rsp) { gatt_rsp->attr_value.len = param->write.len; gatt_rsp->attr_value.handle = param->write.handle; From dedf21c0ae2666743276d9623c73483a23c46731 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:16 +0800 Subject: [PATCH 07/20] fix(ble/bluedroid): Fix memory leak in ble_spp_server example (cherry picked from commit b6b3b81bf698dd7f85303de0cdcdb2d050e6efd2) Co-authored-by: zhanghaipeng --- .../ble_spp_server/main/ble_spp_server_demo.c | 25 +++++++++++-------- .../ble_spp_server/main/ble_spp_server_demo.h | 1 - 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c index d2796402cf..8e4351231e 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c @@ -277,20 +277,25 @@ static bool store_wr_buffer(esp_ble_gatts_cb_param_t *p_data) ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d", __func__, __LINE__); return false; } + + temp_spp_recv_data_node_p1->len = p_data->write.len; + temp_spp_recv_data_node_p1->next_node = NULL; + temp_spp_recv_data_node_p1->node_buff = (uint8_t *)malloc(p_data->write.len); + if (temp_spp_recv_data_node_p1->node_buff == NULL) { + ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d\n", __func__, __LINE__); + // Security fix: Free the node and return false to prevent memory leak + free(temp_spp_recv_data_node_p1); + temp_spp_recv_data_node_p1 = NULL; + return false; + } + memcpy(temp_spp_recv_data_node_p1->node_buff, p_data->write.value, p_data->write.len); + + // Security fix: Link to list only after successful allocation if(temp_spp_recv_data_node_p2 != NULL){ temp_spp_recv_data_node_p2->next_node = temp_spp_recv_data_node_p1; } - temp_spp_recv_data_node_p1->len = p_data->write.len; - SppRecvDataBuff.buff_size += p_data->write.len; - temp_spp_recv_data_node_p1->next_node = NULL; - temp_spp_recv_data_node_p1->node_buff = (uint8_t *)malloc(p_data->write.len); temp_spp_recv_data_node_p2 = temp_spp_recv_data_node_p1; - if (temp_spp_recv_data_node_p1->node_buff == NULL) { - ESP_LOGI(GATTS_TABLE_TAG, "malloc error %s %d\n", __func__, __LINE__); - temp_spp_recv_data_node_p1->len = 0; - } else { - memcpy(temp_spp_recv_data_node_p1->node_buff,p_data->write.value,p_data->write.len); - } + SppRecvDataBuff.buff_size += p_data->write.len; if(SppRecvDataBuff.node_num == 0){ SppRecvDataBuff.first_node = temp_spp_recv_data_node_p1; diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h index 9ca8065889..91829ea5df 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h +++ b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h @@ -16,7 +16,6 @@ //#define SUPPORT_HEARTBEAT //#define SPP_DEBUG_MODE -#define spp_sprintf(s,...) sprintf((char*)(s), ##__VA_ARGS__) #define SPP_DATA_MAX_LEN (512) #define SPP_CMD_MAX_LEN (20) #define SPP_STATUS_MAX_LEN (20) From f67bb6c31c635cc87eeb2a55164881f0253facc3 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:17 +0800 Subject: [PATCH 08/20] fix(ble/blufi): Add DH param length validation (cherry picked from commit 773814c087effb3d69c2eeed3ac2e8472861be7c) Co-authored-by: zhanghaipeng --- examples/bluetooth/blufi/main/blufi_security.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/blufi/main/blufi_security.c index 8b62777bba..123f506336 100644 --- a/examples/bluetooth/blufi/main/blufi_security.c +++ b/examples/bluetooth/blufi/main/blufi_security.c @@ -41,6 +41,7 @@ struct blufi_security { #define DH_SELF_PUB_KEY_LEN 128 +#define DH_PARAM_LEN_MAX 1024 uint8_t self_public_key[DH_SELF_PUB_KEY_LEN]; #define SHARE_KEY_LEN 128 uint8_t share_key[SHARE_KEY_LEN]; @@ -83,6 +84,13 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da switch (type) { case SEC_TYPE_DH_PARAM_LEN: blufi_sec->dh_param_len = ((data[1]<<8)|data[2]); + // Security fix: Limit DH param length to prevent DoS via large memory allocation + if (blufi_sec->dh_param_len == 0 || blufi_sec->dh_param_len > DH_PARAM_LEN_MAX) { + BLUFI_ERROR("%s, invalid dh param len %d\n", __func__, blufi_sec->dh_param_len); + blufi_sec->dh_param_len = 0; + btc_blufi_report_error(ESP_BLUFI_DH_PARAM_ERROR); + return; + } if (blufi_sec->dh_param) { free(blufi_sec->dh_param); blufi_sec->dh_param = NULL; From 775b64753e03cc85a8f812ae4fe1ad762e082e2d Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:17 +0800 Subject: [PATCH 09/20] fix(ble/bt): Add NULL check in esp_hid_host example (cherry picked from commit 8b5dd7536890d2eca026f88a410972e4f19e2d3b) Co-authored-by: zhanghaipeng --- examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c b/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c index 03e255d3ab..8934b60c1a 100644 --- a/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c +++ b/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c @@ -164,7 +164,7 @@ void hid_demo_task(void *pvParameters) printf("] srv 0x%03x, ", r->bt.cod.service); print_uuid(&r->bt.uuid); printf(", "); - if (strncmp(r->name, remote_device_name, strlen(remote_device_name)) == 0) { + if (r->name && strncmp(r->name, remote_device_name, strlen(remote_device_name)) == 0) { break; } } @@ -175,7 +175,7 @@ void hid_demo_task(void *pvParameters) } #if CONFIG_BT_HID_HOST_ENABLED - if (cr && strncmp(cr->name, remote_device_name, strlen(remote_device_name)) == 0) { + if (cr && cr->name && strncmp(cr->name, remote_device_name, strlen(remote_device_name)) == 0) { esp_hidh_dev_open(cr->bda, cr->transport, cr->ble.addr_type); } #else From de2b4af5bddd3a37420c4964ec98c05678db53eb Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:18 +0800 Subject: [PATCH 10/20] fix(ble/bt): Add NULL check in esp_hid_device example (cherry picked from commit 8e0f74a2cc52cd1ec5e039db34d09d4e07097f7b) Co-authored-by: zhanghaipeng --- examples/bluetooth/esp_hid_device/main/esp_hid_gap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c index 6cc854920b..9c87942f88 100644 --- a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c +++ b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c @@ -278,6 +278,9 @@ static void handle_bt_device_result(struct disc_res_param *disc_res) GAP_DBG_PRINTF(", %s: ", gap_bt_prop_type_names[prop->type]); } if (prop->type == ESP_BT_GAP_DEV_PROP_BDNAME) { + if (prop->val == NULL) { + continue; + } name = (uint8_t *)prop->val; name_len = strlen((const char *)name); GAP_DBG_PRINTF("%s", (const char *)name); From 8ef83c23675dcdb694140738c2ae506e453f59ed Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:19 +0800 Subject: [PATCH 11/20] fix(ble/bluedroid): Add NULL check in esp_ble_gap_add_device_to_resolving_list (cherry picked from commit 4b44d8e814927083be952f31d5e09ae3bbaa3dc6) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/api/esp_gap_ble_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c index 3c3a48e5b9..c7c16c037f 100644 --- a/components/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -239,7 +239,7 @@ esp_err_t esp_ble_gap_add_device_to_resolving_list(esp_bd_addr_t peer_addr, uint { ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); - if (addr_type > BLE_ADDR_TYPE_RANDOM ||!peer_addr || (addr_type && ((peer_addr[0] & 0xC0) != 0xC0))) { + if (addr_type > BLE_ADDR_TYPE_RANDOM || !peer_addr || !peer_irk || (addr_type && ((peer_addr[0] & 0xC0) != 0xC0))) { return ESP_ERR_INVALID_ARG; } From 8960e3ef50d3d1b24c33a46f12500dc2ea96d435 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:19 +0800 Subject: [PATCH 12/20] fix(ble/bluedroid): Add NULL checks in esp_gap_ble_api (cherry picked from commit b71c51564a7c2bb2be1377d40ae022baf2cea3b2) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/api/esp_gap_ble_api.c | 71 ++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c index c7c16c037f..d592b6b77f 100644 --- a/components/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -111,6 +111,10 @@ esp_err_t esp_ble_gap_start_advertising(esp_ble_adv_params_t *adv_params) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (adv_params == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_ACT_START_ADV; @@ -171,6 +175,10 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_ ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (remote_device == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_ACT_SET_PKT_DATA_LEN; @@ -182,6 +190,9 @@ esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_ esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr) { + if (rand_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } // Static device address: First two bits are '11', rest is random rand_addr[0] = 0xC0 | (esp_random() & 0x3F); for (int i = 1; i < 6; i++) { @@ -192,6 +203,9 @@ esp_err_t esp_ble_gap_addr_create_static(esp_bd_addr_t rand_addr) esp_err_t esp_ble_gap_addr_create_nrpa(esp_bd_addr_t rand_addr) { + if (rand_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } // Non-resolvable private address: First two bits are '00', rest is random rand_addr[0] = (esp_random() & 0x3F); for (int i = 1; i < 6; i++) { @@ -207,6 +221,10 @@ esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (rand_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_ACT_SET_RAND_ADDRESS; @@ -357,6 +375,10 @@ esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr, return ESP_ERR_INVALID_STATE; } + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (ESP_BLE_IS_VALID_PARAM(min_conn_int, ESP_BLE_CONN_INT_MIN, ESP_BLE_CONN_INT_MAX) && ESP_BLE_IS_VALID_PARAM(max_conn_int, ESP_BLE_CONN_INT_MIN, ESP_BLE_CONN_INT_MAX) && ESP_BLE_IS_VALID_PARAM(supervision_tout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) && @@ -424,6 +446,9 @@ esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t LOG_ERROR("%s, bluedroid status error", __func__); return ESP_FAIL; } + if (local_used_addr == NULL || addr_type == NULL) { + return ESP_ERR_INVALID_ARG; + } if(!BTM_BleGetCurrentAddress(local_used_addr, addr_type)) { return ESP_FAIL; } @@ -436,13 +461,6 @@ uint8_t *esp_ble_resolve_adv_data_by_type( uint8_t *adv_data, uint16_t adv_data_ return NULL; } - if (((type < ESP_BLE_AD_TYPE_FLAG) || (type > ESP_BLE_AD_TYPE_128SERVICE_DATA)) && - (type != ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE)) { - LOG_ERROR("The advertising data type is not defined, type = %x", type); - *length = 0; - return NULL; - } - if (adv_data_len == 0) { *length = 0; return NULL; @@ -495,6 +513,10 @@ esp_err_t esp_ble_gap_read_rssi(esp_bd_addr_t remote_addr) return ESP_ERR_INVALID_STATE; } + if (remote_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_ACT_READ_RSSI; @@ -645,6 +667,10 @@ esp_err_t esp_ble_set_encryption(esp_bd_addr_t bd_addr, esp_ble_sec_act_t sec_ac ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_SET_ENCRYPTION_EVT; @@ -662,6 +688,10 @@ esp_err_t esp_ble_gap_security_rsp(esp_bd_addr_t bd_addr, bool accept) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_SECURITY_RSP_EVT; @@ -680,6 +710,10 @@ esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t pas ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_PASSKEY_REPLY_EVT; @@ -698,6 +732,10 @@ esp_err_t esp_ble_confirm_reply(esp_bd_addr_t bd_addr, bool accept) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_CONFIRM_REPLY_EVT; @@ -712,6 +750,11 @@ esp_err_t esp_ble_remove_bond_device(esp_bd_addr_t bd_addr) { btc_msg_t msg = {0}; btc_ble_gap_args_t arg; + + if (bd_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_REMOVE_BOND_DEV_EVT; @@ -757,6 +800,10 @@ esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len) return ESP_ERR_INVALID_ARG; } + if (bd_addr == NULL || TK == NULL) { + return ESP_ERR_INVALID_ARG; + } + btc_msg_t msg = {0}; btc_ble_gap_args_t arg; @@ -775,7 +822,7 @@ esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len) esp_err_t esp_ble_sc_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t p_c[16], uint8_t p_r[16]) { - if (!p_c || !p_r) { + if (!bd_addr || !p_c || !p_r) { return ESP_ERR_INVALID_ARG; } @@ -836,6 +883,10 @@ esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (remote_device == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_DISCONNECT_EVT; @@ -864,6 +915,10 @@ esp_err_t esp_gap_ble_set_channels(esp_gap_ble_channels channels) return ESP_ERR_INVALID_STATE; } + if (channels == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GAP_BLE; msg.act = BTC_GAP_BLE_SET_AFH_CHANNELS; From 1ab91f0b5fc77117872be11a18e67eb4c6efbfe0 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:20 +0800 Subject: [PATCH 13/20] fix(ble/bluedroid): Add NULL checks in GATT APIs (cherry picked from commit a6730c7da697477ed696148cf737bfb66514a742) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/api/esp_gattc_api.c | 36 +++++++++++++++++++ .../bt/host/bluedroid/api/esp_gatts_api.c | 26 +++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/api/esp_gattc_api.c b/components/bt/host/bluedroid/api/esp_gattc_api.c index 83481a85c6..00c6a96e0b 100644 --- a/components/bt/host/bluedroid/api/esp_gattc_api.c +++ b/components/bt/host/bluedroid/api/esp_gattc_api.c @@ -173,6 +173,10 @@ esp_err_t esp_ble_gattc_enh_open(esp_gatt_if_t gattc_if, esp_ble_gatt_creat_conn #if (BLE_42_FEATURE_SUPPORT == TRUE) esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, esp_ble_addr_type_t remote_addr_type, bool is_direct) { + if (remote_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + esp_ble_gatt_creat_conn_params_t creat_conn_params = {0}; memcpy(creat_conn_params.remote_bda, remote_bda, ESP_BD_ADDR_LEN); creat_conn_params.remote_addr_type = remote_addr_type; @@ -187,6 +191,10 @@ esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, e #if (BLE_50_FEATURE_SUPPORT == TRUE) esp_err_t esp_ble_gattc_aux_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, esp_ble_addr_type_t remote_addr_type, bool is_direct) { + if (remote_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + esp_ble_gatt_creat_conn_params_t creat_conn_params = {0}; memcpy(creat_conn_params.remote_bda, remote_bda, ESP_BD_ADDR_LEN); creat_conn_params.remote_addr_type = remote_addr_type; @@ -521,6 +529,10 @@ esp_err_t esp_ble_gattc_read_multiple(esp_gatt_if_t gattc_if, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (read_multi == NULL) { + return ESP_ERR_INVALID_ARG; + } + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id); if (!gatt_check_connection_state_by_tcb(p_tcb)) { LOG_WARN("%s, The connection not created.", __func__); @@ -557,6 +569,10 @@ esp_err_t esp_ble_gattc_read_multiple_variable(esp_gatt_if_t gattc_if, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (read_multi == NULL) { + return ESP_ERR_INVALID_ARG; + } + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id); if (!gatt_check_connection_state_by_tcb(p_tcb)) { LOG_WARN("%s, The connection not created.", __func__); @@ -810,6 +826,10 @@ esp_err_t esp_ble_gattc_register_for_notify (esp_gatt_if_t gattc_if, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (server_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (handle == 0) { return ESP_GATT_INVALID_HANDLE; } @@ -832,6 +852,10 @@ esp_err_t esp_ble_gattc_unregister_for_notify (esp_gatt_if_t gattc_if, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (server_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (handle == 0) { return ESP_GATT_INVALID_HANDLE; } @@ -852,6 +876,10 @@ esp_err_t esp_ble_gattc_cache_refresh(esp_bd_addr_t remote_bda) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (remote_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTC; msg.act = BTC_GATTC_ACT_CACHE_REFRESH; @@ -867,6 +895,10 @@ esp_err_t esp_ble_gattc_cache_clean(esp_bd_addr_t remote_bda) ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (remote_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTC; msg.act = BTC_GATTC_ACT_CACHE_CLEAN; @@ -882,6 +914,10 @@ esp_err_t esp_ble_gattc_cache_assoc(esp_gatt_if_t gattc_if, esp_bd_addr_t src_ad ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (src_addr == NULL || assoc_addr == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTC; msg.act = BTC_GATTC_ACT_CACHE_ASSOC; diff --git a/components/bt/host/bluedroid/api/esp_gatts_api.c b/components/bt/host/bluedroid/api/esp_gatts_api.c index 03c8186099..1d7c696126 100644 --- a/components/bt/host/bluedroid/api/esp_gatts_api.c +++ b/components/bt/host/bluedroid/api/esp_gatts_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -78,6 +78,10 @@ esp_err_t esp_ble_gatts_create_service(esp_gatt_if_t gatts_if, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (service_id == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTS; msg.act = BTC_GATTS_ACT_CREATE_SERVICE; @@ -98,6 +102,10 @@ esp_err_t esp_ble_gatts_create_attr_tab(const esp_gatts_attr_db_t *gatts_attr_db ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (gatts_attr_db == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (max_nb_attr > ESP_GATT_ATTR_HANDLE_MAX) { LOG_ERROR("The number of attribute should not be greater than CONFIG_BT_GATT_MAX_SR_ATTRIBUTES\n"); return ESP_ERR_INVALID_ARG; @@ -143,6 +151,10 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_ ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (char_uuid == NULL) { + return ESP_ERR_INVALID_ARG; + } + /* parameter validation check */ status = esp_ble_gatts_add_char_desc_param_check(char_val, control); if (status != ESP_OK){ @@ -183,6 +195,10 @@ esp_err_t esp_ble_gatts_add_char_descr (uint16_t service_handle, ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (descr_uuid == NULL) { + return ESP_ERR_INVALID_ARG; + } + /* parameter validation check */ status = esp_ble_gatts_add_char_desc_param_check(char_descr_val, control); if (status != ESP_OK){ @@ -344,6 +360,10 @@ esp_gatt_status_t esp_ble_gatts_get_attr_value(uint16_t attr_handle, uint16_t *l { ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (length == NULL || value == NULL) { + return ESP_GATT_INVALID_PDU; + } + if (attr_handle == ESP_GATT_ILLEGAL_HANDLE) { *length = 0; return ESP_GATT_INVALID_HANDLE; @@ -359,6 +379,10 @@ esp_err_t esp_ble_gatts_open(esp_gatt_if_t gatts_if, esp_bd_addr_t remote_bda, b ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + if (remote_bda == NULL) { + return ESP_ERR_INVALID_ARG; + } + msg.sig = BTC_SIG_API_CALL; msg.pid = BTC_PID_GATTS; msg.act = BTC_GATTS_ACT_OPEN; From 8739a2d82bbc5a9c660add40c007496217c66813 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:20 +0800 Subject: [PATCH 14/20] fix(ble/bluedroid): Fix VLA in a2dp_gatts_coex example (cherry picked from commit e741f09e0f4b959b76183d4a3492e16235ac9785) Co-authored-by: zhanghaipeng --- .../coex/a2dp_gatts_coex/main/main.c | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index e4456ea165..12e8bdd8b1 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -131,8 +131,24 @@ static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = { }; static void ble_init_adv_data(const char *name) { - int len = strlen(name); - uint8_t raw_adv_data[len+5]; + if (name == NULL) { + ESP_LOGE(BT_BLE_COEX_TAG, "ble_init_adv_data: name is NULL"); + return; + } + + size_t len = strlen(name); + // ADV data max is 31 bytes; overhead is 5 bytes (Flags: 3, Name header: 2) + #define ADV_DATA_MAX_LEN 31 + #define ADV_DATA_OVERHEAD 5 + + if (len > (ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD)) { + ESP_LOGW(BT_BLE_COEX_TAG, "ADV name too long (%d), truncating to %d", (int)len, ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD); + len = ADV_DATA_MAX_LEN - ADV_DATA_OVERHEAD; + } + + uint8_t raw_adv_data[ADV_DATA_MAX_LEN]; + size_t adv_data_len = len + ADV_DATA_OVERHEAD; + //flag raw_adv_data[0] = 2; raw_adv_data[1] = ESP_BT_EIR_TYPE_FLAGS; @@ -140,16 +156,14 @@ static void ble_init_adv_data(const char *name) //adv name raw_adv_data[3] = len + 1; raw_adv_data[4] = ESP_BLE_AD_TYPE_NAME_CMPL; - for (int i = 0;i < len;i++) - { - raw_adv_data[i+5] = *(name++); - } + memcpy(&raw_adv_data[5], name, len); + //The length of adv data must be less than 31 bytes - esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); + esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, adv_data_len); if (raw_adv_ret){ ESP_LOGE(BT_BLE_COEX_TAG, "config raw adv data failed, error code = 0x%x ", raw_adv_ret); } - esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_adv_data, sizeof(raw_adv_data)); + esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_adv_data, adv_data_len); if (raw_scan_ret){ ESP_LOGE(BT_BLE_COEX_TAG, "config raw scan rsp data failed, error code = 0x%x", raw_scan_ret); } From 1936ba80d714f88d3a8f577f25dc88d501a863b1 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:21 +0800 Subject: [PATCH 15/20] fix(ble/bluedroid): Add boundary check for adv_handle in btm_ble_adv_set_terminated_evt (cherry picked from commit d2baf3b0d4b8695abec90fa3fc1d46ce1bdab47b) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index 76fe63c08a..e82d95f61e 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -1254,6 +1254,11 @@ void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params) return; } + if (params->adv_handle >= MAX_BLE_ADV_INSTANCE) { + BTM_TRACE_ERROR("%s, Invalid adv_handle %d, max is %d.", __func__, params->adv_handle, MAX_BLE_ADV_INSTANCE); + return; + } + // adv terminated due to connection, save the adv handle and connection handle if(params->status == 0x00) { adv_record[params->adv_handle].ter_con_handle = params->conn_handle; From 569854b55af3d032dc1be1f0c7d0ce2f8fd2d09d Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:22 +0800 Subject: [PATCH 16/20] fix(ble/bluedroid): Add length check in prepare write response (cherry picked from commit b03ff3cf218c3974b798a700cf1ede95641fe7af) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/gatt/gatt_cl.c | 12 +++++----- .../bluedroid/stack/smp/include/smp_int.h | 5 ++++- .../bt/host/bluedroid/stack/smp/smp_l2c.c | 22 ++++++++++++++++--- .../bt/host/bluedroid/stack/smp/smp_utils.c | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c index 12168dc00d..ddd089f4e0 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c @@ -66,7 +66,7 @@ static const UINT16 disc_type_to_uuid[GATT_DISC_MAX] = { 0 /* no type filtering for DISC_CHAR_DSCPT */ }; -// Use for GATTC discover infomation print +// Use for GATTC discover information print #define GATT_DISC_INFO(fmt, args...) {if (gatt_cb.auto_disc == FALSE) BT_PRINT_I("BT_GATT", fmt, ## args);} /******************************************************************************* @@ -604,7 +604,7 @@ void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op GATT_TRACE_DEBUG("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len); - if (len < GATT_PREP_WRITE_RSP_MIN_LEN) { + if ((len < GATT_PREP_WRITE_RSP_MIN_LEN) || ((len - 4) > GATT_MAX_ATTR_LEN)) { GATT_TRACE_ERROR("illegal prepare write response length, discard"); gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value); return; @@ -701,7 +701,7 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, } p_tcb->ind_count = 0; - /* should notify all registered client with the handle value notificaion/indication + /* should notify all registered client with the handle value notification/indication Note: need to do the indication count and start timer first then do callback */ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { @@ -800,7 +800,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 handle_len = 4; } - value_len -= handle_len; /* substract the handle pairs bytes */ + value_len -= handle_len; /* subtract the handle pairs bytes */ len -= 1; while (len >= (handle_len + value_len)) { @@ -887,7 +887,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p); } return; - } else { /* discover characterisitic */ + } else { /* discover characteristic */ STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p); STREAM_TO_UINT16(record_value.dclr_value.val_handle, p); if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) { @@ -979,7 +979,7 @@ void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */ len + offset < GATT_MAX_ATTR_LEN) { - GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d", + GATT_TRACE_DEBUG("full pkt issue read blob for remaining bytes old offset=%d len=%d new offset=%d", offset, len, p_clcb->counter); gatt_act_read(p_clcb, p_clcb->counter); } else { /* end of request, send callback */ diff --git a/components/bt/host/bluedroid/stack/smp/include/smp_int.h b/components/bt/host/bluedroid/stack/smp/include/smp_int.h index f3ab7ad445..ca2dbfaf07 100644 --- a/components/bt/host/bluedroid/stack/smp/include/smp_int.h +++ b/components/bt/host/bluedroid/stack/smp/include/smp_int.h @@ -197,7 +197,7 @@ enum { }; typedef UINT8 tSMP_BR_STATE; -/* random and encrption activity state */ +/* random and encryption activity state */ enum { SMP_GEN_COMPARE = 1, SMP_GEN_CONFIRM, @@ -363,6 +363,9 @@ extern tSMP_CB *smp_cb_ptr; /* Functions provided by att_main.c */ extern void smp_init (void); +/* SMP command sizes per spec - defined in smp_utils.c */ +extern const UINT8 smp_cmd_size_per_spec[]; + /* smp main */ extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); diff --git a/components/bt/host/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c index a6f0670598..1f3db502e2 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -156,15 +156,31 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; - UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; - UINT8 cmd ; + UINT8 *p; + UINT8 cmd; SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__); + /* Validate packet length before accessing data to prevent out-of-bounds read */ + if (p_buf->len < 1) { + SMP_TRACE_WARNING ("Ignore empty SMP packet (len=%d)\n", p_buf->len); + osi_free (p_buf); + return; + } + + p = (UINT8 *)(p_buf + 1) + p_buf->offset; STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { - SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd); + SMP_TRACE_WARNING ("Ignore received command with RESERVED code 0x%02x\n", cmd); + osi_free (p_buf); + return; + } + + /* Validate command length to prevent out-of-bounds read in handler functions */ + if (p_buf->len != smp_cmd_size_per_spec[cmd]) { + SMP_TRACE_WARNING ("Ignore SMP cmd 0x%02x with invalid length %d (expected %d)\n", + cmd, p_buf->len, smp_cmd_size_per_spec[cmd]); osi_free (p_buf); return; } diff --git a/components/bt/host/bluedroid/stack/smp/smp_utils.c b/components/bt/host/bluedroid/stack/smp/smp_utils.c index 48ba6c0ae3..8ec4d548ac 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/host/bluedroid/stack/smp/smp_utils.c @@ -55,7 +55,7 @@ #define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/) /* SMP command sizes per spec */ -static const UINT8 smp_cmd_size_per_spec[] = { +const UINT8 smp_cmd_size_per_spec[] = { 0, SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */ SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */ From 7c7f30aa09af698517da4683119259fd70f9d39a Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:22 +0800 Subject: [PATCH 17/20] fix(ble/bluedroid): Fix security issues in GAP module (cherry picked from commit 1ed5a4465dbb0f6a36e0514ad1b2162616d356ca) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/gap/gap_ble.c | 21 ++++++++++++++---- .../bt/host/bluedroid/stack/gap/gap_conn.c | 22 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gap/gap_ble.c b/components/bt/host/bluedroid/stack/gap/gap_ble.c index e32151298e..bf3d97d666 100644 --- a/components/bt/host/bluedroid/stack/gap/gap_ble.c +++ b/components/bt/host/bluedroid/stack/gap/gap_ble.c @@ -104,7 +104,7 @@ tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id) } } - return p_clcb; + return NULL; } /******************************************************************************* @@ -126,10 +126,10 @@ tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda) memset(p_clcb, 0, sizeof(tGAP_CLCB)); p_clcb->in_use = TRUE; memcpy (p_clcb->bda, bda, BD_ADDR_LEN); - break; + return p_clcb; } } - return p_clcb; + return NULL; } /******************************************************************************* @@ -665,6 +665,12 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS switch (op_type) { case GATT_UUID_GAP_PREF_CONN_PARAM: GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM"); + /* Verify sufficient data length before reading connection parameters */ + if (p_data->att_value.len < 8) { + GAP_TRACE_ERROR ("GATT_UUID_GAP_PREF_CONN_PARAM: insufficient data length %d", p_data->att_value.len); + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + break; + } /* Extract the peripheral preferred connection parameters and save them */ STREAM_TO_UINT16 (min, pp); @@ -679,7 +685,8 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS case GATT_UUID_GAP_DEVICE_NAME: GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME\n"); - len = (UINT16)strlen((char *)pp); + /* Use att_value.len instead of strlen to avoid reading beyond buffer */ + len = p_data->att_value.len; if (len > GAP_CHAR_DEV_NAME_SIZE) { len = GAP_CHAR_DEV_NAME_SIZE; } @@ -687,6 +694,12 @@ static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS break; case GATT_UUID_GAP_CENTRAL_ADDR_RESOL: + /* Verify sufficient data length */ + if (p_data->att_value.len < 1) { + GAP_TRACE_ERROR ("GATT_UUID_GAP_CENTRAL_ADDR_RESOL: insufficient data length"); + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + break; + } gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp); break; } diff --git a/components/bt/host/bluedroid/stack/gap/gap_conn.c b/components/bt/host/bluedroid/stack/gap/gap_conn.c index db9065de81..cdd6a2d3a9 100644 --- a/components/bt/host/bluedroid/stack/gap/gap_conn.c +++ b/components/bt/host/bluedroid/stack/gap/gap_conn.c @@ -148,7 +148,7 @@ UINT16 GAP_ConnOpen (const char *p_serv_name, UINT8 service_id, BOOLEAN is_serve memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN); } else if (!is_server) { - /* remore addr is not specified and is not a server -> bad */ + /* remote addr is not specified and is not a server -> bad */ return (GAP_INVALID_HANDLE); } @@ -775,7 +775,9 @@ static void gap_checks_con_flags (tGAP_CCB *p_ccb) if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) { p_ccb->con_state = GAP_CCB_STATE_CONNECTED; - p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED); + if (p_ccb->p_callback) { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED); + } } } @@ -933,7 +935,9 @@ static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) gap_checks_con_flags (p_ccb); } else { - p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + if (p_ccb->p_callback) { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + } gap_release_ccb (p_ccb); } } @@ -964,7 +968,9 @@ static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) L2CA_DISCONNECT_RSP (l2cap_cid); } - p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + if (p_ccb->p_callback) { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + } gap_release_ccb (p_ccb); } @@ -997,7 +1003,9 @@ static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) p_ccb->rx_queue_size, p_msg->len); */ - p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL); + if (p_ccb->p_callback) { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL); + } } else { osi_free (p_msg); } @@ -1030,7 +1038,9 @@ static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested) p_ccb->is_congested = is_congested; event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED; - p_ccb->p_callback (p_ccb->gap_handle, event); + if (p_ccb->p_callback) { + p_ccb->p_callback (p_ccb->gap_handle, event); + } if (!is_congested) { while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) { From ef96110b4d85792983dd98c204d0bba06b9b20bf Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:23 +0800 Subject: [PATCH 18/20] fix(ble/bluedroid): Fix security issues in HCI module (cherry picked from commit b163685c060047783b0ad3a4b83f2b27302f397c) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/hci/hci_layer.c | 12 ++++++++---- components/bt/host/bluedroid/hci/hci_packet_parser.c | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index e5cd263fbc..34bdb57093 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -452,10 +452,12 @@ static bool filter_incoming_event(BT_HDR *packet) STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); - metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); - } else if (metadata->command_complete_cb) { + goto intercepted; + } + metadata = (hci_cmd_metadata_t *)(wait_entry->data); + if (metadata->command_complete_cb) { metadata->command_complete_cb(packet, metadata->context); #if (BLE_50_FEATURE_SUPPORT == TRUE) BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info(); @@ -482,10 +484,12 @@ static bool filter_incoming_event(BT_HDR *packet) // If a command generates a command status event, it won't be getting a command complete event wait_entry = get_waiting_command(opcode); - metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); - } else if (metadata->command_status_cb) { + goto intercepted; + } + metadata = (hci_cmd_metadata_t *)(wait_entry->data); + if (metadata->command_status_cb) { metadata->command_status_cb(status, &metadata->command, metadata->context); } diff --git a/components/bt/host/bluedroid/hci/hci_packet_parser.c b/components/bt/host/bluedroid/hci/hci_packet_parser.c index b254c9be2a..560ee7b4a1 100644 --- a/components/bt/host/bluedroid/hci/hci_packet_parser.c +++ b/components/bt/host/bluedroid/hci/hci_packet_parser.c @@ -164,7 +164,7 @@ static void parse_ble_read_buffer_size_response_v2 ( uint8_t *iso_pkt_num_ptr) { - uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_BUFFER_SZIE_V2, 3 /* bytes after */); + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_BUFFER_SZIE_V2, 6 /* bytes after: 2+1+2+1 */); assert(stream != NULL); STREAM_TO_UINT16(*data_size_ptr, stream); STREAM_TO_UINT8(*acl_buffer_count_ptr, stream); From d28b874e35b194549d977a6e599cac77e6330a8e Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:24 +0800 Subject: [PATCH 19/20] fix(ble/bluedroid): Fix security issues in GATT module (cherry picked from commit f502b2aab1cfd0002f66e5978771ecbd9c1113ed) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/gatt/gatt_db.c | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c index 8844ef5dc8..6c578e678f 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_db.c @@ -1039,20 +1039,23 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db, return GATT_APP_RSP; } - if ((p_attr->p_value != NULL) && - (p_attr->p_value->attr_val.attr_max_len >= offset + len) && - p_attr->p_value->attr_val.attr_val != NULL) { - memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len); - p_attr->p_value->attr_val.attr_len = len + offset; - return GATT_SUCCESS; - } else if (p_attr->p_value && p_attr->p_value->attr_val.attr_max_len < offset + len){ - GATT_TRACE_DEBUG("Remote device try to write with a length larger then attribute's max length\n"); - return GATT_INVALID_ATTR_LEN; - } else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){ + if (p_attr->p_value == NULL || p_attr->p_value->attr_val.attr_val == NULL) { GATT_TRACE_ERROR("Error in %s, line=%d, %s should not be NULL here\n", __func__, __LINE__, \ (p_attr->p_value == NULL) ? "p_value" : "attr_val.attr_val"); return GATT_UNKNOWN_ERROR; } + + /* Check for integer overflow: offset + len must not overflow UINT16 + * and must not exceed attr_max_len */ + if (offset > p_attr->p_value->attr_val.attr_max_len || + len > p_attr->p_value->attr_val.attr_max_len - offset) { + GATT_TRACE_DEBUG("Remote device try to write with a length larger than attribute's max length\n"); + return GATT_INVALID_ATTR_LEN; + } + + memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len); + p_attr->p_value->attr_val.attr_len = offset + len; + return GATT_SUCCESS; } p_attr = (tGATT_ATTR16 *)p_attr->p_next; From c4cc87501b9b47b4bbfa0dfbee4a6edcdbea7229 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Wed, 17 Dec 2025 17:10:58 +0800 Subject: [PATCH 20/20] fix(ble/bledroid): fix codespell issues in bluedroid code --- components/bt/host/bluedroid/stack/gatt/att_protocol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c index b336aecc38..9b3a2507a3 100644 --- a/components/bt/host/bluedroid/stack/gatt/att_protocol.c +++ b/components/bt/host/bluedroid/stack/gatt/att_protocol.c @@ -33,7 +33,7 @@ #define GATT_HDR_FIND_TYPE_VALUE_LEN 21 #define GATT_OP_CODE_SIZE 1 /********************************************************************** -** ATT protocl message building utility * +** ATT protocol message building utility * ***********************************************************************/ /******************************************************************************* ** @@ -494,7 +494,7 @@ BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) ** Description This function sends the server response or indication message ** to client. ** -** Parameter p_tcb: pointer to the connecton control block. +** Parameter p_tcb: pointer to the connection control block. ** p_msg: pointer to message parameters structure. ** ** Returns GATT_SUCCESS if successfully sent; otherwise error code.