diff options
author | Myles Watson <mylesgw@google.com> | 2018-01-11 17:43:40 -0800 |
---|---|---|
committer | Andreas Blaesius <andi@unlegacy-android.org> | 2018-04-14 14:02:06 +0200 |
commit | a490759d3569efe6e94bef306865a4f8e01b3656 (patch) | |
tree | c8f04ee2d54f94c547538eca2f4b3665242b4dda | |
parent | 178c0ff3a46a9a633822414ddeaed6aa0e536ba9 (diff) | |
download | android_system_bt-a490759d3569efe6e94bef306865a4f8e01b3656.tar.gz android_system_bt-a490759d3569efe6e94bef306865a4f8e01b3656.tar.bz2 android_system_bt-a490759d3569efe6e94bef306865a4f8e01b3656.zip |
SDP: Check p_req_end before reading from p_req
Bug: 69384124
Test: Connect a headset
Change-Id: Ia30c58ed39977552e5ddc21cc3c1b54c6b1d8abe
Merged-In: Ia30c58ed39977552e5ddc21cc3c1b54c6b1d8abe
(cherry picked from commit dd856fbc4ade8f7d78873db3533b4c9fd7c6d612)
-rw-r--r-- | stack/sdp/sdp_server.c | 56 | ||||
-rw-r--r-- | stack/sdp/sdp_utils.c | 38 |
2 files changed, 68 insertions, 26 deletions
diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c index c9a214fc0..b7ef7ee99 100644 --- a/stack/sdp/sdp_server.c +++ b/stack/sdp/sdp_server.c @@ -23,7 +23,6 @@ * ******************************************************************************/ #include <cutils/log.h> - #include <stdlib.h> #include <string.h> #include <stdio.h> @@ -360,11 +359,25 @@ void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg) /* Start inactivity timer */ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + if (p_req + sizeof(pdu_id) + sizeof(trans_num) > p_req_end) { + android_errorWriteLog(0x534e4554, "69384124"); + trans_num = 0; + sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, + SDP_TEXT_BAD_HEADER); + } + /* The first byte in the message is the pdu type */ pdu_id = *p_req++; /* Extract the transaction number and parameter length */ BE_STREAM_TO_UINT16 (trans_num, p_req); + + if (p_req + sizeof(param_len) > p_req_end) { + android_errorWriteLog(0x534e4554, "69384124"); + sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, + SDP_TEXT_BAD_HEADER); + } + BE_STREAM_TO_UINT16 (param_len, p_req); if ((p_req + param_len) != p_req_end) @@ -429,19 +442,17 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, return; } - /* Get the max replies we can send. Cap it at our max anyways. */ - BE_STREAM_TO_UINT16 (max_replies, p_req); - - if (max_replies > SDP_MAX_RECORDS) - max_replies = SDP_MAX_RECORDS; - - - if ((!p_req) || (p_req > p_req_end)) + if (p_req + sizeof(max_replies) + sizeof(uint8_t) > p_req_end) { + android_errorWriteLog(0x534e4554, "69384124"); sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); return; } + /* Get the max replies we can send. Cap it at our max anyways. */ + BE_STREAM_TO_UINT16 (max_replies, p_req); + if (max_replies > SDP_MAX_RECORDS) + max_replies = SDP_MAX_RECORDS; /* Get a list of handles that match the UUIDs given to us */ for (num_rsp_handles = 0; num_rsp_handles < max_replies; ) @@ -457,7 +468,8 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, /* Check if this is a continuation request */ if (*p_req) { - if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) + if (*p_req++ != SDP_CONTINUATION_LEN || + (p_req + sizeof(cont_offset) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); @@ -580,15 +592,16 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, BOOLEAN is_hfp_fallback = FALSE; UINT16 attr_len; - /* Extract the record handle */ - BE_STREAM_TO_UINT32 (rec_handle, p_req); - - if (p_req > p_req_end) + if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) { + android_errorWriteLog(0x534e4554, "69384124"); sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE); return; } + /* Extract the record handle */ + BE_STREAM_TO_UINT32 (rec_handle, p_req); + /* Get the max list length we can send. Cap it at MTU size minus overhead */ BE_STREAM_TO_UINT16 (max_list_len, p_req); @@ -597,7 +610,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq); - if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end)) + if ((!p_req) || (!attr_seq.num_attr) || + (p_req + sizeof(uint8_t) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST); return; @@ -634,7 +648,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) + if (*p_req++ != SDP_CONTINUATION_LEN || + (p_req + sizeof(cont_offset) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; @@ -922,7 +937,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, /* Extract the UUID sequence to search for */ p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); - if ((!p_req) || (!uid_seq.num_uids)) + if ((!p_req) || (!uid_seq.num_uids) || + (p_req + sizeof(uint16_t) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST); return; @@ -936,7 +952,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq); - if ((!p_req) || (!attr_seq.num_attr)) + if ((!p_req) || (!attr_seq.num_attr) || + (p_req + sizeof(uint8_t) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST); return; @@ -967,7 +984,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) + if (*p_req++ != SDP_CONTINUATION_LEN || + (p_req + sizeof(uint16_t) > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c index d9b1ea7ef..02af9f971 100644 --- a/stack/sdp/sdp_utils.c +++ b/stack/sdp/sdp_utils.c @@ -382,6 +382,8 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq) p_seq->num_uids = 0; /* A UID sequence is composed of a bunch of UIDs. */ + if (sizeof(descr) > param_len) return (NULL); + param_len -= sizeof(descr); BE_STREAM_TO_UINT8 (descr, p); type = descr >> 3; @@ -402,19 +404,25 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq) seq_len = 16; break; case SIZE_IN_NEXT_BYTE: + if (sizeof(uint8_t) > param_len) return (NULL); + param_len -= sizeof(uint8_t); BE_STREAM_TO_UINT8 (seq_len, p); break; case SIZE_IN_NEXT_WORD: + if (sizeof(uint16_t) > param_len) return (NULL); + param_len -= sizeof(uint16_t); BE_STREAM_TO_UINT16 (seq_len, p); break; case SIZE_IN_NEXT_LONG: + if (sizeof(uint32_t) > param_len) return (NULL); + param_len -= sizeof(uint32_t); BE_STREAM_TO_UINT32 (seq_len, p); break; default: return (NULL); } - if (seq_len >= param_len) + if (seq_len > param_len) return (NULL); p_seq_end = p + seq_len; @@ -441,12 +449,15 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq) uuid_len = 16; break; case SIZE_IN_NEXT_BYTE: + if (p + sizeof(uint8_t) > p_seq_end) return NULL; BE_STREAM_TO_UINT8 (uuid_len, p); break; case SIZE_IN_NEXT_WORD: + if (p + sizeof(uint16_t) > p_seq_end) return NULL; BE_STREAM_TO_UINT16 (uuid_len, p); break; case SIZE_IN_NEXT_LONG: + if (p + sizeof(uint32_t) > p_seq_end) return NULL; BE_STREAM_TO_UINT32 (uuid_len, p); break; default: @@ -454,7 +465,8 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq) } /* If UUID length is valid, copy it across */ - if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) + if (((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) && + (p + uuid_len <= p_seq_end)) { p_seq->uuid_entry[p_seq->num_uids].len = (UINT16) uuid_len; BE_STREAM_TO_ARRAY (p, p_seq->uuid_entry[p_seq->num_uids].value, (int)uuid_len); @@ -496,33 +508,41 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq) p_seq->num_attr = 0; /* Get attribute sequence info */ + if (param_len < sizeof(descr)) return NULL; + param_len -= sizeof(descr); BE_STREAM_TO_UINT8 (descr, p); type = descr >> 3; size = descr & 7; if (type != DATA_ELE_SEQ_DESC_TYPE) - return (p); + return NULL; switch (size) { case SIZE_IN_NEXT_BYTE: + if (param_len < sizeof(uint8_t)) return NULL; + param_len -= sizeof(uint8_t); BE_STREAM_TO_UINT8 (list_len, p); break; case SIZE_IN_NEXT_WORD: + if (param_len < sizeof(uint16_t)) return NULL; + param_len -= sizeof(uint16_t); BE_STREAM_TO_UINT16 (list_len, p); break; case SIZE_IN_NEXT_LONG: + if (param_len < sizeof(uint32_t)) return NULL; + param_len -= sizeof(uint32_t); BE_STREAM_TO_UINT32 (list_len, p); break; default: - return (p); + return NULL; } if (list_len > param_len) - return (p); + return NULL; p_end_list = p + list_len; @@ -534,7 +554,7 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq) size = descr & 7; if (type != UINT_DESC_TYPE) - return (p); + return NULL; switch (size) { @@ -545,20 +565,24 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq) attr_len = 4; break; case SIZE_IN_NEXT_BYTE: + if (p + sizeof(uint8_t) > p_end_list) return NULL; BE_STREAM_TO_UINT8 (attr_len, p); break; case SIZE_IN_NEXT_WORD: + if (p + sizeof(uint16_t) > p_end_list) return NULL; BE_STREAM_TO_UINT16 (attr_len, p); break; case SIZE_IN_NEXT_LONG: + if (p + sizeof(uint32_t) > p_end_list) return NULL; BE_STREAM_TO_UINT32 (attr_len, p); break; default: - return (NULL); + return NULL; break; } /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */ + if (p + attr_len > p_end_list) return NULL; if (attr_len == 2) { BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p); |