DO NOT MERGE  Ensure hci command status event has sufficient packet length

Bug: 141618611
Test: net_test_hci_native

Change-Id: I70a318b05d7781ddf8f82d7922a8ee7afc8d2e9f
(cherry picked from commit 6e25c5d81c4a43c2794a605c9fc8a194f37889af)
diff --git a/hci/Android.bp b/hci/Android.bp
index 5702177..b7f278a 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -77,3 +77,39 @@
         "libbt-protos-lite",
     ],
 }
+
+// HCI native unit tests for target
+// ========================================================
+cc_test {
+    name: "net_test_hci_native",
+    test_suites: ["device-tests"],
+    defaults: ["fluoride_defaults"],
+    host_supported: true,
+    local_include_dirs: [
+        "include",
+    ],
+    include_dirs: [
+        "system/bt",
+        "system/bt/stack/include",
+    ],
+    srcs: [
+        "test/hci_layer_test.cc",
+        "test/other_stack_stub.cc",
+    ],
+    shared_libs: [
+        "libcrypto",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "libbt-common",
+        "libbt-protos-lite",
+        "libosi",
+        "libosi-AllocationTestHarness",
+    ],
+    sanitize: {
+        address: true,
+        cfi: true,
+        misc_undefined: ["bounds"],
+    },
+}
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index 80f63de..2d17b50 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -569,11 +569,12 @@
   waiting_command_t* wait_entry = NULL;
   uint8_t* stream = packet->data;
   uint8_t event_code;
+  uint8_t length;
   int credits = 0;
   command_opcode_t opcode;
 
   STREAM_TO_UINT8(event_code, stream);
-  STREAM_SKIP_UINT8(stream);  // Skip the parameter total length field
+  STREAM_TO_UINT8(length, stream);
 
   if (event_code == HCI_COMMAND_COMPLETE_EVT) {
     STREAM_TO_UINT8(credits, stream);
@@ -601,6 +602,11 @@
 
     goto intercepted;
   } else if (event_code == HCI_COMMAND_STATUS_EVT) {
+    if (length < (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint16_t))) {
+      LOG_WARN(LOG_TAG, "%s Unexpected hci command status event length:%hhd",
+               __func__, length);
+      goto intercepted;
+    }
     uint8_t status;
     STREAM_TO_UINT8(status, stream);
     STREAM_TO_UINT8(credits, stream);
diff --git a/hci/test/hci_layer_test.cc b/hci/test/hci_layer_test.cc
new file mode 100644
index 0000000..6855fea
--- /dev/null
+++ b/hci/test/hci_layer_test.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
+
+#include "common/message_loop_thread.h"
+#include "hci/src/hci_layer.cc"
+#include "hci_internals.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+#include "osi/test/AllocationTestHarness.h"
+#include "osi/test/test_stubs.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+extern void allocation_tracker_uninit(void);
+
+allocator_t buffer_allocator_ = {
+    .alloc = osi_malloc,
+    .free = osi_free,
+};
+
+void monitor_socket(int ctrl_fd, int fd) {
+  LOG(INFO) << __func__ << " UNIMPLEMENTED";
+}
+void hci_initialize() { LOG(INFO) << __func__ << " UNIMPLEMENTED"; }
+void hci_close() { LOG(INFO) << __func__ << " UNIMPLEMENTED"; }
+void hci_transmit(BT_HDR* packet) { LOG(INFO) << __func__ << " UNIMPLEMENTED"; }
+int hci_open_firmware_log_file() { return INVALID_FD; }
+void hci_close_firmware_log_file(int fd) {}
+void hci_log_firmware_debug_packet(int fd, BT_HDR* packet) {}
+const allocator_t* buffer_allocator_get_interface() {
+  return &buffer_allocator_;
+}
+
+/**
+ * Test class to test selected functionality in hci/src/hci_layer.cc
+ */
+class HciLayerTest : public AllocationTestHarness {
+ protected:
+  void SetUp() override {
+    AllocationTestHarness::SetUp();
+    // Disable our allocation tracker to allow ASAN full range
+    allocation_tracker_uninit();
+    commands_pending_response = list_new(NULL);
+    buffer_allocator = &buffer_allocator_;
+  }
+
+  void TearDown() override {
+    list_free(commands_pending_response);
+    AllocationTestHarness::TearDown();
+  }
+
+  BT_HDR* AllocateHciEventPacket(size_t packet_length) const {
+    return AllocatePacket(packet_length, MSG_HC_TO_STACK_HCI_EVT);
+  }
+
+  uint8_t* GetPayloadPointer(BT_HDR* packet) const {
+    return static_cast<uint8_t*>(packet->data);
+  }
+
+ private:
+  BT_HDR* AllocatePacket(size_t packet_length, uint16_t event) const {
+    BT_HDR* packet =
+        static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
+    packet->offset = 0;
+    packet->len = packet_length;
+    packet->layer_specific = 0;
+    packet->event = MSG_HC_TO_STACK_HCI_EVT;
+    return packet;
+  }
+};
+
+TEST_F(HciLayerTest, FilterIncomingEvent) {
+  {
+    BT_HDR* packet = AllocateHciEventPacket(3);
+
+    auto p = GetPayloadPointer(packet);
+    *p++ = HCI_COMMAND_STATUS_EVT;
+    *p++ = 0x0;  // length
+
+    CHECK(filter_incoming_event(packet));
+  }
+
+  {
+    BT_HDR* packet = AllocateHciEventPacket(3);
+
+    auto p = GetPayloadPointer(packet);
+    *p++ = HCI_COMMAND_STATUS_EVT;
+    *p++ = 0x1;  // length
+    *p++ = 0xff;
+
+    CHECK(filter_incoming_event(packet));
+  }
+
+  {
+    BT_HDR* packet = AllocateHciEventPacket(6);
+
+    auto p = GetPayloadPointer(packet);
+    *p++ = HCI_COMMAND_STATUS_EVT;
+    *p++ = 0x04;  // length
+    *p++ = 0x00;  // status
+    *p++ = 0x01;  // credits
+    *p++ = 0x34;  // opcode0
+    *p++ = 0x12;  // opcode1
+
+    CHECK(filter_incoming_event(packet));
+  }
+}
diff --git a/hci/test/other_stack_stub.cc b/hci/test/other_stack_stub.cc
new file mode 100644
index 0000000..4271fc0
--- /dev/null
+++ b/hci/test/other_stack_stub.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Gabeldorsche related legacy-only-stack-side expansion and support code.
+ */
+#include "base/bind.h"
+#include "btcore/include/module.h"  // base::OnceClosure
+#include "hci/include/btsnoop.h"
+#include "hci/include/hci_layer.h"
+
+const btsnoop_t* btsnoop_get_interface() { return nullptr; }
+const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; }
+base::MessageLoop* get_main_message_loop() { return nullptr; }
+
+namespace bluetooth {
+namespace bqr {
+
+void DumpLmpLlMessage(uint8_t length, uint8_t* p_lmp_ll_message_event) {}
+void DumpBtScheduling(unsigned char, unsigned char*) {}
+
+}  // namespace bqr
+
+namespace shim {
+
+bool is_gd_shim_enabled() { return false; }
+bool is_gd_stack_started_up() { return false; }
+void Post(base::OnceClosure task) {}
+const hci_t* hci_layer_get_interface() { return nullptr; }
+
+}  // namespace shim
+}  // namespace bluetooth