fix(bt/bluedroid): fixed potential OOB in Bluedroid

This commit is contained in:
JinCheng
2025-09-26 17:28:55 +08:00
parent da21126583
commit 999710fccf
14 changed files with 279 additions and 68 deletions
@@ -276,7 +276,7 @@ extern void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UIN
extern UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq);
extern UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq);
extern UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len);
extern UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 *p_end, UINT8 type, UINT32 *p_len);
extern BOOLEAN sdpu_is_base_uuid (UINT8 *p_uuid);
extern BOOLEAN sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2);
extern BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2);
@@ -139,7 +139,11 @@ static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_uuid,
while (p < p_end) {
type = *p++;
p = sdpu_get_len_from_type (p, type, &len);
p = sdpu_get_len_from_type (p, p_end, type, &len);
if ((p == NULL) || (p + len) > p_end) {
SDP_TRACE_WARNING("bad length\n");
return (FALSE);
}
type = type >> 3;
if (type == UUID_DESC_TYPE) {
if (sdpu_compare_uuid_arrays (p, len, p_uuid, uuid_len)) {
@@ -50,7 +50,7 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end);
static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level);
/* Safety check in case we go crazy */
@@ -333,6 +333,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
unsigned int cpy_len;
UINT32 list_len;
UINT8 *p;
UINT8 *p_end;
UINT8 type;
#if (SDP_DEBUG_RAW == TRUE)
@@ -349,10 +350,22 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
list_len = p_ccb->list_len;
p = &p_ccb->rsp_list[0];
p_end = &p_ccb->rsp_list[0] + list_len;
if (offset) {
type = *p++;
p = sdpu_get_len_from_type (p, type, &list_len);
cpy_len--;
uint8_t *p_old = p;
p = sdpu_get_len_from_type (p, p_end, type, &list_len);
if ((p == NULL) || (p + list_len) > p_end) {
SDP_TRACE_WARNING("bad length\n");
return;
}
if ((int)cpy_len < (p - p_old)) {
SDP_TRACE_WARNING("no bytes left for data\n");
return;
}
cpy_len -= (p - p_old);
}
if (list_len < cpy_len ) {
cpy_len = list_len;
@@ -672,7 +685,11 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
sdp_disconnect (p_ccb, SDP_ILLEGAL_PARAMETER);
return;
}
p = sdpu_get_len_from_type (p, type, &seq_len);
p = sdpu_get_len_from_type (p, p + p_ccb->list_len, type, &seq_len);
if (p == NULL || (p + seq_len) > (p + p_ccb->list_len)) {
sdp_disconnect(p_ccb, SDP_ILLEGAL_PARAMETER);
return;
}
p_end = &p_ccb->rsp_list[p_ccb->list_len];
@@ -717,8 +734,8 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
return (NULL);
}
p = sdpu_get_len_from_type (p, type, &seq_len);
if ((p + seq_len) > p_msg_end) {
p = sdpu_get_len_from_type (p, p_msg_end, type, &seq_len);
if ((p == NULL) || (p + seq_len) > p_msg_end) {
SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d\n", seq_len);
return (NULL);
}
@@ -735,7 +752,11 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
while (p < p_seq_end) {
/* First get the attribute ID */
type = *p++;
p = sdpu_get_len_from_type (p, type, &attr_len);
p = sdpu_get_len_from_type (p, p_msg_end, type, &attr_len);
if ((p == NULL) || (p + attr_len) > p_seq_end) {
SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d\n", attr_len);
return (NULL);
}
if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) {
SDP_TRACE_WARNING ("SDP - Bad type: 0x%02x or len: %d in attr_rsp\n", type, attr_len);
return (NULL);
@@ -743,7 +764,7 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
BE_STREAM_TO_UINT16 (attr_id, p);
/* Now, add the attribute value */
p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
p = add_attr (p, p_seq_end, p_ccb->p_db, p_rec, attr_id, NULL, 0);
if (!p) {
SDP_TRACE_WARNING ("SDP - DB full add_attr\n");
@@ -809,7 +830,7 @@ tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
** Returns pointer to next byte in data stream
**
*******************************************************************************/
static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level)
{
tSDP_DISC_ATTR *p_attr;
@@ -818,14 +839,19 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
UINT16 attr_type;
UINT16 id;
UINT8 type;
UINT8 *p_end;
UINT8 *p_attr_end;
UINT8 is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
type = *p++;
p = sdpu_get_len_from_type (p, type, &attr_len);
p = sdpu_get_len_from_type (p, p_end, type, &attr_len);
if ((p == NULL) || (p + attr_len > p_end)) {
SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d\n", attr_len);
return NULL;
}
p_attr_end = p + attr_len;
attr_len &= SDP_DISC_ATTR_LEN_MASK;
attr_type = (type >> 3) & 0x0f;
@@ -860,17 +886,16 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
/* Reserve the memory for the attribute now, as we need to add sub-attributes */
p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
p_db->mem_free -= sizeof (tSDP_DISC_ATTR);
p_end = p + attr_len;
total_len = 0;
/* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
if (nest_level >= MAX_NEST_LEVELS) {
SDP_TRACE_ERROR ("SDP - attr nesting too deep\n");
return (p_end);
return (p_attr_end);
}
/* Now, add the list entry */
p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
p = add_attr (p, p_end, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
break;
}
@@ -943,22 +968,21 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
/* Reserve the memory for the attribute now, as we need to add sub-attributes */
p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
p_db->mem_free -= sizeof (tSDP_DISC_ATTR);
p_end = p + attr_len;
total_len = 0;
/* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */
if (nest_level >= MAX_NEST_LEVELS) {
SDP_TRACE_ERROR ("SDP - attr nesting too deep\n");
return (p_end);
return (p_attr_end);
}
if (is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) {
nest_level |= SDP_ADDITIONAL_LIST_MASK;
}
/* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
while (p < p_end) {
while (p < p_attr_end) {
/* Now, add the list entry */
p = add_attr (p, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
p = add_attr (p, p_end, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
if (!p) {
return (NULL);
@@ -978,7 +1002,7 @@ static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
break;
default:
SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d\n", attr_len);
return (p + attr_len);
return (p_attr_end);
}
break;
@@ -355,6 +355,7 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
/* Free and reallocate buffer */
if (p_ccb->rsp_list) {
osi_free(p_ccb->rsp_list);
p_ccb->rsp_list = NULL;
}
p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
@@ -457,7 +458,7 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
}
}
}
/* If all the attributes have been accomodated in p_rsp,
/* If all the attributes have been accommodated in p_rsp,
reset next_attr_index */
if (xx == attr_seq.num_attr) {
p_ccb->cont_info.next_attr_index = 0;
@@ -590,6 +591,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
/* Free and reallocate buffer */
if (p_ccb->rsp_list) {
osi_free (p_ccb->rsp_list);
p_ccb->rsp_list = NULL;
}
p_ccb->rsp_list = (UINT8 *)osi_malloc (max_list_len);
@@ -623,6 +625,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
/* Free and reallocate if the earlier allocated buffer is small */
if (p_ccb->rsp_list) {
osi_free (p_ccb->rsp_list);
p_ccb->rsp_list = NULL;
}
p_ccb->rsp_list = (UINT8 *)osi_malloc (max_list_len);
@@ -575,7 +575,7 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
** Returns void
**
*******************************************************************************/
UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len)
UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 *p_end, UINT8 type, UINT32 *p_len)
{
UINT8 u8;
UINT16 u16;
@@ -598,14 +598,26 @@ UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len)
*p_len = 16;
break;
case SIZE_IN_NEXT_BYTE:
if (p + 1 > p_end) {
*p_len = 0;
return NULL;
}
BE_STREAM_TO_UINT8 (u8, p);
*p_len = u8;
break;
case SIZE_IN_NEXT_WORD:
if (p + 2 > p_end) {
*p_len = 0;
return NULL;
}
BE_STREAM_TO_UINT16 (u16, p);
*p_len = u16;
break;
case SIZE_IN_NEXT_LONG:
if (p + 4 > p_end) {
*p_len = 0;
return NULL;
}
BE_STREAM_TO_UINT32 (u32, p);
*p_len = (UINT16) u32;
break;
@@ -753,7 +765,7 @@ BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2)
**
** NOTE - it is assumed that BT UUID structures are compressed to the
** smallest possible UUIDs (by removing the base SDP UUID).
** - it is also assumed that the discovery atribute is compressed
** - it is also assumed that the discovery attribute is compressed
** to the smallest possible
**
** Returns TRUE if matched, else FALSE
@@ -768,21 +780,13 @@ BOOLEAN sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr)
return (FALSE);
}
if (p_btuuid->len == 2) {
if (p_btuuid->len == LEN_UUID_16) {
return (BOOLEAN)(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16);
} else if (p_btuuid->len == 4) {
} else if (p_btuuid->len == LEN_UUID_32) {
return (BOOLEAN)(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32);
}
/* coverity[overrun-buffer-arg] */
/*
Event overrun-buffer-arg: Overrun of static array "&p_attr->attr_value.v.array" of size 4 bytes by passing it to a function which indexes it with argument "16U" at byte position 15
FALSE-POSITIVE error from Coverity test tool. Please do NOT remove following comment.
False-positive: SDP uses scratch buffer to hold the attribute value.
The actual size of tSDP_DISC_ATVAL does not matter.
If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
*/
else if (!memcmp (p_btuuid->uu.uuid128, (void *) p_attr->attr_value.v.array, MAX_UUID_SIZE)) {
return (TRUE);
else if (p_btuuid->len == LEN_UUID_128) {
return (BOOLEAN)(!memcmp(p_btuuid->uu.uuid128, (void *) p_attr->attr_value.v.array, LEN_UUID_128));
}
return (FALSE);