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(&param, sizeof(param));
280         (void)GATTC_Read(s_ConnId, type, &param);
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