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

Commit f65a661e authored by Liz Prucka's avatar Liz Prucka Committed by Automerger Merge Worker
Browse files

Merge "Adding RFCOMM Bluetooth fuzzer" into main am: 55628441 am: a3671725

parents 66a58e6f a3671725
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -426,6 +426,64 @@ cc_fuzz {
    ],
}

cc_fuzz {
    name: "rfcomm-fuzzer",
    team: "trendy_team_attack_tools",
    defaults: [
        "btstack_fuzzer_default",
        "fluoride_defaults",
    ],
    include_dirs: [
        "external/flatbuffers/include",
        "external/rust/crates/quiche/deps/boringssl/src/include",
        "packages/modules/Bluetooth/system/stack/btm",
        "packages/modules/Bluetooth/system/stack/test/common",
        "packages/modules/Bluetooth/system/stack/test/rfcomm",
    ],
    generated_headers: [
        "BluetoothGeneratedDumpsysDataSchema_h",
    ],
    srcs: [
        ":BluetoothPacketSources",
        ":TestCommonMockFunctions",
        ":TestCommonStackConfig",
        ":TestFakeOsi",
        ":TestMockBtif",
        ":TestMockDevice",
        ":TestMockGdOsLoggingLogRedaction",
        ":TestMockMainShim",
        ":TestMockMainShimEntry",
        ":TestMockRustFfi",
        ":TestMockSrvcDis",
        ":TestMockStackAcl",
        ":TestMockStackArbiter",
        ":TestMockStackBtm",
        ":TestMockStackHcic",
        ":TestMockStackL2cap",
        ":TestMockStackMetrics",
        ":TestMockStackSdp",
        "fuzzers/rfcomm_fuzzer.cc",
        "rfcomm/*.cc",
        "test/common/stack_test_packet_utils.cc",
        "test/rfcomm/stack_rfcomm_test_utils.cc",
    ],
    shared_libs: [
        "server_configurable_flags",
    ],
    static_libs: [
        "bluetooth_flags_c_lib",
        "libbluetooth-types",
        "libbluetooth_crypto_toolbox",
        "libbluetooth_hci_pdl",
        "libbluetooth_l2cap_pdl",
        "libbluetooth_log",
        "libbluetooth_smp_pdl",
        "libbt-platform-protos-lite",
        "libbt_shim_bridge",
        "libbt_shim_ffi",
    ],
}

cc_fuzz {
    name: "gatt-fuzzer",
    defaults: [
+221 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 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/location.h>
#include <bluetooth/log.h>
#include <fuzzer/FuzzedDataProvider.h>

#include <cstdint>
#include <iostream>
#include <string>

#include "common/time_util.h"
#include "hal/snoop_logger.h"
#include "osi/include/allocator.h"
#include "stack/include/port_api.h"
#include "stack/include/rfcdefs.h"
#include "stack/test/common/stack_test_packet_utils.h"
#include "test/fake/fake_osi.h"
#include "test/mock/mock_btif_config.h"
#include "test/mock/mock_main_shim_entry.h"
#include "test/mock/mock_stack_acl.h"
#include "test/mock/mock_stack_btm_dev.h"
#include "test/mock/mock_stack_l2cap_api.h"
#include "test/mock/mock_stack_l2cap_ble.h"
#include "test/rfcomm/stack_rfcomm_test_utils.h"

namespace bluetooth {
namespace hal {
class SnoopLogger;

void SnoopLogger::AcceptlistRfcommDlci(uint16_t, uint16_t, uint8_t) {}
void SnoopLogger::SetRfcommPortOpen(uint16_t, uint16_t, uint8_t, uint16_t,
                                    bool) {}
void SnoopLogger::SetRfcommPortClose(uint16_t, uint16_t, uint8_t, uint16_t) {}
}  // namespace hal

namespace common {
uint64_t time_get_os_boottime_ms() { return 0; }
}  // namespace common
}  // namespace bluetooth

namespace {

tL2CAP_APPL_INFO appl_info;
bluetooth::rfcomm::MockRfcommCallback* rfcomm_callback = nullptr;
tBTM_SEC_CALLBACK* security_callback = nullptr;

constexpr uint8_t kDummyId = 0x77;
constexpr uint8_t kDummyRemoteAddr[] = {0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC};
constexpr uint16_t kDummyCID = 0x1234;
constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};

void port_mgmt_cback(const tPORT_RESULT code, uint16_t port_handle) {
  rfcomm_callback->PortManagementCallback(code, port_handle, 0);
}
void port_event_cback(uint32_t code, uint16_t port_handle) {
  rfcomm_callback->PortEventCallback(code, port_handle, 0);
}

class FakeBtStack {
 public:
  FakeBtStack() {
    test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t lcid,
                                                          BT_HDR* hdr) {
      osi_free(hdr);
      return tL2CAP_DW_RESULT::SUCCESS;
    };
    test::mock::stack_l2cap_api::L2CA_ConnectReq.body =
        [](uint16_t psm, const RawAddress& raw_address) { return kDummyCID; };

    test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t) {
      return true;
    };
    test::mock::stack_l2cap_api::L2CA_Register.body =
        [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
           tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
           uint16_t required_remote_mtu, uint16_t sec_level) {
          appl_info = p_cb_info;
          return psm;
        };
  }

  ~FakeBtStack() {
    test::mock::stack_l2cap_api::L2CA_DataWrite = {};
    test::mock::stack_l2cap_api::L2CA_ConnectReq = {};
    test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
    test::mock::stack_l2cap_api::L2CA_Register = {};
  }
};

