From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chienyuan <chienyuanhuang@google.com>
Date: Tue, 12 Feb 2019 16:01:00 +0800
Subject: [PATCH] Fix OOB in bnep_is_packet_allowed

Bug: 112050983
Test: PoC
Change-Id: I5d331f46cdba86c8e61de206a2ede1d2b348d7e4
(cherry picked from commit 230f252b8a1a1073ec1a4081545b2ff62393d16d)
CRs-Fixed: 3155069
---
 stack/bnep/bnep_api.c   | 15 +++++++++++++--
 stack/bnep/bnep_int.h   |  2 +-
 stack/bnep/bnep_utils.c | 13 ++++++++++++-
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/stack/bnep/bnep_api.c b/stack/bnep/bnep_api.c
index dc349299a..e1c9f2e3d 100644
--- a/stack/bnep/bnep_api.c
+++ b/stack/bnep/bnep_api.c
@@ -387,7 +387,8 @@ tBNEP_RESULT BNEP_WriteBuf (UINT16 handle,
 
     /* Check if the packet should be filtered out */
     p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
-    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present,
+                                p_data, p_buf->len) != BNEP_SUCCESS)
     {
         /*
         ** If packet is filtered and ext headers are present
@@ -401,6 +402,11 @@ tBNEP_RESULT BNEP_WriteBuf (UINT16 handle,
             org_len = p_buf->len;
             new_len = 0;
             do {
+                if ((new_len + 2) > org_len)
+                {
+                  osi_free(p_buf);
+                  return BNEP_IGNORE_CMD;
+                }
 
                 ext     = *p_data++;
                 length  = *p_data++;
@@ -505,7 +511,8 @@ tBNEP_RESULT  BNEP_Write (UINT16 handle,
     p_bcb = &(bnep_cb.bcb[handle - 1]);
 
     /* Check if the packet should be filtered out */
-    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present,
+                                p_data, len) != BNEP_SUCCESS)
     {
         /*
         ** If packet is filtered and ext headers are present
@@ -520,6 +527,10 @@ tBNEP_RESULT  BNEP_Write (UINT16 handle,
             new_len = 0;
             p       = p_data;
             do {
+                if ((new_len + 2) > org_len)
+                {
+                  return BNEP_IGNORE_CMD;
+                }
 
                 ext     = *p_data++;
                 length  = *p_data++;
diff --git a/stack/bnep/bnep_int.h b/stack/bnep/bnep_int.h
index 126be04fe..b10098122 100644
--- a/stack/bnep/bnep_int.h
+++ b/stack/bnep/bnep_int.h
@@ -236,7 +236,7 @@ extern UINT8       *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UI
 extern void        bnep_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
                                                     void *p_ref_data, UINT8 result);
 extern tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, BD_ADDR p_dest_addr, UINT16 protocol,
-                                                    BOOLEAN fw_ext_present, UINT8 *p_data);
+                                            BOOLEAN fw_ext_present, UINT8 *p_data, UINT16 org_len);
 extern UINT32      bnep_get_uuid32 (tBT_UUID *src_uuid);
 
 
diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c
index 65acd33f6..09f2d13c2 100644
--- a/stack/bnep/bnep_utils.c
+++ b/stack/bnep/bnep_utils.c
@@ -1336,7 +1336,7 @@ tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb,
                                      BD_ADDR p_dest_addr,
                                      UINT16 protocol,
                                      BOOLEAN fw_ext_present,
-                                     UINT8 *p_data)
+                                     UINT8 *p_data, UINT16 org_len)
 {
     if (p_bcb->rcvd_num_filters)
     {
@@ -1346,18 +1346,29 @@ tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb,
         proto = protocol;
         if (proto == BNEP_802_1_P_PROTOCOL)
         {
+            UINT16 new_len = 0;
             if (fw_ext_present)
             {
                 UINT8       len, ext;
                 /* parse the extension headers and findout actual protocol */
                 do {
+                    if ((new_len + 2) > org_len)
+                    {
+                      return BNEP_IGNORE_CMD;
+                    }
 
                     ext     = *p_data++;
                     len     = *p_data++;
                     p_data += len;
 
+                    new_len += (len + 2);
+
                 } while (ext & 0x80);
             }
+            if ((new_len + 4) > org_len)
+            {
+              return BNEP_IGNORE_CMD;
+            }
             p_data += 2;
             BE_STREAM_TO_UINT16 (proto, p_data);
         }
