From 2b2b88a33c1acb2fb5128c1d5a8519b2faaf2329 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 21 Sep 2026 10:20:44 +0800 Subject: [PATCH 1/2] fix(bt/bluedroid): fixed heap corruption when deinit SPP during SDP discovery bta_jv_disable() reset the control block and let BTA_JvFree() release p_sdp_db/p_sdp_raw_data while an SDP service search could still be in progress. Late SDP responses were then parsed into the freed discovery database and corrupted the heap, so the crash surfaced much later in an unrelated malloc(), inside TLSF remove_free_block(). Cancel the search first. SDP_CancelServiceSearch() moves the connection control block to SDP_DISC_WAIT_CANCEL, and sdp_disc_server_rsp() matches none of its PDU cases in that state, so a late response is rejected instead of being written into the database. Reachable from both esp_spp_deinit() and esp_bt_l2cap_deinit(), e.g. when an application deinitializes SPP before ESP_SPP_DISCOVERY_COMP_EVT arrives. --- components/bt/host/bluedroid/bta/jv/bta_jv_act.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c index e5ac11a10ad..1c24cd5844f 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -754,6 +754,15 @@ void bta_jv_disable (tBTA_JV_MSG *p_data) tBTA_JV_STATUS evt_data; evt_data = BTA_JV_SUCCESS; + /* An SDP search still in progress keeps writing into p_bta_jv_cfg->p_sdp_db, + * which BTA_JvFree() releases once BTA_JV_DISABLE_EVT is handled. Cancel it + * first: the connection control block then rejects any late response instead + * of parsing it into freed memory. */ + if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) { + APPL_TRACE_WARNING("%s: SDP discovery active, cancelling it", __func__); + SDP_CancelServiceSearch(p_bta_jv_cfg->p_sdp_db); + } + // clear all the pm_cb slots for (int i = 0; i < BTA_JV_PM_MAX_NUM; i++) { if (bta_jv_cb.pm_cb[i].state != BTA_JV_PM_FREE_ST) { From a72a6b60fb383de76da183f6c81d53b2d1f22ed2 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 21 Sep 2026 11:16:52 +0800 Subject: [PATCH 2/2] fix(bt/bluedroid): fixed heap corruption when deinit A2DP/HID during SDP discovery Cancel in-flight SDP searches before freeing discovery databases in BTA AV and HID Host. Otherwise a late SDP response can be parsed into a freed buffer after esp_a2d_*_deinit / HID host disable, the same class of corruption as JV/SPP deinit. Co-authored-by: Cursor --- .../bt/host/bluedroid/bta/av/bta_av_aact.c | 12 ++++++---- .../bt/host/bluedroid/bta/av/bta_av_act.c | 15 +++++++++++-- .../bt/host/bluedroid/bta/hh/bta_hh_act.c | 10 ++++++--- .../bt/host/bluedroid/bta/hh/bta_hh_utils.c | 22 ++++++++++++++++++- .../bluedroid/bta/hh/include/bta_hh_int.h | 1 + 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/components/bt/host/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c index 1120c9fb0b5..1cf3d65714e 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -35,6 +35,7 @@ #include "bta_av_int.h" #include "stack/avdt_api.h" +#include "stack/sdp_api.h" #include "bta/utl.h" #include "stack/l2c_api.h" #include "stack/l2cdefs.h" @@ -1035,7 +1036,7 @@ void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) /* free any buffers */ utl_freebuf((void **) &p_scb->p_cap); - utl_freebuf((void **) &p_scb->p_disc_db); + bta_av_free_sdb(p_scb, NULL); p_scb->avdt_version = 0; /* initialize some control block variables */ @@ -1082,7 +1083,10 @@ void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { UNUSED(p_data); - utl_freebuf((void **) &p_scb->p_disc_db); + if (p_scb->p_disc_db) { + SDP_CancelServiceSearch(p_scb->p_disc_db); + utl_freebuf((void **) &p_scb->p_disc_db); + } } /******************************************************************************* @@ -1586,7 +1590,7 @@ void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { UNUSED(p_data); - utl_freebuf((void **) &p_scb->p_disc_db); + bta_av_free_sdb(p_scb, NULL); if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { /* SNK initiated L2C connection while SRC was doing SDP. */ @@ -1613,7 +1617,7 @@ void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_scb->open_status = BTA_AV_FAIL_SDP; } - utl_freebuf((void **) &p_scb->p_disc_db); + bta_av_free_sdb(p_scb, NULL); bta_av_str_closed(p_scb, p_data); } diff --git a/components/bt/host/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c index 00f6b5f341c..42185814e6e 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_act.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_act.c @@ -31,6 +31,7 @@ #include "bta_av_int.h" #include "stack/avdt_api.h" #include "bta/utl.h" +#include "stack/sdp_api.h" #include "stack/l2c_api.h" #include "osi/allocator.h" #include "osi/list.h" @@ -1302,7 +1303,14 @@ void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) bta_av_close_all_rc(p_cb); - utl_freebuf((void **) &p_cb->p_disc_db); + /* Clear disc first so a late BTA_AV_SDP_AVRC_DISC_EVT hits + * bta_av_rc_disc_done()'s if (!p_cb->disc) and does not scan p_disc_db. */ + p_cb->disc = 0; + if (p_cb->p_disc_db) { + /* SDP may still be writing into this buffer (AVRCP discovery). */ + SDP_CancelServiceSearch(p_cb->p_disc_db); + utl_freebuf((void **) &p_cb->p_disc_db); + } /* disable audio/video - de-register all channels, * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */ @@ -1757,7 +1765,10 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) } #endif p_cb->disc = 0; - utl_freebuf((void **) &p_cb->p_disc_db); + if (p_cb->p_disc_db) { + SDP_CancelServiceSearch(p_cb->p_disc_db); + utl_freebuf((void **) &p_cb->p_disc_db); + } APPL_TRACE_DEBUG("peer_features 0x%x, local features 0x%x", peer_features, p_cb->features); diff --git a/components/bt/host/bluedroid/bta/hh/bta_hh_act.c b/components/bt/host/bluedroid/bta/hh/bta_hh_act.c index efe6a99ebd9..42bc2a04f7a 100644 --- a/components/bt/host/bluedroid/bta/hh/bta_hh_act.c +++ b/components/bt/host/bluedroid/bta/hh/bta_hh_act.c @@ -35,6 +35,7 @@ #include "bta/bta_hh_co.h" #include "bta/utl.h" #include "osi/allocator.h" +#include "stack/sdp_api.h" /***************************************************************************** ** Constants @@ -129,6 +130,9 @@ void bta_hh_api_disable(void) return; } + /* Drop in-flight SDP before tearing down connections / HID host. */ + bta_hh_free_disc_db(); + /* no live connection, signal DISC_CMPL_EVT directly */ if (!bta_hh_cb.cnt_num) { bta_hh_disc_cmpl(); @@ -243,7 +247,7 @@ static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask, } /* free disc_db when SDP is completed */ - utl_freebuf((void **)&bta_hh_cb.p_disc_db); + bta_hh_free_disc_db(); /* send SDP_CMPL_EVT into state machine */ data.status = status; @@ -301,7 +305,7 @@ static void bta_hh_di_sdp_cback(UINT16 result) if (status != BTA_HH_OK) { - utl_freebuf((void **)&bta_hh_cb.p_disc_db); + bta_hh_free_disc_db(); /* send SDP_CMPL_EVT into state machine */ data.status = status; bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &data); @@ -384,7 +388,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) Status 0x%2X", status); #endif status = BTA_HH_ERR_SDP; - utl_freebuf((void **)&bta_hh_cb.p_disc_db); + bta_hh_free_disc_db(); } else { status = BTA_HH_OK; } 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 360b3fd85ea..48a7239c586 100644 --- a/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c +++ b/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c @@ -22,6 +22,7 @@ #include "osi/allocator.h" #include "bta_hh_int.h" +#include "stack/sdp_api.h" /* if SSR max latency is not defined by remote device, set the default value as half of the link supervision timeout */ @@ -462,6 +463,25 @@ tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UIN return status; } +/******************************************************************************* +** +** Function bta_hh_free_disc_db +** +** Description Cancel any in-flight SDP search using the HID discovery +** database, then free it. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_free_disc_db(void) +{ + if (bta_hh_cb.p_disc_db) { + /* SDP (DI discover / HID_HostGetSDPRecord) may still write this buffer. */ + SDP_CancelServiceSearch(bta_hh_cb.p_disc_db); + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + } +} + /******************************************************************************* ** ** Function bta_hh_cleanup_disable @@ -479,7 +499,7 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) { utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); } - utl_freebuf((void **)&bta_hh_cb.p_disc_db); + bta_hh_free_disc_db(); bta_sys_deregister(BTA_ID_HH); diff --git a/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h b/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h index 56f99e8420d..fc6b06de1d9 100644 --- a/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h +++ b/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h @@ -356,6 +356,7 @@ extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, UINT16 version, UINT8 flag); extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status); +extern void bta_hh_free_disc_db(void); extern UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle);