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

Commit e068fd70 authored by Zach Johnson's avatar Zach Johnson
Browse files

Add command response fuzzing to FuzzHciLayer

Also, add auto-reply mode so it can reply
to clients while they are starting.

Test: fuzz/run --host acl_manager
Change-Id: I3d4a4fd01eb4f5e520a803ad60126e3d81e02dc9
parent 85f5f7cb
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -49,6 +49,16 @@ class ContextualOnceCallback<R(Args...)> {
    context_->Post(common::BindOnce(std::move(callback_), std::forward<Args>(args)...));
  }

  void InvokeIfNotEmpty(Args... args) {
    if (context_ != nullptr) {
      context_->Post(common::BindOnce(std::move(callback_), std::forward<Args>(args)...));
    }
  }

  bool IsEmpty() {
    return context_ == nullptr;
  }

 private:
  common::OnceCallback<R(Args...)> callback_;
  IPostableContext* context_;
@@ -75,6 +85,16 @@ class ContextualCallback<R(Args...)> {
    context_->Post(common::BindOnce(callback_, std::forward<Args>(args)...));
  }

  void InvokeIfNotEmpty(Args... args) {
    if (context_ != nullptr) {
      context_->Post(common::BindOnce(callback_, std::forward<Args>(args)...));
    }
  }

  bool IsEmpty() {
    return context_ == nullptr;
  }

 private:
  common::Callback<R(Args...)> callback_;
  IPostableContext* context_;
+15 −0
Original line number Diff line number Diff line
@@ -30,5 +30,20 @@ std::vector<std::vector<uint8_t>> SplitInput(const uint8_t* data, size_t size, c

std::vector<uint8_t> GetArbitraryBytes(FuzzedDataProvider* fdp);

#define CONSTRUCT_VALID_UNIQUE_OTHERWISE_BAIL(T, name, data) \
  auto name = std::make_unique<T>(T::FromBytes(data));       \
  if (!name->IsValid()) {                                    \
    return;                                                  \
  }

template <typename TView>
void InvokeIfValid(common::ContextualOnceCallback<void(TView)> callback, std::vector<uint8_t> data) {
  auto packet = TView::FromBytes(data);
  if (!packet.IsValid()) {
    return;
  }
  callback.InvokeIfNotEmpty(packet);
}

}  // namespace fuzz
}  // namespace bluetooth
+2 −0
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

  static FuzzTestModuleRegistry moduleRegistry = FuzzTestModuleRegistry();
  FuzzHciLayer* fuzzHci = moduleRegistry.Inject<FuzzHciLayer>(&HciLayer::Factory);
  fuzzHci->TurnOnAutoReply(&dataProvider);
  moduleRegistry.Start<AclManager>();
  fuzzHci->TurnOffAutoReply();

  while (dataProvider.remaining_bytes() > 0) {
    const uint8_t action = dataProvider.ConsumeIntegralInRange(0, 2);
+17 −10
Original line number Diff line number Diff line
@@ -23,10 +23,7 @@ namespace fuzz {

using bluetooth::common::ContextualCallback;
using bluetooth::fuzz::GetArbitraryBytes;

common::BidiQueueEnd<hci::AclPacketBuilder, hci::AclPacketView>* FuzzHciLayer::GetAclQueueEnd() {
  return acl_queue_.GetUpEnd();
}
using bluetooth::fuzz::InvokeIfValid;

hci::SecurityInterface* FuzzHciLayer::GetSecurityInterface(
    ContextualCallback<void(hci::EventPacketView)> event_handler) {
@@ -73,21 +70,31 @@ void FuzzHciLayer::Stop() {
}

void FuzzHciLayer::injectArbitrary(FuzzedDataProvider& fdp) {
  const uint8_t action = fdp.ConsumeIntegralInRange(0, 1);
  const uint8_t action = fdp.ConsumeIntegralInRange(0, 3);
  switch (action) {
    case 1:
      injectAclData(GetArbitraryBytes(&fdp));
      break;
    case 2:
      injectCommandComplete(GetArbitraryBytes(&fdp));
      break;
    case 3:
      injectCommandStatus(GetArbitraryBytes(&fdp));
      break;
  }
}

void FuzzHciLayer::injectAclData(std::vector<uint8_t> data) {
  hci::AclPacketView aclPacket = hci::AclPacketView::FromBytes(data);
  if (!aclPacket.IsValid()) {
    return;
  CONSTRUCT_VALID_UNIQUE_OTHERWISE_BAIL(hci::AclPacketView, packet, data);
  acl_inject_->Inject(std::move(packet));
}

void FuzzHciLayer::injectCommandComplete(std::vector<uint8_t> data) {
  InvokeIfValid<hci::CommandCompleteView>(std::move(on_command_complete), data);
}

  acl_inject_->Inject(std::make_unique<AclPacketView>(aclPacket));
void FuzzHciLayer::injectCommandStatus(std::vector<uint8_t> data) {
  InvokeIfValid<hci::CommandStatusView>(std::move(on_command_status), data);
}

const ModuleFactory FuzzHciLayer::Factory = ModuleFactory([]() { return new FuzzHciLayer(); });
+32 −3
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@
#include "hci/hci_layer.h"
#include "os/fuzz/dev_null_queue.h"
#include "os/fuzz/fuzz_inject_queue.h"
#include "os/log.h"

#include <fuzzer/FuzzedDataProvider.h>
#include "fuzz/helpers.h"

namespace bluetooth {
namespace hci {
@@ -39,13 +41,33 @@ class FuzzCommandInterface : public CommandInterface<T> {

class FuzzHciLayer : public HciLayer {
 public:
  void TurnOnAutoReply(FuzzedDataProvider* fdp) {
    auto_reply_fdp = fdp;
  }

  void TurnOffAutoReply() {
    auto_reply_fdp = nullptr;
  }

  void EnqueueCommand(std::unique_ptr<hci::CommandPacketBuilder> command,
                      common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {}
                      common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) override {
    on_command_complete = std::move(on_complete);
    if (auto_reply_fdp != nullptr) {
      injectCommandComplete(bluetooth::fuzz::GetArbitraryBytes(auto_reply_fdp));
    }
  }

  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
                      common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {}
                      common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) override {
    on_command_status = std::move(on_status);
    if (auto_reply_fdp != nullptr) {
      injectCommandStatus(bluetooth::fuzz::GetArbitraryBytes(auto_reply_fdp));
    }
  }

  common::BidiQueueEnd<hci::AclPacketBuilder, hci::AclPacketView>* GetAclQueueEnd() override;
  common::BidiQueueEnd<hci::AclPacketBuilder, hci::AclPacketView>* GetAclQueueEnd() override {
    return acl_queue_.GetUpEnd();
  }

  void RegisterEventHandler(hci::EventCode event_code,
                            common::ContextualCallback<void(hci::EventPacketView)> event_handler) override {}
@@ -92,6 +114,10 @@ class FuzzHciLayer : public HciLayer {

 private:
  void injectAclData(std::vector<uint8_t> data);
  void injectCommandComplete(std::vector<uint8_t> data);
  void injectCommandStatus(std::vector<uint8_t> data);

  FuzzedDataProvider* auto_reply_fdp;

  common::BidiQueue<hci::AclPacketView, hci::AclPacketBuilder> acl_queue_{3};
  os::fuzz::DevNullQueue<AclPacketBuilder>* acl_dev_null_;
@@ -103,6 +129,9 @@ class FuzzHciLayer : public HciLayer {
  FuzzCommandInterface<LeSecurityCommandBuilder> le_security_interface_{};
  FuzzCommandInterface<LeAdvertisingCommandBuilder> le_advertising_interface_{};
  FuzzCommandInterface<LeScanningCommandBuilder> le_scanning_interface_{};

  common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_command_complete;
  common::ContextualOnceCallback<void(hci::CommandStatusView)> on_command_status;
};

}  // namespace fuzz