OSDN Git Service

Fix OOB in bnep_is_packet_allowed
authorChienyuan <chienyuanhuang@google.com>
Tue, 12 Feb 2019 08:01:00 +0000 (16:01 +0800)
committerChienyuan <chienyuanhuang@google.com>
Tue, 12 Feb 2019 08:06:36 +0000 (16:06 +0800)
Bug: 112050983
Test: PoC
Change-Id: I5d331f46cdba86c8e61de206a2ede1d2b348d7e4

stack/bnep/bnep_api.cc
stack/bnep/bnep_int.h
stack/bnep/bnep_utils.cc

index ce5f8c1..809d0b2 100644 (file)
@@ -344,17 +344,12 @@ tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr,
                      BNEP_MTU_SIZE);
     osi_free(p_buf);
     return (BNEP_MTU_EXCEDED);
-  } else if (p_buf->len < 2) {
-    BNEP_TRACE_ERROR("%s length %d too short, must be at least 2", __func__,
-                     p_buf->len);
-    osi_free(p_buf);
-    return BNEP_IGNORE_CMD;
   }
 
   /* Check if the packet should be filtered out */
   p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
   if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
-                             p_data) != BNEP_SUCCESS) {
+                             p_data, p_buf->len) != BNEP_SUCCESS) {
     /*
     ** If packet is filtered and ext headers are present
     ** drop the data and forward the ext headers
@@ -366,6 +361,11 @@ tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, const RawAddress& p_dest_addr,
       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++;
         p_data += length;
@@ -445,10 +445,6 @@ tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr,
     BNEP_TRACE_ERROR("%s length %d exceeded MTU %d", __func__, len,
                      BNEP_MTU_SIZE);
     return (BNEP_MTU_EXCEDED);
-  } else if (len < 2) {
-    BNEP_TRACE_ERROR("%s length %d too short, must be at least 2", __func__,
-                     len);
-    return BNEP_IGNORE_CMD;
   }
 
   if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
@@ -457,7 +453,7 @@ tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr,
 
   /* 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) {
+                             p_data, len) != BNEP_SUCCESS) {
     /*
     ** If packet is filtered and ext headers are present
     ** drop the data and forward the ext headers
@@ -470,6 +466,10 @@ tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr,
       new_len = 0;
       p = p_data;
       do {
+        if ((new_len + 2) > org_len) {
+          return BNEP_IGNORE_CMD;
+        }
+
         ext = *p_data++;
         length = *p_data++;
         p_data += length;
index 2587147..5bba15d 100644 (file)
@@ -229,7 +229,7 @@ extern void bnep_sec_check_complete(const RawAddress* bd_addr,
 extern tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb,
                                            const RawAddress& p_dest_addr,
                                            uint16_t protocol,
-                                           bool fw_ext_present,
-                                           uint8_t* p_data);
+                                           bool fw_ext_present, uint8_t* p_data,
+                                           uint16_t org_len);
 
 #endif
index 6d6d709..ac74ce0 100644 (file)
@@ -1259,23 +1259,33 @@ void bnep_sec_check_complete(UNUSED_ATTR const RawAddress* bd_addr,
 tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb,
                                     const RawAddress& p_dest_addr,
                                     uint16_t protocol, bool fw_ext_present,
-                                    uint8_t* p_data) {
+                                    uint8_t* p_data, uint16_t org_len) {
   if (p_bcb->rcvd_num_filters) {
     uint16_t i, proto;
 
     /* Findout the actual protocol to check for the filtering */
     proto = protocol;
     if (proto == BNEP_802_1_P_PROTOCOL) {
+      uint16_t new_len = 0;
       if (fw_ext_present) {
         uint8_t 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);
     }