OSDN Git Service

DO NOT MERGE: SDP: Check p_req_end before reading from p_req
authorMyles Watson <mylesgw@google.com>
Fri, 12 Jan 2018 01:43:40 +0000 (17:43 -0800)
committerJP Sugarbroad <jpsugar@google.com>
Tue, 13 Feb 2018 21:57:00 +0000 (13:57 -0800)
Bug: 69384124
Test: Connect a headset
Change-Id: Ia30c58ed39977552e5ddc21cc3c1b54c6b1d8abe
(cherry picked from commit d321b13feaebb6ce83d4c449b3ef500ddbbef716)

stack/sdp/sdp_server.c
stack/sdp/sdp_utils.c

index f97b094..ca98d86 100644 (file)
@@ -127,12 +127,25 @@ void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
     /* Start inactivity timer */
     alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
                        sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+    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)
@@ -197,17 +210,17 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
     }
 
     /* Get the max replies we can send. Cap it at our max anyways. */
+    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;
+    }
     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))
-    {
-        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
-        return;
-    }
 
 
     /* Get a list of handles that match the UUIDs given to us */
@@ -224,8 +237,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);
             return;
@@ -329,15 +342,16 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
     BOOLEAN         is_cont = FALSE;
     UINT16          attr_len;
 
-    /* Extract the record handle */
-    BE_STREAM_TO_UINT32 (rec_handle, p_req);
-
-    if (p_req > p_req_end)
-    {
-        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
+    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);
 
@@ -346,8 +360,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;
     }
@@ -374,7 +388,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
 
     /* Check if this is a continuation request */
     if (*p_req) {
-        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;
@@ -570,8 +585,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;
     }
@@ -584,8 +599,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;
     }
@@ -604,7 +619,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
 
     /* Check if this is a continuation request */
     if (*p_req) {
-        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;
index aa1bfb5..30cdb2c 100644 (file)
@@ -370,6 +370,9 @@ UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq)
 
     /* 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;
     size = descr & 7;
@@ -389,19 +392,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;
@@ -428,12 +437,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:
@@ -441,8 +453,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);
             p_seq->num_uids++;
@@ -483,33 +495,39 @@ 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);
+    if (type != DATA_ELE_SEQ_DESC_TYPE) 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);
+    if (list_len > param_len) return NULL;
 
     p_end_list = p + list_len;
 
@@ -520,8 +538,7 @@ UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq)
         type = descr >> 3;
         size = descr & 7;
 
-        if (type != UINT_DESC_TYPE)
-            return (p);
+        if (type != UINT_DESC_TYPE) return NULL;
 
         switch (size)
         {
@@ -532,20 +549,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);