From a0ba14e55dd90f8a087227aac8ce93baf353ef3d Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Tue, 30 Jun 2026 16:27:18 +0800 Subject: [PATCH 1/6] fix(bt/bluedroid): fixed wrong link key flag cleared on legacy BR/EDR authentication failure Stale bond trust state cound remain after authenticaion failure, causing incorrect bond status and link key auto-reply behavior. Closes SEC-1153 --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index a744bc30322..fcf9261534a 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -4490,7 +4490,7 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || (status == HCI_ERR_REPEATED_ATTEMPTS)))) { p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; - p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift); + p_dev_rec->sec_flags &= ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift); #ifdef BRCM_NOT_4_BTE From 91d80bf8742540c79195191b26db6780b2724720 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 2 Jul 2026 19:12:05 +0800 Subject: [PATCH 2/6] fix(bt/bluedroid): fixed integer overflow in HID report descriptor parser Closes SEC-084 --- components/esp_hid/src/esp_hid_common.c | 46 +++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/components/esp_hid/src/esp_hid_common.c b/components/esp_hid/src/esp_hid_common.c index 2b0760bccbf..636c53785d0 100644 --- a/components/esp_hid/src/esp_hid_common.c +++ b/components/esp_hid/src/esp_hid_common.c @@ -1,9 +1,11 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include #include #include "esp_log.h" @@ -65,6 +67,19 @@ static int add_report(temp_hid_report_map_t *map, esp_hid_report_item_t *item) return 0; } +static int add_report_len_bits_to(uint16_t *len_bits, uint16_t size, uint16_t count) +{ + uint32_t add = (uint32_t)size * (uint32_t)count; + uint32_t new_len = (uint32_t)(*len_bits) + add; + + if (new_len > UINT16_MAX) { + ESP_LOGE(TAG, "report length overflow: %u + %u * %u", *len_bits, size, count); + return -1; + } + *len_bits = (uint16_t)new_len; + return 0; +} + static int handle_report(hid_report_params_t *report, bool first) { if (s_temp_hid_report_map == NULL) { @@ -290,15 +305,34 @@ static int handle_cmd(hid_report_cmd_t *cmd) } else if (cmd->cmd == HID_RM_USAGE) { s_report_params.inner_usage = cmd->value; } else if (cmd->cmd == HID_RM_REPORT_SIZE) { - s_report_size = cmd->value; + if (cmd->value > UINT16_MAX) { + ESP_LOGE(TAG, "REPORT_SIZE too large: %" PRIu32, cmd->value); + s_parse_step = PARSE_WAIT_USAGE_PAGE; + return -1; + } + s_report_size = (uint16_t)cmd->value; } else if (cmd->cmd == HID_RM_REPORT_COUNT) { - s_report_count = cmd->value; + if (cmd->value > UINT16_MAX) { + ESP_LOGE(TAG, "REPORT_COUNT too large: %" PRIu32, cmd->value); + s_parse_step = PARSE_WAIT_USAGE_PAGE; + return -1; + } + s_report_count = (uint16_t)cmd->value; } else if (cmd->cmd == HID_RM_INPUT) { - s_report_params.input_len += (s_report_size * s_report_count); + if (add_report_len_bits_to(&s_report_params.input_len, s_report_size, s_report_count) != 0) { + s_parse_step = PARSE_WAIT_USAGE_PAGE; + return -1; + } } else if (cmd->cmd == HID_RM_OUTPUT) { - s_report_params.output_len += (s_report_size * s_report_count); + if (add_report_len_bits_to(&s_report_params.output_len, s_report_size, s_report_count) != 0) { + s_parse_step = PARSE_WAIT_USAGE_PAGE; + return -1; + } } else if (cmd->cmd == HID_RM_FEATURE) { - s_report_params.feature_len += (s_report_size * s_report_count); + if (add_report_len_bits_to(&s_report_params.feature_len, s_report_size, s_report_count) != 0) { + s_parse_step = PARSE_WAIT_USAGE_PAGE; + return -1; + } } else if (cmd->cmd == HID_RM_COLLECTION) { s_collection_depth += 1; } else if (cmd->cmd == HID_RM_END_COLLECTION) { From 81c8d1b999091db26d3defab1ba5f3963dcf4308 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 2 Jul 2026 19:32:02 +0800 Subject: [PATCH 3/6] fix(bt/bluedroid): fixed NULL dereference in remote legacy authentication handler Closes SEC-1143 --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index fcf9261534a..0399ec0bdd9 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -6394,9 +6394,10 @@ void btm_sec_update_legacy_auth_state(tACL_CONN *p_acl_cb, UINT8 legacy_auth_sta *******************************************************************************/ void btm_sec_handle_remote_legacy_auth_cmp(UINT16 handle) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); - tACL_CONN *p_acl_cb = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR); - btm_sec_update_legacy_auth_state(p_acl_cb, BTM_ACL_LEGACY_AUTH_REMOTE); + tACL_CONN *p_acl_cb = btm_handle_to_acl(handle); + if (p_acl_cb) { + btm_sec_update_legacy_auth_state(p_acl_cb, BTM_ACL_LEGACY_AUTH_REMOTE); + } } #endif /// (CLASSIC_BT_INCLUDED == TRUE) #endif ///SMP_INCLUDED == TRUE From 02841cdf506bda96eee948b33c6ba8411ff8e229 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 2 Jul 2026 19:44:17 +0800 Subject: [PATCH 4/6] fix(bt/bluedroid): fixed HID host slot leak on local VUP ACL drop Closes SEC-1169 --- components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c index 228b62cd959..9a787421323 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c @@ -1407,10 +1407,11 @@ void btc_hh_cb_handler(btc_msg_t *msg) BTA_DmRemoveDevice(p_dev->bd_addr, BT_TRANSPORT_BR_EDR); #endif btc_hh_remove_device(p_dev->bd_addr); + } else { + p_dev->dev_status = ESP_HIDH_CONN_STATE_DISCONNECTED; } btc_hh_cb.status = (BTC_HH_STATUS)BTC_HH_DEV_DISCONNECTED; - p_dev->dev_status = ESP_HIDH_CONN_STATE_DISCONNECTED; param.close.status = p_data->dev_status.status; } else { BTC_TRACE_ERROR("Error: cannot find device with handle %d", p_data->dev_status.handle); From b6a8e896e71d666e5345029c4f6c29bff26925dd Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 2 Jul 2026 19:51:06 +0800 Subject: [PATCH 5/6] fix(bt/bluedroid): fixed stuck sec_state on authention HCI command send failure Closes SEC-1164 --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index 0399ec0bdd9..698037a82fc 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -5453,9 +5453,11 @@ static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec) *******************************************************************************/ static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec) { - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; - - return (btsnd_hcic_auth_request (p_dev_rec->hci_handle)); + if (btsnd_hcic_auth_request (p_dev_rec->hci_handle)) { + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + return TRUE; + } + return FALSE; } /******************************************************************************* From e4c999e8913078900e3bf4bd31608acd6b647d92 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 2 Jul 2026 20:17:38 +0800 Subject: [PATCH 6/6] fix(bt/bluedroid): fixed OOB read in PBAP app parameter parsing Closes SEC-713 --- .../btc/profile/std/pba/btc_pba_client.c | 92 +++++++++++++++++-- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c index 8f3e2a7fa1b..128f9a30f98 100644 --- a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c +++ b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c @@ -716,26 +716,51 @@ void btc_pba_client_call_handler(btc_msg_t *msg) } } +static bool btc_pba_client_app_param_tag_valid(const uint8_t *ptr, const uint8_t *end, uint8_t value_len) +{ + if (ptr + BTA_PBAP_APP_PARAM_HEADER_LENGTH > end) { + return false; + } + + if (ptr[1] != value_len) { + return false; + } + + return (ptr + BTA_PBAP_APP_PARAM_HEADER_LENGTH + value_len <= end); +} + static void parse_pull_phone_book_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len) { if (app_param == NULL || app_param_len == 0) { return; } + uint8_t *ptr = app_param; - while(ptr < app_param + app_param_len) { + const uint8_t *end = app_param + app_param_len; + + while (ptr < end) { switch (*ptr) { case BTA_PBAP_APP_PARAM_PHONE_BOOK_SIZE: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_PHONE_BOOK_SIZE)) { + goto error; + } param->pull_phone_book_rsp.include_phone_book_size = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; BE_STREAM_TO_UINT16(param->pull_phone_book_rsp.phone_book_size, ptr); break; case BTA_PBAP_APP_PARAM_NEW_MISSED_CALLS: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_NEW_MISSED_CALLS)) { + goto error; + } param->pull_phone_book_rsp.include_new_missed_calls = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; BE_STREAM_TO_UINT8(param->pull_phone_book_rsp.new_missed_calls, ptr); break; case BTA_PBAP_APP_PARAM_PRIMARY_FOLDER_VERSION: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION)) { + goto error; + } param->pull_phone_book_rsp.include_primary_folder_version = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -743,6 +768,9 @@ static void parse_pull_phone_book_app_param(esp_pbac_param_t *param, uint8_t *ap ptr += BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION; break; case BTA_PBAP_APP_PARAM_SECONDARY_FOLDER_VERSION: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION)) { + goto error; + } param->pull_phone_book_rsp.include_secondary_folder_version = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -750,6 +778,9 @@ static void parse_pull_phone_book_app_param(esp_pbac_param_t *param, uint8_t *ap ptr += BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION; break; case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER)) { + goto error; + } param->pull_phone_book_rsp.include_database_identifier = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -761,8 +792,19 @@ static void parse_pull_phone_book_app_param(esp_pbac_param_t *param, uint8_t *ap break; } } -error: return; + +error: + param->pull_phone_book_rsp.include_phone_book_size = 0; + param->pull_phone_book_rsp.phone_book_size = 0; + param->pull_phone_book_rsp.include_new_missed_calls = 0; + param->pull_phone_book_rsp.new_missed_calls = 0; + param->pull_phone_book_rsp.include_primary_folder_version = 0; + param->pull_phone_book_rsp.primary_folder_version = NULL; + param->pull_phone_book_rsp.include_secondary_folder_version = 0; + param->pull_phone_book_rsp.secondary_folder_version = NULL; + param->pull_phone_book_rsp.include_database_identifier = 0; + param->pull_phone_book_rsp.database_identifier = NULL; } static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len) @@ -770,21 +812,33 @@ static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t if (app_param == NULL || app_param_len == 0) { return; } + uint8_t *ptr = app_param; - while(ptr < app_param + app_param_len) { + const uint8_t *end = app_param + app_param_len; + + while (ptr < end) { switch (*ptr) { case BTA_PBAP_APP_PARAM_PHONE_BOOK_SIZE: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_PHONE_BOOK_SIZE)) { + goto error; + } param->pull_vcard_listing_rsp.include_phone_book_size = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; BE_STREAM_TO_UINT16(param->pull_vcard_listing_rsp.phone_book_size, ptr); break; case BTA_PBAP_APP_PARAM_NEW_MISSED_CALLS: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_NEW_MISSED_CALLS)) { + goto error; + } param->pull_vcard_listing_rsp.include_new_missed_calls = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; BE_STREAM_TO_UINT8(param->pull_vcard_listing_rsp.new_missed_calls, ptr); break; case BTA_PBAP_APP_PARAM_PRIMARY_FOLDER_VERSION: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION)) { + goto error; + } param->pull_vcard_listing_rsp.include_primary_folder_version = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -792,6 +846,9 @@ static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t ptr += BTA_PBAP_APP_PARAM_LENGTH_PRIMARY_FOLDER_VERSION; break; case BTA_PBAP_APP_PARAM_SECONDARY_FOLDER_VERSION: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION)) { + goto error; + } param->pull_vcard_listing_rsp.include_secondary_folder_version = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -799,6 +856,9 @@ static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t ptr += BTA_PBAP_APP_PARAM_LENGTH_SECONDARY_FOLDER_VERSION; break; case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER)) { + goto error; + } param->pull_vcard_listing_rsp.include_database_identifier = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -810,8 +870,19 @@ static void parse_pull_vcard_listing_app_param(esp_pbac_param_t *param, uint8_t break; } } -error: return; + +error: + param->pull_vcard_listing_rsp.include_phone_book_size = 0; + param->pull_vcard_listing_rsp.phone_book_size = 0; + param->pull_vcard_listing_rsp.include_new_missed_calls = 0; + param->pull_vcard_listing_rsp.new_missed_calls = 0; + param->pull_vcard_listing_rsp.include_primary_folder_version = 0; + param->pull_vcard_listing_rsp.primary_folder_version = NULL; + param->pull_vcard_listing_rsp.include_secondary_folder_version = 0; + param->pull_vcard_listing_rsp.secondary_folder_version = NULL; + param->pull_vcard_listing_rsp.include_database_identifier = 0; + param->pull_vcard_listing_rsp.database_identifier = NULL; } static void parse_pull_vcard_entry_app_param(esp_pbac_param_t *param, uint8_t *app_param, uint16_t app_param_len) @@ -819,11 +890,17 @@ static void parse_pull_vcard_entry_app_param(esp_pbac_param_t *param, uint8_t *a if (app_param == NULL || app_param_len == 0) { return; } + uint8_t *ptr = app_param; - while(ptr < app_param + app_param_len) { + const uint8_t *end = app_param + app_param_len; + + while (ptr < end) { switch (*ptr) { case BTA_PBAP_APP_PARAM_DATABASE_IDENTIFIER: + if (!btc_pba_client_app_param_tag_valid(ptr, end, BTA_PBAP_APP_PARAM_LENGTH_DATABASE_IDENTIFIER)) { + goto error; + } param->pull_vcard_entry_rsp.include_database_identifier = 1; ptr += BTA_PBAP_APP_PARAM_HEADER_LENGTH; /* don't copy */ @@ -835,8 +912,11 @@ static void parse_pull_vcard_entry_app_param(esp_pbac_param_t *param, uint8_t *a break; } } -error: return; + +error: + param->pull_vcard_entry_rsp.include_database_identifier = 0; + param->pull_vcard_entry_rsp.database_identifier = NULL; } static uint16_t get_next_dir_len_from_path(char *path, uint16_t path_len, uint16_t path_pos)