Added bluetoothV1.0_fuzzer

Test: ./bluetoothV1.0_fuzzer
Bug: 187131546

Change-Id: If73b3e9fa799057ae9ca8a1eba0e6a02c66498c0
diff --git a/bluetooth/1.0/default/test/fuzzer/Android.bp b/bluetooth/1.0/default/test/fuzzer/Android.bp
new file mode 100644
index 0000000..4ebeb28
--- /dev/null
+++ b/bluetooth/1.0/default/test/fuzzer/Android.bp
@@ -0,0 +1,55 @@
+/*
+ * 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,
+    },
+}
diff --git a/bluetooth/1.0/default/test/fuzzer/README.md b/bluetooth/1.0/default/test/fuzzer/README.md
new file mode 100644
index 0000000..edd4fb6
--- /dev/null
+++ b/bluetooth/1.0/default/test/fuzzer/README.md
@@ -0,0 +1,48 @@
+# 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
diff --git a/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
new file mode 100644
index 0000000..90cdc66
--- /dev/null
+++ b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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;
+}
diff --git a/bluetooth/1.0/default/test/fuzzer/bt_vendor.cpp b/bluetooth/1.0/default/test/fuzzer/bt_vendor.cpp
new file mode 100644
index 0000000..897fb67
--- /dev/null
+++ b/bluetooth/1.0/default/test/fuzzer/bt_vendor.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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);
+    }
+  }
+}
diff --git a/bluetooth/1.0/default/test/fuzzer/bt_vendor.h b/bluetooth/1.0/default/test/fuzzer/bt_vendor.h
new file mode 100644
index 0000000..ca227ea
--- /dev/null
+++ b/bluetooth/1.0/default/test/fuzzer/bt_vendor.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __BT_VENDOR_H__
+#define __BT_VENDOR_H__
+
+#include "bt_vendor_lib.h"
+
+class BtVendor {
+ public:
+  static BtVendor* getInstance() {
+    if (!mInstance) {
+      mInstance = new BtVendor;
+    }
+    return mInstance;
+  }
+
+  void setVendorCback(bt_vendor_callbacks_t* cb, bt_vendor_opcode_t opcode) {
+    mCbacks = cb;
+    mOpcode = opcode;
+  }
+
+  int32_t* queryFdList() { return fdList; }
+  size_t queryFdCount() { return fdCount; }
+  void callRemainingCbacks();
+  void populateFdList(int32_t list[], size_t count);
+
+ private:
+  BtVendor() = default;
+
+  ~BtVendor() {
+    if (mInstance) {
+      delete mInstance;
+      mInstance = nullptr;
+    }
+    mCbacks = nullptr;
+  }
+
+  static BtVendor* mInstance;
+  bt_vendor_callbacks_t* mCbacks = nullptr;
+  bt_vendor_opcode_t mOpcode;
+  int32_t fdCount;
+  int32_t fdList[CH_MAX] = {0};
+};
+
+BtVendor* BtVendor::mInstance = nullptr;
+#endif  // __BT_VENDOR_H__