fix(ble/bluedroid): Add null/range checks and fix resource handling in BTA layer

- bta_dm_int: fix BTA_SERVICE_ID_TO_SERVICE_MASK undefined behavior (1<<id when id>=32)
- bta_gattc_main: add event bounds check before state table lookup
- bta_gattc_utils: null checks for remote_bda/p_rcb, fix list_free in clcb_dealloc,
  bta_to_btif_uuid fixes
- bta_gatts_act: fix formatting/indent in send_service_change_indication
- bta_gatts_api: validate attr_val/len, add error logs on alloc failure
- bta_sys_main: null/range checks in sm_execute, alarm/hash_map error handling in
  bta_alarm_cb
This commit is contained in:
zhiweijian
2026-03-18 16:33:02 +08:00
parent 6fc4116876
commit f4cec2ac4e
6 changed files with 83 additions and 20 deletions
@@ -45,7 +45,8 @@
#define BTA_DM_MSG_LEN 50
#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
/* Use 1ULL to avoid UB: 1 << 32 is undefined when int is 32-bit (C11 §6.5.7) */
#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) ((UINT32)(1ULL << (id)))
/* DM events */
enum {
@@ -108,7 +108,6 @@ const tBTA_GATTC_ACTION bta_gattc_action[] = {
#define BTA_GATTC_ACTIONS 1 /* number of actions */
#define BTA_GATTC_NEXT_STATE 1 /* position of next state */
#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */
/* state table for idle state */
static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = {
/* Event Action 1 Next state */
@@ -298,6 +297,11 @@ BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_D
event &= 0x00FF;
if (event >= sizeof(bta_gattc_st_idle) / sizeof(bta_gattc_st_idle[0])) {
APPL_TRACE_ERROR("bta_gattc_sm_execute: invalid event index %d", event);
return TRUE;
}
/* set next state */
p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
@@ -125,8 +125,13 @@ tBTA_GATTC_CLCB *bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda
tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0];
UINT8 i;
if (remote_bda == NULL) {
return NULL;
}
for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) {
if (p_clcb->in_use &&
p_clcb->p_rcb != NULL &&
p_clcb->p_rcb->client_if == client_if &&
p_clcb->transport == transport &&
bdcmp(p_clcb->bda, remote_bda) == 0) {
@@ -244,16 +249,16 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb)
if (p_clcb) {
p_srcb = p_clcb->p_srcb;
if (p_srcb->num_clcb) {
if (p_srcb != NULL && p_srcb->num_clcb) {
p_srcb->num_clcb --;
}
if (p_clcb->p_rcb->num_clcb) {
if (p_clcb->p_rcb != NULL && p_clcb->p_rcb->num_clcb) {
p_clcb->p_rcb->num_clcb --;
}
/* if the srcb is no longer needed, reset the state */
if ( p_srcb->num_clcb == 0) {
if (p_srcb != NULL && p_srcb->num_clcb == 0) {
p_srcb->connected = FALSE;
p_srcb->state = BTA_GATTC_SERV_IDLE;
p_srcb->mtu = 0;
@@ -268,13 +273,13 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb)
#endif
}
if ( p_clcb->p_q_cmd != NULL && !list_contains(p_clcb->p_cmd_list, p_clcb->p_q_cmd)){
if (p_clcb->p_q_cmd != NULL &&
(p_clcb->p_cmd_list == NULL || !list_contains(p_clcb->p_cmd_list, p_clcb->p_q_cmd))) {
osi_free(p_clcb->p_q_cmd);
p_clcb->p_q_cmd = NULL;
}
// don't forget to clear the command queue before dealloc the clcb.
list_clear(p_clcb->p_cmd_list);
osi_free((void *)p_clcb->p_cmd_list);
list_free(p_clcb->p_cmd_list);
p_clcb->p_cmd_list = NULL;
//osi_free_and_reset((void **)&p_clcb->p_q_cmd);
memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
@@ -970,6 +975,10 @@ tBTA_GATTC_CLCB *bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA *p_msg)
{
tBTA_GATTC_CLCB *p_clcb = NULL;
if (p_msg == NULL) {
return NULL;
}
if (p_msg->int_conn.role == HCI_ROLE_SLAVE) {
bta_gattc_conn_find_alloc(p_msg->int_conn.remote_bda);
}
@@ -1005,6 +1014,10 @@ tBTA_GATTC_CLCB *bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA *p_msg)
{
tBTA_GATTC_CLCB *p_clcb = NULL;
if (p_msg == NULL) {
return NULL;
}
bta_gattc_conn_dealloc(p_msg->int_conn.remote_bda);
if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->int_conn.hdr.layer_specific)) == NULL) {
/* connection attempt failed, send connection callback event */
@@ -1033,6 +1046,8 @@ void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src)
switch (p_src->len)
{
case 0:
/* Invalid/empty UUID: zero p_dest so callers don't use garbage */
memset(p_dest->uu, 0, sizeof(p_dest->uu));
break;
case LEN_UUID_16:
@@ -1041,8 +1056,8 @@ void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src)
break;
case LEN_UUID_32:
p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
p_dest->uu[12] = p_src->uu.uuid32 & 0xff;
p_dest->uu[13] = (p_src->uu.uuid32 >> 8) & 0xff;
p_dest->uu[14] = (p_src->uu.uuid32 >> 16) & 0xff;
p_dest->uu[15] = (p_src->uu.uuid32 >> 24) & 0xff;
break;
@@ -1054,6 +1069,7 @@ void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src)
default:
APPL_TRACE_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_src->len);
memset(p_dest->uu, 0, sizeof(p_dest->uu));
break;
}
}
@@ -872,7 +872,7 @@ void bta_gatts_send_service_change_indication (tBTA_GATTS_DATA *p_msg)
tBTA_GATTS_RCB *p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_send_service_change.server_if);
tBTA_GATTS_SERVICE_CHANGE service_change;
tBTA_GATT_STATUS status = BTA_GATT_OK;
UINT16 addr[BD_ADDR_LEN] = {0};
UINT8 addr[BD_ADDR_LEN] = {0};
if(memcmp(p_msg->api_send_service_change.remote_bda, addr, BD_ADDR_LEN) != 0) {
BD_ADDR bd_addr;
memcpy(bd_addr, p_msg->api_send_service_change.remote_bda, BD_ADDR_LEN);
@@ -223,6 +223,7 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_u
UINT16 len = 0;
if(attr_val != NULL){
len = attr_val->attr_len;
APPL_TRACE_DEBUG("attr_val->attr_len = %x, attr_max_len = %x\n",attr_val->attr_len, attr_val->attr_max_len);
}
if ((p_buf = (tBTA_GATTS_API_ADD_CHAR *) osi_malloc(sizeof(tBTA_GATTS_API_ADD_CHAR))) != NULL) {
memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_CHAR));
@@ -234,15 +235,22 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_u
if(control !=NULL){
p_buf->control.auto_rsp = control->auto_rsp;
}
if(attr_val != NULL){
APPL_TRACE_DEBUG("!!!!!!attr_val->attr_len = %x\n",attr_val->attr_len);
APPL_TRACE_DEBUG("!!!!!!!attr_val->attr_max_len = %x\n",attr_val->attr_max_len);
if(attr_val != NULL && len){
p_buf->attr_val.attr_len = attr_val->attr_len;
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, len);
} else {
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
APPL_TRACE_ERROR("Allocate fail for %s\n", __func__);
}
} else {
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
p_buf->attr_val.attr_val = NULL;
}
if (p_char_uuid) {
@@ -499,6 +507,9 @@ void BTA_SetAttributeValue(UINT16 attr_handle, UINT16 length, UINT8 *value)
if(value != NULL){
if((p_buf->value = (UINT8 *)osi_malloc(length)) != NULL){
memcpy(p_buf->value, value, length);
} else {
p_buf->length = 0;
APPL_TRACE_ERROR("Allocate fail for %s\n", __func__);
}
}
@@ -103,6 +103,7 @@ enum {
#define BTA_SYS_ACTIONS 2 /* number of actions */
#define BTA_SYS_NEXT_STATE 2 /* position of next state */
#define BTA_SYS_NUM_COLS 3 /* number of columns in state tables */
#define BTA_SYS_NUM_STATES 4 /* OFF, STARTING, ON, STOPPING */
/* state table for OFF state */
@@ -213,22 +214,39 @@ BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg)
BOOLEAN freebuf = TRUE;
tBTA_SYS_ST_TBL state_table;
UINT8 action;
UINT8 evt_idx;
int i;
if (p_msg == NULL) {
return freebuf;
}
evt_idx = p_msg->event & 0x00ff;
if (evt_idx >= BTA_SYS_NUM_ACTIONS) {
APPL_TRACE_ERROR("bta_sys_sm_execute: event 0x%x out of range (evt_idx=%u)", p_msg->event, evt_idx);
return freebuf;
}
if (bta_sys_cb.state >= BTA_SYS_NUM_STATES) {
APPL_TRACE_ERROR("bta_sys_sm_execute: invalid state %u", bta_sys_cb.state);
return freebuf;
}
APPL_TRACE_EVENT("bta_sys_sm_execute state:%d, event:0x%x\n", bta_sys_cb.state, p_msg->event);
/* look up the state table for the current state */
state_table = bta_sys_st_tbl[bta_sys_cb.state];
/* update state */
bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE];
bta_sys_cb.state = state_table[evt_idx][BTA_SYS_NEXT_STATE];
/* execute action functions */
for (i = 0; i < BTA_SYS_ACTIONS; i++) {
if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE) {
(*bta_sys_action[action])( (tBTA_SYS_HW_MSG *) p_msg);
} else {
action = state_table[evt_idx][i];
if (action == BTA_SYS_IGNORE) {
break;
}
if (action < BTA_SYS_NUM_ACTIONS) {
(*bta_sys_action[action])( (tBTA_SYS_HW_MSG *) p_msg);
}
}
return freebuf;
@@ -598,16 +616,29 @@ void bta_alarm_cb(void *data)
void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms)
{
osi_alarm_t *alarm = NULL;
assert(p_tle != NULL);
// Get the alarm for this p_tle.
osi_mutex_lock(&bta_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
if (!hash_map_has_key(bta_alarm_hash_map, p_tle)) {
hash_map_set(bta_alarm_hash_map, p_tle, osi_alarm_new("bta_sys", bta_alarm_cb, p_tle, 0));
alarm = osi_alarm_new("bta_sys", bta_alarm_cb, p_tle, 0);
if (alarm == NULL) {
APPL_TRACE_ERROR("%s unable to create new alarm.", __func__);
osi_mutex_unlock(&bta_alarm_lock);
return;
}
if (!hash_map_set(bta_alarm_hash_map, p_tle, alarm)) {
APPL_TRACE_ERROR("%s unable to set alarm in map.", __func__);
osi_alarm_free(alarm);
osi_mutex_unlock(&bta_alarm_lock);
return;
}
}
osi_mutex_unlock(&bta_alarm_lock);
osi_alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle);
alarm = hash_map_get(bta_alarm_hash_map, p_tle);
if (alarm == NULL) {
APPL_TRACE_ERROR("%s unable to create alarm.", __func__);
return;