From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brian Delwiche <delwiche@google.com>
Date: Tue, 21 Mar 2023 22:35:35 +0000
Subject: [PATCH] Revert "Revert "[RESTRICT AUTOMERGE] Validate buffer length
 in sdpu_build_uuid_seq""

This reverts commit 487a1079078f3717fdc4665c19a45eca5b3ec5e6.

Reason for revert: Reinstate original change for QPR
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a681067af2ea4565543238db3025d749923f63ec)
Merged-In: If0528519a29dc73ff99163098da2a05592ab15d8
Change-Id: If0528519a29dc73ff99163098da2a05592ab15d8
---
 stack/sdp/sdp_discovery.c | 64 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 5 deletions(-)

diff --git a/stack/sdp/sdp_discovery.c b/stack/sdp/sdp_discovery.c
index ec85da47a..d57c47790 100644
--- a/stack/sdp/sdp_discovery.c
+++ b/stack/sdp/sdp_discovery.c
@@ -73,11 +73,18 @@ extern fixed_queue_t *btu_general_alarm_queue;
 ** Returns          Pointer to next byte in the output buffer.
 **
 *******************************************************************************/
-static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_uuid_list)
+static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_uuid_list,
+                                   UINT16 bytes_left)
 {
     UINT16  xx;
     UINT8   *p_len;
 
+    if (bytes_left < 2) {
+      SDP_TRACE_ERROR("SDP: No space for data element header");
+      return (p_out);
+    }
+
+
     /* First thing is the data element header */
     UINT8_TO_BE_STREAM  (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
 
@@ -85,9 +92,19 @@ static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_
     p_len = p_out;
     p_out += 1;
 
+    /* Account for data element header and length */
+    bytes_left -= 2;
+
     /* Now, loop through and put in all the UUID(s) */
     for (xx = 0; xx < num_uuids; xx++, p_uuid_list++)
     {
+        if (p_uuid_list->len + 1 > bytes_left) {
+            SDP_TRACE_ERROR("SDP: Too many UUIDs for internal buffer");
+            break;
+        } else {
+            bytes_left -= (p_uuid_list->len + 1);
+        }
+
         if (p_uuid_list->len == 2)
         {
             UINT8_TO_BE_STREAM  (p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
@@ -130,6 +147,7 @@ static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 *
     UINT8           *p, *p_start, *p_param_len;
     BT_HDR          *p_cmd = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE);
     UINT16          param_len;
+    UINT16          bytes_left = SDP_DATA_BUF_SIZE;
 
     /* Prepare the buffer for sending the packet to L2CAP */
     p_cmd->offset = L2CAP_MIN_OFFSET;
@@ -144,11 +162,29 @@ static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 *
     p_param_len = p;
     p += 2;
 
+    /* Account for header size, max service record count and
+     * continuation state */
+    const UINT16 base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET +
+                                 3u + /* service search request header */
+                                 2u + /* param len */
+                                 3u + ((p_cont) ? cont_len : 0));
+
+    if (base_bytes > bytes_left) {
+        SDP_TRACE_ERROR("SDP: Overran SDP data buffer");
+        osi_free(p_cmd);
+        return;
+    }
+
+    bytes_left -= base_bytes;
+
     /* Build the UID sequence. */
 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
-    p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+    p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx],
+		             bytes_left);
 #else
-    p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+    /* Build the UID sequence. */
+    p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters,
+		             bytes_left);
 #endif
 
     /* Set max service record count */
@@ -686,6 +722,7 @@ static void process_service_search_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
     {
         BT_HDR  *p_msg = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
         UINT8   *p;
+        UINT16  bytes_left = SDP_DATA_BUF_SIZE;
 
         p_msg->offset = L2CAP_MIN_OFFSET;
         p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
@@ -699,11 +736,28 @@ static void process_service_search_attr_rsp (tCONN_CB* p_ccb, uint8_t* p_reply,
         p_param_len = p;
         p += 2;
 
+        /* Account for header size, max service record count and
+         * continuation state */
+        const UINT16 base_bytes = (sizeof(BT_HDR) + L2CAP_MIN_OFFSET +
+                                     3u + /* service search request header */
+                                     2u + /* param len */
+                                     3u + /* max service record count */
+                                     ((p_reply) ? (*p_reply) : 0));
+
+        if (base_bytes > bytes_left) {
+            sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
+            return;
+        }
+
+        bytes_left -= base_bytes;
+
         /* Build the UID sequence. */
 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
-        p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+        p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx],
+                                 bytes_left);
 #else
-        p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+        p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters,
+                                 bytes_left);
 #endif
 
         /* Max attribute byte count */
