diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c index e1ffdf7261..3f4cc2931f 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c @@ -45,9 +45,9 @@ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /********************************************************************************/ #if SDP_CLIENT_ENABLED == TRUE -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); -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 void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); 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, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec, @@ -189,7 +189,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) if (p_ccb->is_attr_search) { p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR; - process_service_search_attr_rsp (p_ccb, NULL); + process_service_search_attr_rsp (p_ccb, NULL, NULL); } else { /* First step is to get a list of the handles from the server. */ /* We are not searching for a specific attribute, so we will */ @@ -213,7 +213,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) *******************************************************************************/ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) { - UINT8 *p, rsp_pdu; + UINT8 *p, *p_end, rsp_pdu; BOOLEAN invalid_pdu = TRUE; #if (SDP_DEBUG_RAW == TRUE) @@ -225,7 +225,12 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) /* Got a reply!! Check what we got back */ p = (UINT8 *)(p_msg + 1) + p_msg->offset; + p_end = p + p_msg->len; + if (p_msg->len < 1) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } BE_STREAM_TO_UINT8 (rsp_pdu, p); p_msg->len--; @@ -233,21 +238,21 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) switch (rsp_pdu) { case SDP_PDU_SERVICE_SEARCH_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) { - process_service_search_rsp (p_ccb, p); + process_service_search_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) { - process_service_attr_rsp (p_ccb, p); + process_service_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_SEARCH_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) { - process_service_search_attr_rsp (p_ccb, p); + process_service_search_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; @@ -269,12 +274,17 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) ** Returns void ** *******************************************************************************/ -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT16 xx; UINT16 total, cur_handles, orig; UINT8 cont_len; + if (p_reply + 8 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_GENERIC_ERROR); + return; + } + /* Skip transaction, and param len */ p_reply += 4; BE_STREAM_TO_UINT16 (total, p_reply); @@ -296,6 +306,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->num_handles = sdp_cb.max_recs_per_search; } + if (p_reply + ((p_ccb->num_handles - orig) * 4) + 1 > p_reply_end) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } + for (xx = orig; xx < p_ccb->num_handles; xx++) { BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply); } @@ -306,6 +321,10 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); return; } + if (p_reply + cont_len > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); + return; + } /* stay in the same state */ sdp_snd_service_search_req(p_ccb, cont_len, p_reply); } else { @@ -313,7 +332,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->disc_state = SDP_DISC_WAIT_ATTR; /* Kick off the first attribute request */ - process_service_attr_rsp (p_ccb, NULL); + process_service_attr_rsp (p_ccb, NULL, NULL); } } @@ -392,7 +411,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset) ** Returns void ** *******************************************************************************/ -static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p_start, *p_param_len; UINT16 param_len, list_byte_count; @@ -411,6 +430,11 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (list_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("list_byte_count:%d\n", list_byte_count); @@ -426,6 +450,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, list_byte_count); #endif + + if (p_reply + list_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -502,8 +532,10 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Was this a continuation request ? */ if (cont_request_needed) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); } @@ -537,7 +569,7 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) ** Returns void ** *******************************************************************************/ -static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p, *p_start, *p_end, *p_param_len; UINT8 type; @@ -557,6 +589,11 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (lists_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("lists_byte_count:%d\n", lists_byte_count); @@ -572,6 +609,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, lists_byte_count); #endif + + if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -643,8 +686,10 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* No continuation for first request */ if (p_reply) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); }