OSDN Git Service

BNEP: Fix OOB access in bnep_data_ind
[android-x86/system-bt.git] / stack / bnep / bnep_main.cc
index 19d8078..ae6c51b 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2001-2012 Broadcom Corporation
+ *  Copyright 2001-2012 Broadcom Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -46,8 +46,6 @@
 #include "device/include/controller.h"
 #include "osi/include/osi.h"
 
-extern fixed_queue_t* btu_general_alarm_queue;
-
 /******************************************************************************/
 /*                     G L O B A L    B N E P       D A T A                   */
 /******************************************************************************/
@@ -58,8 +56,8 @@ const uint16_t bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8};
 /******************************************************************************/
 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
 /******************************************************************************/
-static void bnep_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
-                             uint8_t l2cap_id);
+static void bnep_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid,
+                             uint16_t psm, uint8_t l2cap_id);
 static void bnep_connect_cfm(uint16_t l2cap_cid, uint16_t result);
 static void bnep_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
 static void bnep_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
@@ -115,7 +113,7 @@ tBNEP_RESULT bnep_register_with_l2cap(void) {
  * Returns          void
  *
  ******************************************************************************/
-static void bnep_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+static void bnep_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid,
                              UNUSED_ATTR uint16_t psm, uint8_t l2cap_id) {
   tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(bd_addr);
 
@@ -140,8 +138,8 @@ static void bnep_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
   L2CA_ConfigReq(l2cap_cid, &bnep_cb.l2cap_my_cfg);
 
   /* Start timer waiting for config setup */
-  alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
-                     bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+  alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                     bnep_conn_timer_timeout, p_bcb);
 
   BNEP_TRACE_EVENT("BNEP - Rcvd L2CAP conn ind, CID: 0x%x", p_bcb->l2cap_cid);
 }
@@ -177,8 +175,8 @@ static void bnep_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
     L2CA_ConfigReq(l2cap_cid, &bnep_cb.l2cap_my_cfg);
 
     /* Start timer waiting for config results */
-    alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
-                       bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+    alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                       bnep_conn_timer_timeout, p_bcb);
 
     BNEP_TRACE_EVENT("BNEP - got conn cnf, sent cfg req, CID: 0x%x",
                      p_bcb->l2cap_cid);
@@ -253,13 +251,13 @@ static void bnep_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
     p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
 
     /* Start timer waiting for setup or response */
-    alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
-                       bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+    alarm_set_on_mloop(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+                       bnep_conn_timer_timeout, p_bcb);
 
     if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
-      btm_sec_mx_access_request(
-          p_bcb->rem_bda, BT_PSM_BNEP, true, BTM_SEC_PROTO_BNEP,
-          bnep_get_uuid32(&(p_bcb->src_uuid)), &bnep_sec_check_complete, p_bcb);
+      btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
+                                BTM_SEC_PROTO_BNEP, p_bcb->src_uuid.As32Bit(),
+                                &bnep_sec_check_complete, p_bcb);
     }
   }
 }
@@ -296,14 +294,12 @@ static void bnep_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
       p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
 
       /* Start timer waiting for setup or response */
-      alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
-                         bnep_conn_timer_timeout, p_bcb,
-                         btu_general_alarm_queue);
+      alarm_set_on_mloop(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+                         bnep_conn_timer_timeout, p_bcb);
 
       if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
         btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
-                                  BTM_SEC_PROTO_BNEP,
-                                  bnep_get_uuid32(&(p_bcb->src_uuid)),
+                                  BTM_SEC_PROTO_BNEP, p_bcb->src_uuid.As32Bit(),
                                   &bnep_sec_check_complete, p_bcb);
       }
     }
@@ -434,10 +430,14 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
   tBNEP_CONN* p_bcb;
   uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
   uint16_t rem_len = p_buf->len;
+  if (rem_len == 0) {
+    android_errorWriteLog(0x534e4554, "78286118");
+    osi_free(p_buf);
+    return;
+  }
   uint8_t type, ctrl_type, ext_type = 0;
   bool extension_present, fw_ext_present;
   uint16_t protocol = 0;
-  uint8_t *p_src_addr, *p_dst_addr;
 
   /* Find CCB based on CID */
   p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
@@ -483,24 +483,35 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
       uint16_t org_len, new_len;
       /* parse the extension headers and process unknown control headers */
       org_len = rem_len;
-      new_len = 0;
       do {
-        if (org_len < 2) break;
+        if (org_len < 2) {
+          android_errorWriteLog(0x534e4554, "67863755");
+          break;
+        }
         ext = *p++;
         length = *p++;
-        p += length;
 
         new_len = (length + 2);
-        if (new_len > org_len) break;
+        if (new_len > org_len) {
+          android_errorWriteLog(0x534e4554, "67863755");
+          break;
+        }
 
-        if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
-          bnep_send_command_not_understood(p_bcb, *p);
+        if ((ext & 0x7F) == BNEP_EXTENSION_FILTER_CONTROL) {
+          if (length == 0) {
+            android_errorWriteLog(0x534e4554, "79164722");
+            break;
+          }
+          if (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG) {
+            bnep_send_command_not_understood(p_bcb, *p);
+          }
+        }
+
+        p += length;
 
         org_len -= new_len;
       } while (ext & 0x80);
