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