class Fakes {
 public:
  test::fake::FakeOsi fake_osi;
  FakeBtStack fake_stack;
};

}  // namespace

static int Cleanup(uint16_t* server_handle) {
  return RFCOMM_RemoveServer(*server_handle);
}

static int ServerInit(FuzzedDataProvider* fdp, uint16_t* server_handle) {
  RFCOMM_Init();

  auto mtu = fdp->ConsumeIntegral<uint16_t>();
  auto scn = fdp->ConsumeIntegral<uint8_t>();
  auto uuid = fdp->ConsumeIntegral<uint16_t>();

  int status = RFCOMM_CreateConnectionWithSecurity(
      uuid, scn, true, mtu, kDummyAddr, server_handle, port_mgmt_cback, 0);
  if (status != PORT_SUCCESS) {
    return status;
  }
  status = PORT_SetEventMaskAndCallback(*server_handle, PORT_EV_RXCHAR,
                                        port_event_cback);
  return status;
}

static void FuzzAsServer(FuzzedDataProvider* fdp) {
  auto server_handle = fdp->ConsumeIntegralInRange<uint16_t>(1, MAX_RFC_PORTS);
  if (ServerInit(fdp, &server_handle) != PORT_SUCCESS) {
    return;
  }

  appl_info.pL2CA_ConnectInd_Cb(kDummyRemoteAddr, kDummyCID, 0, kDummyId);

  // Simulating configuration confirmation event
  tL2CAP_CFG_INFO cfg = {};
  appl_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg);

  // Feeding input packets
  constexpr uint16_t kMaxPacketSize = 1024;
  while (fdp->remaining_bytes() > 0) {
    auto size = fdp->ConsumeIntegralInRange<uint16_t>(0, kMaxPacketSize);
    auto bytes = fdp->ConsumeBytes<uint8_t>(size);
    BT_HDR* hdr =
        reinterpret_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + bytes.size()));
    hdr->len = bytes.size();
    std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
    appl_info.pL2CA_DataInd_Cb(kDummyCID, hdr);
  }

  // Simulating disconnecting event
  appl_info.pL2CA_DisconnectInd_Cb(kDummyCID, false);

  Cleanup(&server_handle);
}

static int ClientInit(FuzzedDataProvider* fdp, uint16_t* client_handle) {
  RFCOMM_Init();

  auto mtu = fdp->ConsumeIntegral<uint16_t>();
  auto scn = fdp->ConsumeIntegral<uint8_t>();
  auto uuid = fdp->ConsumeIntegral<uint16_t>();

  int status = RFCOMM_CreateConnectionWithSecurity(
      uuid, scn, false, mtu, kDummyAddr, client_handle, port_mgmt_cback, 0);
  if (status != PORT_SUCCESS) {
    return status;
  }
  status = PORT_SetEventMaskAndCallback(*client_handle, PORT_EV_RXCHAR,
                                        port_event_cback);
  return status;
}

static void FuzzAsClient(FuzzedDataProvider* fdp) {
  auto client_handle = fdp->ConsumeIntegralInRange<uint16_t>(1, MAX_RFC_PORTS);

  if (ClientInit(fdp, &client_handle) != PORT_SUCCESS) {
    return;
  }

  // Simulating outbound connection confirm event
  appl_info.pL2CA_ConnectCfm_Cb(kDummyCID, L2CAP_CONN_OK);

  // Simulating configuration confirmation event
  tL2CAP_CFG_INFO cfg = {};
  appl_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg);

  // Feeding input packets
  constexpr uint16_t kMaxPacketSize = 1024;
  while (fdp->remaining_bytes() > 0) {
    auto size = fdp->ConsumeIntegralInRange<uint16_t>(0, kMaxPacketSize);
    auto bytes = fdp->ConsumeBytes<uint8_t>(size);
    BT_HDR* hdr =
        reinterpret_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + bytes.size()));
    hdr->len = bytes.size();
    std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
    appl_info.pL2CA_DataInd_Cb(kDummyCID, hdr);
  }

  Cleanup(&client_handle);
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  auto fakes = std::make_unique<Fakes>();

  FuzzedDataProvider fdp(data, size);

  if (fdp.ConsumeBool()) {
    FuzzAsServer(&fdp);
  } else {
    FuzzAsClient(&fdp);
  }

  return 0;
}