1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <base/functional/callback.h>
18 #include <base/location.h>
19 #include <bluetooth/log.h>
20 #include <fuzzer/FuzzedDataProvider.h>
21
22 #include <cstdint>
23 #include <string>
24
25 #include "osi/include/allocator.h"
26 #include "stack/include/bt_hdr.h"
27 #include "stack/include/bt_uuid16.h"
28 #include "stack/include/gatt_api.h"
29 #include "test/fake/fake_osi.h"
30 #include "test/mock/mock_btif_config.h"
31 #include "test/mock/mock_stack_acl.h"
32 #include "test/mock/mock_stack_btm_dev.h"
33 #include "test/mock/mock_stack_l2cap_api.h"
34 #include "test/mock/mock_stack_l2cap_ble.h"
35
36 // TODO(b/369381361) Enfore -Wmissing-prototypes
37 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
38 #pragma GCC diagnostic ignored "-Wunused-parameter"
39
40 using bluetooth::Uuid;
do_in_main_thread(base::OnceCallback<void ()>)41 bt_status_t do_in_main_thread(base::OnceCallback<void()>) {
42 // this is not properly mocked, so we use abort to catch if this is used in
43 // any test cases
44 abort();
45 }
do_in_main_thread_delayed(base::OnceCallback<void ()>,std::chrono::microseconds)46 bt_status_t do_in_main_thread_delayed(base::OnceCallback<void()>, std::chrono::microseconds) {
47 // this is not properly mocked, so we use abort to catch if this is used in
48 // any test cases
49 abort();
50 }
51
52 namespace bluetooth {
53 namespace os {
GetSystemPropertyBool(const std::string & property,bool default_value)54 bool GetSystemPropertyBool(const std::string& property, bool default_value) {
55 return default_value;
56 }
GetSystemPropertyUint32(const std::string & property,uint32_t default_value)57 uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value) {
58 return default_value;
59 }
60 } // namespace os
61 } // namespace bluetooth
62
63 constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
64 constexpr uint16_t kMaxPacketSize = 1024;
65 namespace {
66
67 tL2CAP_FIXED_CHNL_REG fixed_chnl_reg;
68 tL2CAP_APPL_INFO appl_info;
69 tBTM_SEC_DEV_REC btm_sec_dev_rec;
70
71 class FakeBtStack {
72 public:
FakeBtStack()73 FakeBtStack() {
74 test::mock::stack_btm_dev::btm_find_dev.body = [](const RawAddress&) {
75 return &btm_sec_dev_rec;
76 };
77
78 test::mock::stack_l2cap_ble::L2CA_GetBleConnRole.body = [](const RawAddress&) {
79 return HCI_ROLE_CENTRAL;
80 };
81
82 test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr.body = [](const RawAddress&, uint16_t,
83 uint8_t) { return true; };
84 test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl.body = [](uint16_t lcid, const RawAddress&) {
85 bluetooth::log::assert_that(lcid == L2CAP_ATT_CID, "assert failed: lcid == L2CAP_ATT_CID");
86 return true;
87 };
88 test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl.body = [](uint16_t, const RawAddress&) {
89 return true;
90 };
91 test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t lcid, BT_HDR* hdr) {
92 osi_free(hdr);
93 return tL2CAP_DW_RESULT::SUCCESS;
94 };
95 test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t) { return true; };
96 test::mock::stack_l2cap_api::L2CA_SendFixedChnlData.body =
97 [](uint16_t cid, const RawAddress& addr, BT_HDR* hdr) {
98 osi_free(hdr);
99 return tL2CAP_DW_RESULT::SUCCESS;
100 };
101 test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel.body =
102 [](uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG* p_freg) {
103 fixed_chnl_reg = *p_freg;
104 return true;
105 };
106 test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity.body =
107 [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
108 tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu,
109 uint16_t sec_level) {
110 appl_info = p_cb_info;
111 return psm;
112 };
113 test::mock::stack_l2cap_api::L2CA_RegisterLECoc.body =
114 [](uint16_t psm, const tL2CAP_APPL_INFO& p_fixed_chnl_reg, uint16_t sec_level,
115 tL2CAP_LE_CFG_INFO cfg) { return psm; };
116
117 test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr.body = [](const RawAddress&, uint16_t,
118 uint8_t) { return true; };
119 test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout.body = [](const RawAddress&, uint16_t) {
120 return true;
121 };
122 }
123
~FakeBtStack()124 ~FakeBtStack() {
125 test::mock::stack_btm_dev::btm_find_dev = {};
126
127 test::mock::stack_l2cap_ble::L2CA_GetBleConnRole = {};
128
129 test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr = {};
130 test::mock::stack_l2cap_api::L2CA_RemoveFixedChnl = {};
131 test::mock::stack_l2cap_api::L2CA_ConnectFixedChnl = {};
132 test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
133 test::mock::stack_l2cap_api::L2CA_SendFixedChnlData = {};
134 test::mock::stack_l2cap_api::L2CA_RegisterFixedChannel = {};
135 test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity = {};
136 test::mock::stack_l2cap_api::L2CA_RegisterLECoc = {};
137 test::mock::stack_l2cap_api::L2CA_SetIdleTimeoutByBdAddr = {};
138 test::mock::stack_l2cap_api::L2CA_SetLeGattTimeout = {};
139 }
140 };
141
142 class Fakes {
143 public:
144 test::fake::FakeOsi fake_osi;
145 FakeBtStack fake_stack;
146 };
147
148 } // namespace
149
150 static uint16_t s_ConnId;
151 static tGATT_IF s_AppIf;
152
GattInit()153 static void GattInit() {
154 s_ConnId = 0;
155 s_AppIf = 0;
156
157 gatt_init();
158
159 /* Fill our internal UUID with a fixed pattern 0x82 */
160 std::array<uint8_t, Uuid::kNumBytes128> tmp;
161 tmp.fill(0x82);
162 Uuid app_uuid = Uuid::From128BitBE(tmp);
163
164 tGATT_CBACK gap_cback = {
165 .p_conn_cb = [](tGATT_IF, const RawAddress&, uint16_t conn_id, bool connected,
166 tGATT_DISCONN_REASON, tBT_TRANSPORT) { s_ConnId = conn_id; },
167 .p_cmpl_cb = [](uint16_t, tGATTC_OPTYPE, tGATT_STATUS, tGATT_CL_COMPLETE*) {},
168 .p_disc_res_cb = nullptr,
169 .p_disc_cmpl_cb = nullptr,
170 .p_req_cb = [](uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
171 tGATTS_DATA* p_data) {},
172 .p_enc_cmpl_cb = nullptr,
173 .p_congestion_cb = nullptr,
174 .p_phy_update_cb = nullptr,
175 .p_conn_update_cb = nullptr,
176 .p_subrate_chg_cb = nullptr,
177 };
178
179 s_AppIf = GATT_Register(app_uuid, "Gap", &gap_cback, false);
180 GATT_StartIf(s_AppIf);
181 }
182
ServerInit()183 static void ServerInit() {
184 GattInit();
185
186 tGATT_APPL_INFO appl_info = {
187 .p_nv_save_callback = [](bool, tGATTS_HNDL_RANGE*) {},
188 .p_srv_chg_callback = [](tGATTS_SRV_CHG_CMD, tGATTS_SRV_CHG_REQ*,
189 tGATTS_SRV_CHG_RSP*) { return true; },
190 };
191 (void)GATTS_NVRegister(&appl_info);
192
193 Uuid svc_uuid = Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER);
194 Uuid name_uuid = Uuid::From16Bit(GATT_UUID_GAP_DEVICE_NAME);
195 Uuid icon_uuid = Uuid::From16Bit(GATT_UUID_GAP_ICON);
196 Uuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
197
198 btgatt_db_element_t service[] = {{
199 .uuid = svc_uuid,
200 .type = BTGATT_DB_PRIMARY_SERVICE,
201 },
202 {.uuid = name_uuid,
203 .type = BTGATT_DB_CHARACTERISTIC,
204 .properties = GATT_CHAR_PROP_BIT_READ,
205 .permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE},
206 {.uuid = icon_uuid,
207 .type = BTGATT_DB_CHARACTERISTIC,
208 .properties = GATT_CHAR_PROP_BIT_READ,
209 .permissions = GATT_PERM_READ},
210 {.uuid = addr_res_uuid,
211 .type = BTGATT_DB_CHARACTERISTIC,
212 .properties = GATT_CHAR_PROP_BIT_READ,
213 .permissions = GATT_PERM_READ}};
214
215 /* Add a GAP service */
216 (void)GATTS_AddService(s_AppIf, service, sizeof(service) / sizeof(btgatt_db_element_t));
217 }
218
ServerCleanup()219 static void ServerCleanup() {
220 GATT_Deregister(s_AppIf);
221 gatt_free();
222 }
223
FuzzAsServer(FuzzedDataProvider & fdp)224 static void FuzzAsServer(FuzzedDataProvider& fdp) {
225 ServerInit();
226 fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, true, 0, BT_TRANSPORT_LE);
227
228 while (fdp.remaining_bytes() > 0) {
229 auto size = fdp.ConsumeIntegralInRange<uint16_t>(0, kMaxPacketSize);
230 auto bytes = fdp.ConsumeBytes<uint8_t>(size);
231 BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size());
232 hdr->len = bytes.size();
233 std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
234 fixed_chnl_reg.pL2CA_FixedData_Cb(L2CAP_ATT_CID, kDummyAddr, hdr);
235 }
236
237 ServerCleanup();
238 }
239
ClientInit()240 static void ClientInit() {
241 GattInit();
242 (void)GATT_Connect(s_AppIf, kDummyAddr, BTM_BLE_DIRECT_CONNECTION, BT_TRANSPORT_LE, false);
243 }
244
ClientCleanup()245 static void ClientCleanup() {
246 (void)GATT_CancelConnect(s_AppIf, kDummyAddr, true);
247 GATT_Deregister(s_AppIf);
248 gatt_free();
249 }
250
FuzzAsClient(FuzzedDataProvider & fdp)251 static void FuzzAsClient(FuzzedDataProvider& fdp) {
252 ClientInit();
253 fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, true, 0, BT_TRANSPORT_LE);
254
255 while (fdp.remaining_bytes() > 0) {
256 auto op = fdp.ConsumeIntegral<uint8_t>();
257 switch (op) {
258 case GATTC_OPTYPE_CONFIG: {
259 auto mtu = fdp.ConsumeIntegral<uint16_t>();
260 (void)GATTC_ConfigureMTU(s_ConnId, mtu);
261 break;
262 }
263 case GATTC_OPTYPE_DISCOVERY: {
264 auto type = (tGATT_DISC_TYPE)fdp.ConsumeIntegralInRange<uint8_t>(0, GATT_DISC_MAX);
265 uint16_t start = fdp.ConsumeIntegral<uint16_t>();
266 uint16_t end = fdp.ConsumeIntegral<uint16_t>();
267 (void)GATTC_Discover(s_ConnId, type, start, end);
268 break;
269 }
270 case GATTC_OPTYPE_READ: {
271 auto type = (tGATT_READ_TYPE)fdp.ConsumeIntegralInRange<uint8_t>(0, GATT_READ_MAX);
272 tGATT_READ_PARAM param = {};
273 fdp.ConsumeData(¶m, sizeof(param));
274 (void)GATTC_Read(s_ConnId, type, ¶m);
275 break;
276 }
277 case GATTC_OPTYPE_WRITE: {
278 auto type =
279 (tGATT_WRITE_TYPE)fdp.ConsumeIntegralInRange<uint8_t>(0, GATT_WRITE_PREPARE + 1);
280 tGATT_VALUE value = {};
281 value.len = fdp.ConsumeIntegralInRange<uint16_t>(0, sizeof(value.value));
282 value.len = fdp.ConsumeData(&value.value, value.len);
283 (void)GATTC_Write(s_ConnId, type, &value);
284 break;
285 }
286 case GATTC_OPTYPE_EXE_WRITE: {
287 auto type = fdp.ConsumeBool();
288 (void)GATTC_ExecuteWrite(s_ConnId, type);
289 break;
290 }
291 default:
292 break;
293 }
294 auto size = fdp.ConsumeIntegralInRange<uint16_t>(0, kMaxPacketSize);
295 auto bytes = fdp.ConsumeBytes<uint8_t>(size);
296 BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size());
297 hdr->len = bytes.size();
298 std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
299 fixed_chnl_reg.pL2CA_FixedData_Cb(L2CAP_ATT_CID, kDummyAddr, hdr);
300 }
301
302 fixed_chnl_reg.pL2CA_FixedConn_Cb(L2CAP_ATT_CID, kDummyAddr, false, 0, BT_TRANSPORT_LE);
303 ClientCleanup();
304 }
305
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)306 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
307 auto fakes = std::make_unique<Fakes>();
308
309 FuzzedDataProvider fdp(data, size);
310
311 if (fdp.ConsumeBool()) {
312 FuzzAsServer(fdp);
313 } else {
314 FuzzAsClient(fdp);
315 }
316
317 return 0;
318 }
319