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