From 179e1ee138a8811deffd49eae77f85246e5092a9 Mon Sep 17 00:00:00 2001 From: Chris Manton Date: Tue, 3 Mar 2020 10:33:42 -0800 Subject: [PATCH] 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) --- hci/Android.bp | 36 +++++++++++++ hci/src/hci_layer.cc | 8 ++- hci/test/hci_layer_test.cc | 124 +++++++++++++++++++++++++++++++++++++++++++ hci/test/other_stack_stub.cc | 45 ++++++++++++++++ 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 hci/test/hci_layer_test.cc create mode 100644 hci/test/other_stack_stub.cc diff --git a/hci/Android.bp b/hci/Android.bp index 57021770c..b7f278afe 100644 --- a/hci/Android.bp +++ b/hci/Android.bp @@ -77,3 +77,39 @@ cc_test { "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 80f63deee..2d17b5041 100644 --- a/hci/src/hci_layer.cc +++ b/hci/src/hci_layer.cc @@ -569,11 +569,12 @@ static bool filter_incoming_event(BT_HDR* packet) { 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 @@ static bool filter_incoming_event(BT_HDR* packet) { 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 000000000..6855feab0 --- /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 +#include +#include + +#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(packet->data); + } + + private: + BT_HDR* AllocatePacket(size_t packet_length, uint16_t event) const { + BT_HDR* packet = + static_cast(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 000000000..4271fc0b2 --- /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 -- 2.11.0