Merge changes If73b3e9f,If67bf4ff

* changes:
  Added bluetoothV1.0_fuzzer
  Added cc_defaults for android.hardware.bluetooth@1.0-impl
This commit is contained in:
Treehugger Robot
2021-09-09 22:20:56 +00:00
committed by Gerrit Code Review
7 changed files with 548 additions and 3 deletions

View File

@@ -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,

View File

@@ -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,
},
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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__

View File

@@ -27,7 +27,11 @@
#include "h4_protocol.h"
#include "mct_protocol.h"
#ifdef BT_FUZZER
static const char* VENDOR_LIBRARY_NAME = "libbt-vendor-fuzz.so";
#else
static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
#endif
static const char* VENDOR_LIBRARY_SYMBOL_NAME =
"BLUETOOTH_VENDOR_LIB_INTERFACE";