-      android_errorWriteLog(0x534e4554, "67863755");
     }
-
     osi_free(p_buf);
     return;
   }
@@ -515,13 +526,14 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
                    p_buf->len, extension_present);
 
   /* Initialize addresses to 'not supplied' */
+  const RawAddress *p_src_addr, *p_dst_addr;
   p_src_addr = p_dst_addr = NULL;
 
   switch (type) {
     case BNEP_FRAME_GENERAL_ETHERNET:
-      p_dst_addr = p;
+      p_dst_addr = (RawAddress*)p;
       p += BD_ADDR_LEN;
-      p_src_addr = p;
+      p_src_addr = (RawAddress*)p;
       p += BD_ADDR_LEN;
       BE_STREAM_TO_UINT16(protocol, p);
       rem_len -= 14;
@@ -543,13 +555,13 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
         while (extension_present && p && rem_len) {
           ext_type = *p++;
           rem_len--;
-          android_errorWriteLog(0x534e4554, "69271284");
           extension_present = ext_type >> 7;
           ext_type &= 0x7F;
 
           /* if unknown extension present stop processing */
-          if (ext_type) break;
+          if (ext_type != BNEP_EXTENSION_FILTER_CONTROL) break;
 
+          android_errorWriteLog(0x534e4554, "69271284");
           p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
         }
       }
@@ -562,14 +574,14 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
       break;
 
     case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
-      p_src_addr = p;
+      p_src_addr = (RawAddress*)p;
       p += BD_ADDR_LEN;
       BE_STREAM_TO_UINT16(protocol, p);
       rem_len -= 8;
       break;
 
     case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
-      p_dst_addr = p;
+      p_dst_addr = (RawAddress*)p;
       p += BD_ADDR_LEN;
       BE_STREAM_TO_UINT16(protocol, p);
       rem_len -= 8;
@@ -597,10 +609,9 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
   p_buf->len = rem_len;
 
   /* Always give the upper layer MAC addresses */
-  if (!p_src_addr) p_src_addr = (uint8_t*)p_bcb->rem_bda;
+  if (!p_src_addr) p_src_addr = &p_bcb->rem_bda;
 
-  if (!p_dst_addr)
-    p_dst_addr = (uint8_t*)controller_get_interface()->get_address();
+  if (!p_dst_addr) p_dst_addr = controller_get_interface()->get_address();
 
   /* check whether there are any extensions to be forwarded */
   if (ext_type)
@@ -609,12 +620,11 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
     fw_ext_present = false;
 
   if (bnep_cb.p_data_buf_cb) {
-    (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol,
+    (*bnep_cb.p_data_buf_cb)(p_bcb->handle, *p_src_addr, *p_dst_addr, protocol,
                              p_buf, fw_ext_present);
-    osi_free(p_buf);
   } else if (bnep_cb.p_data_ind_cb) {
-    (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p,
-                             rem_len, fw_ext_present);
+    (*bnep_cb.p_data_ind_cb)(p_bcb->handle, *p_src_addr, *p_dst_addr, protocol,
+                             p, rem_len, fw_ext_present);
     osi_free(p_buf);
   }
 }
@@ -651,9 +661,8 @@ void bnep_conn_timer_timeout(void* data) {
 
     if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
       bnep_send_conn_req(p_bcb);
-      alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
-                         bnep_conn_timer_timeout, p_bcb,
-                         btu_general_alarm_queue);
+      alarm_set_on_mloop(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                         bnep_conn_timer_timeout, p_bcb);
     } else {
       L2CA_DisconnectReq(p_bcb->l2cap_cid);
 
@@ -679,9 +688,8 @@ void bnep_conn_timer_timeout(void* data) {
   } else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND) {
     if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
       bnepu_send_peer_our_filters(p_bcb);
-      alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
-                         bnep_conn_timer_timeout, p_bcb,
-                         btu_general_alarm_queue);
+      alarm_set_on_mloop(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                         bnep_conn_timer_timeout, p_bcb);
     } else {
       L2CA_DisconnectReq(p_bcb->l2cap_cid);
 
@@ -696,9 +704,8 @@ void bnep_conn_timer_timeout(void* data) {
   } else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND) {
     if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
       bnepu_send_peer_our_multi_filters(p_bcb);
-      alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
-                         bnep_conn_timer_timeout, p_bcb,
-                         btu_general_alarm_queue);
+      alarm_set_on_mloop(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                         bnep_conn_timer_timeout, p_bcb);
     } else {
       L2CA_DisconnectReq(p_bcb->l2cap_cid);