From 1955a18c8da716ac45e5b8cf6f9837fe2dc0ab5d Mon Sep 17 00:00:00 2001 From: Ted Wang Date: Mon, 29 Apr 2019 10:11:04 +0800 Subject: [PATCH] Fix potential OOB read in sdpu_get_len_from_type Add boundary check in sdpu_get_len_from_type to prevent potential OOB read. Bug: 117105007 Test: Manul Merged-In: I3755e13ee0a7e22ffd5f48fca909610a26b09d0a Change-Id: I3755e13ee0a7e22ffd5f48fca909610a26b09d0a (cherry picked from commit 1243f8da338dadfe2a3c281a08297b431402d41c) (cherry picked from commit 4d8e1d63e1a2116c47702d38d858f5a742e8292f) --- stack/sdp/sdp_db.c | 7 ++++++- stack/sdp/sdp_discovery.c | 37 ++++++++++++++++++++++++++++--------- stack/sdp/sdp_utils.c | 18 +++++++++++++++++- stack/sdp/sdpint.h | 2 +- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/stack/sdp/sdp_db.c b/stack/sdp/sdp_db.c index 82e7784a0..b7f489770 100644 --- a/stack/sdp/sdp_db.c +++ b/stack/sdp/sdp_db.c @@ -129,7 +129,12 @@ 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("%s: bad length", __func__); + break; + } type = type >> 3; if (type == UUID_DESC_TYPE) { diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c index 596fbbc2c..a00485387 100644 --- a/stack/sdp/sdp_discovery.c +++ b/stack/sdp/sdp_discovery.c @@ -373,6 +373,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset) unsigned int cpy_len, rem_len; UINT32 list_len; UINT8 *p; + UINT8 *p_end; UINT8 type; #if (SDP_DEBUG_RAW == TRUE) @@ -391,13 +392,19 @@ 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) { cpy_len -= 1; type = *p++; uint8_t* old_p = p; - p = sdpu_get_len_from_type (p, type, &list_len); + p = sdpu_get_len_from_type(p, p_end, type, &list_len); + if (p == NULL || (p + list_len) > p_end) + { + SDP_TRACE_WARNING("%s: bad length", __func__); + return; + } if ((int)cpy_len < (p - old_p)) { SDP_TRACE_WARNING("%s: no bytes left for data", __func__); @@ -752,8 +759,12 @@ static void process_service_search_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply, SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type); 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_TRACE_WARNING("%s: bad length", __func__); + return; + } p_end = &p_ccb->rsp_list[p_ccb->list_len]; if ((p + seq_len) != p_end) @@ -800,9 +811,8 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end) SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type); 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", seq_len); return (NULL); @@ -822,7 +832,12 @@ static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_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("%s: Bad len in attr_rsp %d", __func__, 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", type, attr_len); @@ -912,8 +927,12 @@ static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DI 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("%s: bad length in attr_rsp", __func__); + return NULL; + } attr_len &= SDP_DISC_ATTR_LEN_MASK; attr_type = (type >> 3) & 0x0f; diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c index 7d79306dc..e9df46068 100644 --- a/stack/sdp/sdp_utils.c +++ b/stack/sdp/sdp_utils.c @@ -637,7 +637,8 @@ 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; @@ -661,14 +662,29 @@ 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; diff --git a/stack/sdp/sdpint.h b/stack/sdp/sdpint.h index 05a134d4e..e2abbbc66 100644 --- a/stack/sdp/sdpint.h +++ b/stack/sdp/sdpint.h @@ -284,7 +284,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); -- 2.11.0