Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62d54d07 authored by Zach Johnson's avatar Zach Johnson
Browse files

Start fuzzing HCI events + minor fix in hci_layer

Check event for validity before trying to send it,
to avoid triggering asserts inside HCI layer.

Rudimentary filtering right now since HCI reset is the only
thing that gets sent to the HAL.

Also, remove unhandled event assert, as controllers may send us
unsolicited events that (while unhandled) should not cause us
to crash.

Test: fuzz/run --host bluetooth_gd_hci_fuzz_test
Change-Id: Ic3181c0865b7519b89d2f03caf228c0010256a4a
parent 10e1d496
Loading
Loading
Loading
Loading
+44 −4
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

#include "hal/fuzz/fuzz_hci_hal.h"
#include "fuzz/helpers.h"
#include "hci/hci_packets.h"

namespace bluetooth {
namespace hal {
@@ -30,17 +29,58 @@ void FuzzHciHal::unregisterIncomingPacketCallback() {
  callbacks_ = nullptr;
}

void FuzzHciHal::sendHciCommand(HciPacket packet) {
  auto packetView = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(packet));
  hci::CommandPacketView command = hci::CommandPacketView::Create(packetView);
  if (!command.IsValid()) {
    return;
  }

  waiting_opcode_ = command.GetOpCode();
  // TODO: expand list or find better way to associate opcodes needing status vs complete
  waiting_for_status_ = waiting_opcode_ == hci::OpCode::RESET;
}

bool FuzzHciHal::is_currently_valid_event(packet::PacketView<packet::kLittleEndian> packet) {
  hci::EventPacketView event = hci::EventPacketView::Create(packet);
  if (!event.IsValid()) {
    return false;
  }

  hci::CommandCompleteView complete = hci::CommandCompleteView::Create(event);
  if (complete.IsValid()) {
    if (waiting_for_status_ || complete.GetCommandOpCode() != waiting_opcode_) {
      return false;
    }
  } else if (!waiting_for_status_) {
    return false;
  }

  hci::CommandStatusView status = hci::CommandStatusView::Create(event);
  if (status.IsValid()) {
    if (!waiting_for_status_ || status.GetCommandOpCode() != waiting_opcode_) {
      return false;
    }
  } else if (waiting_for_status_) {
    return false;
  }

  return true;
}

int FuzzHciHal::injectFuzzInput(const uint8_t* data, size_t size) {
  const uint8_t separator[] = {0xDE, 0xAD, 0xBE, 0xEF};
  auto inputs = ::bluetooth::fuzz::SplitInput(data, size, separator, sizeof(separator));
  for (auto const& sdata : inputs) {
    auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(sdata));
    hci::AclPacketView aclPacket = hci::AclPacketView::Create(packet);
    if (!aclPacket.IsValid()) {
      continue;
    if (aclPacket.IsValid()) {
      callbacks_->aclDataReceived(sdata);
    }
    if (is_currently_valid_event(packet)) {
      callbacks_->hciEventReceived(sdata);
    }

    callbacks_->aclDataReceived(sdata);
    sentinel_work_item_.WaitUntilFinishedOn(GetHandler());
  }
  return 0;
+5 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "fuzz/helpers.h"
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"

namespace bluetooth {
namespace hal {
@@ -28,7 +29,7 @@ class FuzzHciHal : public HciHal {
  void registerIncomingPacketCallback(HciHalCallbacks* callbacks) override;
  void unregisterIncomingPacketCallback() override;

  void sendHciCommand(HciPacket command) override {}
  void sendHciCommand(HciPacket command) override;
  void sendAclData(HciPacket packet) override {}
  void sendScoData(HciPacket packet) override {}

@@ -46,6 +47,9 @@ class FuzzHciHal : public HciHal {
 private:
  HciHalCallbacks* callbacks_;
  ::bluetooth::fuzz::SentinelWorkItem sentinel_work_item_;
  bool is_currently_valid_event(packet::PacketView<packet::kLittleEndian> packet);
  hci::OpCode waiting_opcode_;
  bool waiting_for_status_;
};

}  // namespace fuzz
+4 −4
Original line number Diff line number Diff line
@@ -330,13 +330,13 @@ struct HciLayer::impl : public hal::HciHalCallbacks {

  void hci_event_received_handler(EventPacketView event) {
    EventCode event_code = event.GetEventCode();
    ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx (%s)",
               event_code, EventCodeText(event_code).c_str());
    if (event_handlers_.find(event_code) == event_handlers_.end()) {
      LOG_DEBUG("Dropping unregistered event of type 0x%02hhx (%s)", event_code, EventCodeText(event_code).c_str());
      return;
    }
    auto& registered = event_handlers_[event_code];
    if (registered.handler != nullptr) {
      registered.handler->Post(BindOnce(registered.event_handler, event));
    } else {
      LOG_DEBUG("Dropping unregistered event of type 0x%02hhx (%s)", event_code, EventCodeText(event_code).c_str());
    }
  }