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

Commit de5e7233 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge changes If73b3e9f,If67bf4ff am: b87fef9c am: f92be067

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1723072

Change-Id: Id08bacc8b07247377826acae859d431631a4b2cf
parents f1f4b798 f92be067
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -22,9 +22,8 @@ package {
    default_applicable_licenses: ["hardware_interfaces_license"],
}

cc_library {
    name: "android.hardware.bluetooth@1.0-impl",
    defaults: ["hidl_defaults"],
cc_defaults {
    name: "android.hardware.bluetooth@1.0-defaults",
    vendor: true,
    relative_install_path: "hw",
    srcs: [
@@ -47,6 +46,25 @@ cc_library {
    ],
}

cc_library {
    name: "android.hardware.bluetooth@1.0-impl",
    defaults: [
        "hidl_defaults",
        "android.hardware.bluetooth@1.0-defaults",
    ],
}

cc_library {
    name: "android.hardware.bluetooth@1.0-impl-test",
    defaults: [
        "hidl_defaults",
        "android.hardware.bluetooth@1.0-defaults",
    ],
    cflags: [
        "-DBT_FUZZER",
    ],
}

cc_library_static {
    name: "android.hardware.bluetooth-async",
    vendor: true,
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.
 *
 */
cc_library {
    name: "libbt-vendor-fuzz",
    vendor: true,
    srcs: [
        "bt_vendor.cpp",
    ],
    static_libs: [
        "android.hardware.bluetooth@1.0-impl-test",
        "android.hardware.bluetooth-hci",
    ],
}

cc_fuzz {
    name: "bluetoothV1.0_fuzzer",
    vendor: true,
    srcs: [
        "bluetoothV1.0_fuzzer.cpp",
    ],
    static_libs: [
        "android.hardware.bluetooth@1.0-impl-test",
        "android.hardware.bluetooth-async",
        "android.hardware.bluetooth-hci",
        "libcutils",
        "libutils",
    ],
    shared_libs: [
        "android.hardware.bluetooth@1.0",
        "libhardware",
        "libhidlbase",
        "libbt-vendor-fuzz",
        "liblog",
    ],
    fuzz_config: {
        cc: [
            "android-media-fuzzing-reports@google.com",
        ],
        componentid: 533764,
    },
}
+48 −0
Original line number Diff line number Diff line
# Fuzzer for android.hardware.bluetooth@1.0-impl-test

## Plugin Design Considerations
The fuzzer plugin for android.hardware.bluetooth@1.0-impl-test is designed based on the understanding of the source code and tries to achieve the following:

##### Maximize code coverage
1. The configuration parameters are not hardcoded, but instead selected based on
incoming data. This ensures more code paths are reached by the fuzzer.

2. A new library *'libbt-vendor-fuzz.so'* is created that implements functions of `bt_vendor_interface_t` and calls them in order to maximize the code coverage

android.hardware.bluetooth@1.0-impl-test supports the following parameters:

1. Bluetooth Address (parameter name: `btAddress`)

| Parameter| Valid Values| Configured Value|
|------------- |-------------| ----- |
| `btAddress` | Values inside array ranges from `0x0` to `0xFF`| Value obtained from FuzzedDataProvider|

This also ensures that the plugin is always deterministic for any given input.

##### Maximize utilization of input data
The plugin feeds the entire input data to the module.
This ensures that the plugin tolerates any kind of input (empty, huge,
malformed, etc) and doesnt `exit()` on any input and thereby increasing the
chance of identifying vulnerabilities.

## Build

This describes steps to build bluetoothV1.0_fuzzer binary.

### Android

#### Steps to build
Build the fuzzer
```
  $ mm -j$(nproc) bluetoothV1.0_fuzzer
```
#### Steps to run
To run on device
```
  $ adb sync data
  $ adb shell LD_LIBRARY_PATH=/data/fuzz/${TARGET_ARCH}/lib/ /data/fuzz/${TARGET_ARCH}/bluetoothV1.0_fuzzer/bluetoothV1.0_fuzzer
```

## References:
 * http://llvm.org/docs/LibFuzzer.html
 * https://github.com/google/oss-fuzz
+198 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 <android/hardware/bluetooth/1.0/IBluetoothHci.h>
#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
#include <bluetooth_address.h>
#include <bluetooth_hci.h>
#include <cutils/properties.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <log/log.h>

#include "bt_vendor.h"

using namespace std;
using ::android::sp;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
using ::android::hardware::bluetooth::V1_0::Status;
using ::android::hardware::bluetooth::V1_0::implementation::BluetoothAddress;
using ::android::hardware::bluetooth::V1_0::implementation::BluetoothHci;
using ::android::hardware::bluetooth::V1_0::implementation::
    FACTORY_BDADDR_PROPERTY;
using ::android::hardware::bluetooth::V1_0::implementation::
    PERSIST_BDADDR_PROPERTY;
using ::android::hardware::bluetooth::V1_0::implementation::
    PROPERTY_BT_BDADDR_PATH;

constexpr size_t kMaxPacketSize = 100;
constexpr size_t kMinFdcount = 2;

template <typename T>
const hidl_vec<T> toHidlVec(const std::vector<T>& vec) {
  hidl_vec<T> hVec;
  hVec.setToExternal(const_cast<T*>(vec.data()), vec.size());
  return hVec;
}

class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
 public:
  virtual ~BluetoothHciCallbacks() = default;

  Return<void> initializationComplete(Status status) override {
    if (status == Status::SUCCESS) {
      isInitialized = true;
    } else {
      isInitialized = false;
    }
    return Return<void>();
  };

  Return<void> hciEventReceived(
      const ::android::hardware::hidl_vec<uint8_t>& /*event*/) override {
    return Return<void>();
  };

  Return<void> aclDataReceived(
      const ::android::hardware::hidl_vec<uint8_t>& /*data*/) override {
    return Return<void>();
  };

  Return<void> scoDataReceived(
      const ::android::hardware::hidl_vec<uint8_t>& /*data*/) override {
    return Return<void>();
  };
  bool isInitialized;
};

class BluetoothFuzzer {
 public:
  ~BluetoothFuzzer() {
    if (mFdp) {
      delete mFdp;
    }
    mBtHci->close();
    mBtHci.clear();
  }
  bool init(const uint8_t* data, size_t size);
  void process();

 private:
  sp<BluetoothHci> mBtHci = nullptr;
  FuzzedDataProvider* mFdp = nullptr;
};

bool BluetoothFuzzer::init(const uint8_t* data, size_t size) {
  mBtHci = sp<BluetoothHci>::make();
  if (!mBtHci) {
    return false;
  }
  mFdp = new FuzzedDataProvider(data, size);
  return true;
}

void BluetoothFuzzer::process() {
  sp<BluetoothHciCallbacks> bluetoothCallback =
      sp<BluetoothHciCallbacks>::make();

  uint8_t btAddress[BluetoothAddress::kBytes];
  mFdp->ConsumeData(btAddress, sizeof(uint8_t) * BluetoothAddress::kBytes);

  char btAddrString[BluetoothAddress::kStringLength + 1];
  BluetoothAddress::bytes_to_string(btAddress, btAddrString);

  /* property_set() is called so that BluetoothAddress::get_local_address()
   * could return true and the LOG_ALWAYS_FATAL() that aborts the run, if
   * BluetoothAddress::get_local_address() returns false, could be avoided.
   *
   * BluetoothAddress::get_local_address() first searches if
   * PROPERTY_BT_BDADDR_PATH is set, if it fails to get PROPERTY_BT_BDADDR_PATH,
   * it searches for FACTORY_BDADDR_PROPERTY. If it fails to get
   * FACTORY_BDADDR_PROPERTY, it then searches for PERSIST_BDADDR_PROPERTY. If
   * PERSIST_BDADDR_PROPERTY is also not set, it results in an abort.
   */
  property_set(PERSIST_BDADDR_PROPERTY, btAddrString);

  if (mFdp->ConsumeBool()) {
    property_set(FACTORY_BDADDR_PROPERTY, btAddrString);
  }

  if (mFdp->ConsumeBool()) {
    char property[PROPERTY_VALUE_MAX] = {0};
    property_get("ro.vendor.bt.bdaddr_path", property, NULL);
    // get the value of ro.vendor.bt.bdaddr_path and set it to
    // PROPERTY_BT_BDADDR_PATH
    property_set(PROPERTY_BT_BDADDR_PATH, property);
  }

  bool shouldSetH4Protocol = mFdp->ConsumeBool();
  BtVendor* btVendor = BtVendor::getInstance();

  size_t fdcount = 1;
  int32_t fdList[CH_MAX] = {0};
  if (!shouldSetH4Protocol) {
    fdcount = mFdp->ConsumeIntegralInRange<size_t>(kMinFdcount, CH_MAX - 1);
  }

  for (size_t i = 0; i < fdcount; ++i) {
    fdList[i] = open("/dev/null", O_RDWR | O_CREAT);
  }

  btVendor->populateFdList(fdList, fdcount);
  mBtHci->initialize(bluetoothCallback);

  if (!bluetoothCallback->isInitialized) {
    return;
  }

  std::vector<uint8_t> hciPacket, aclPacket;

  size_t hciPacketSize =
      mFdp->ConsumeIntegralInRange<size_t>(0, kMaxPacketSize);
  hciPacket = mFdp->ConsumeBytes<uint8_t>(hciPacketSize);
  mBtHci->sendHciCommand(toHidlVec(hciPacket));

  size_t aclPacketSize =
      mFdp->ConsumeIntegralInRange<size_t>(0, kMaxPacketSize);
  aclPacket = mFdp->ConsumeBytes<uint8_t>(aclPacketSize);
  mBtHci->sendAclData(toHidlVec(aclPacket));

  if (shouldSetH4Protocol) {
    std::vector<uint8_t> scoPacket;
    size_t scoPacketSize =
        mFdp->ConsumeIntegralInRange<size_t>(0, kMaxPacketSize);
    scoPacket = mFdp->ConsumeBytes<uint8_t>(scoPacketSize);
    mBtHci->sendScoData(toHidlVec(scoPacket));
  }

  btVendor->callRemainingCbacks();

  for (size_t i = 0; i < fdcount; ++i) {
    if (fdList[i]) {
      close(fdList[i]);
    }
  }
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  BluetoothFuzzer bluetoothFuzzer;
  if (bluetoothFuzzer.init(data, size)) {
    bluetoothFuzzer.process();
  }
  return 0;
}
+162 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 "bt_vendor.h"

#define UNUSED_PARAM __attribute__((unused))
#define HCI_CMD_PREAMBLE_SIZE 3
#define HCI_RESET 0x0C03
#define HCI_EVT_CMD_CMPL_OPCODE 3
#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE 5
#define MSG_STACK_TO_HC_HCI_CMD 0x2000
#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR))
#define STREAM_TO_UINT16(u16, p)                                \
  {                                                             \
    u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
    (p) += 2;                                                   \
  }
#define UINT16_TO_STREAM(p, u16)    \
  {                                 \
    *(p)++ = (uint8_t)(u16);        \
    *(p)++ = (uint8_t)((u16) >> 8); \
  }
bt_vendor_callbacks_t* bt_vendor_cbacks = nullptr;

void hw_epilog_cback(void* p_mem) {
  HC_BT_HDR* p_evt_buf = (HC_BT_HDR*)p_mem;
  uint8_t *p, status;
  uint16_t opcode;

  status = *((uint8_t*)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE);
  p = (uint8_t*)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
  STREAM_TO_UINT16(opcode, p);

  if (!bt_vendor_cbacks) {
    return;
  }
  /* Must free the RX event buffer */
  bt_vendor_cbacks->dealloc(p_evt_buf);

  /* Once epilog process is done, must call callback to notify caller */
  bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
  return;
}

static int testInit(const bt_vendor_callbacks_t* cb,
                    unsigned char* bdaddr UNUSED_PARAM) {
  if (cb == nullptr) {
    return -1;
  }
  /*store reference to user callbacks */
  bt_vendor_cbacks = (bt_vendor_callbacks_t*)cb;
  return 0;
}

static int testOperations(bt_vendor_opcode_t opcode, void* param UNUSED_PARAM) {
  BtVendor* btVendor = BtVendor::getInstance();
  if (bt_vendor_cbacks) {
    btVendor->setVendorCback(bt_vendor_cbacks, opcode);
  }
  switch (opcode) {
    case BT_VND_OP_POWER_CTRL: {
      // No callback for this opcode
      break;
    }
    case BT_VND_OP_USERIAL_OPEN: {
      int32_t(*fd_array)[] = (int32_t(*)[])param;
      int32_t fdArray[CH_MAX];
      *fdArray = *(btVendor->queryFdList());
      size_t fdcount = btVendor->queryFdCount();
      for (size_t i = 0; i < fdcount; ++i) {
        (*fd_array)[i] = fdArray[i];
      }
      return fdcount;
      break;
    }
    case BT_VND_OP_FW_CFG: {
      if (bt_vendor_cbacks) {
        bt_vendor_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
      }
      break;
    }
    case BT_VND_OP_GET_LPM_IDLE_TIMEOUT: {
      // No callback for this opcode
      uint32_t* timeout_ms = (uint32_t*)param;
      *timeout_ms = 0;
      break;
    }
    case BT_VND_OP_LPM_SET_MODE: {
      if (bt_vendor_cbacks) {
        bt_vendor_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
      }
      break;
    }
    case BT_VND_OP_USERIAL_CLOSE: {
      // No callback for this opcode
      break;
    }
    case BT_VND_OP_LPM_WAKE_SET_STATE: {
      // No callback for this opcode
      break;
    }
    default:
      break;
  }
  return 0;
}

static void testCleanup(void) { bt_vendor_cbacks = nullptr; }

const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
    sizeof(bt_vendor_interface_t), testInit, testOperations, testCleanup};

void BtVendor::populateFdList(int32_t list[], size_t count) {
  fdCount = count;
  for (size_t i = 0; i < count; ++i) {
    fdList[i] = list[i];
  }
}

void BtVendor::callRemainingCbacks() {
  if (mCbacks) {
    mCbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS);
    mCbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
    mCbacks->a2dp_offload_cb(BT_VND_OP_RESULT_SUCCESS, mOpcode, 0);
    mCbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);

    HC_BT_HDR* p_buf = NULL;
    uint8_t* p;

    /* Sending a HCI_RESET */
    /* Must allocate command buffer via HC's alloc API */
    p_buf = (HC_BT_HDR*)mCbacks->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE);
    if (p_buf) {
      p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
      p_buf->offset = 0;
      p_buf->layer_specific = 0;
      p_buf->len = HCI_CMD_PREAMBLE_SIZE;

      p = (uint8_t*)(p_buf + 1);
      UINT16_TO_STREAM(p, HCI_RESET);
      *p = 0; /* parameter length */

      /* Send command via HC's xmit_cb API */
      mCbacks->xmit_cb(HCI_RESET, p_buf, hw_epilog_cback);
    } else {
      mCbacks->epilog_cb(BT_VND_OP_RESULT_FAIL);
    }
  }
}
Loading