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