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 <cursoragent@cursor.com>
This commit is contained in:
xiongweichao
2026-09-22 14:14:34 +08:00
co-authored by Cursor
parent 2b2b88a33c
commit a72a6b60fb
5 changed files with 50 additions and 10 deletions
@@ -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);
}
@@ -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);
@@ -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;
}
@@ -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);
@@ -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);