1 /*
2  * Copyright 2022 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 <fuzzer/FuzzedDataProvider.h>
18 
19 #include <cstdint>
20 #include <string>
21 #include <vector>
22 
23 #include "osi/include/allocator.h"
24 #include "stack/include/bt_hdr.h"
25 #include "stack/include/l2cdefs.h"
26 #include "stack/include/sdpdefs.h"
27 #include "stack/sdp/internal/sdp_api.h"
28 #include "stack/sdp/sdpint.h"
29 #include "test/fake/fake_osi.h"
30 #include "test/mock/mock_btif_config.h"
31 #include "test/mock/mock_stack_l2cap_api.h"
32 #include "types/bluetooth/uuid.h"
33 
34 namespace {
35 
36 #define SDP_DB_SIZE 0x10000
37 
38 constexpr uint16_t kDummyCID = 0x1234;
39 constexpr uint16_t kDummyPSM = 0x7788;
40 constexpr uint8_t kDummyID = 0x99;
41 constexpr uint8_t kDummyAddr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
42 
43 // Set up default callback structure
44 tL2CAP_APPL_INFO cb_info = {
45     .pL2CA_ConnectInd_Cb = [](const RawAddress& bd_addr, uint16_t lcid,
46                               uint16_t psm,
__anon580d385b0202() 47                               uint8_t id) {},  // tL2CA_CONNECT_IND_CB
48     .pL2CA_ConnectCfm_Cb = [](uint16_t lcid,
__anon580d385b0302() 49                               uint16_t result) {},  // tL2CA_CONNECT_CFM_CB
50     .pL2CA_ConfigInd_Cb = [](uint16_t lcid,
__anon580d385b0402() 51                              tL2CAP_CFG_INFO* p_cfg) {},  // tL2CA_CONFIG_IND_CB
52     .pL2CA_ConfigCfm_Cb = [](uint16_t lcid, uint16_t initiator,
__anon580d385b0502() 53                              tL2CAP_CFG_INFO* p_cfg) {},  // tL2CA_CONFIG_CFM_CB
54     .pL2CA_DisconnectInd_Cb =
__anon580d385b0602() 55         [](uint16_t lcid, bool should_ack) {},  // tL2CA_DISCONNECT_IND_CB
56     .pL2CA_DisconnectCfm_Cb =
__anon580d385b0702() 57         [](uint16_t lcid, uint16_t result) {},  // tL2CA_DISCONNECT_CFM_CB
58     .pL2CA_DataInd_Cb = [](uint16_t lcid,
__anon580d385b0802() 59                            BT_HDR* data) {},  // tL2CA_DATA_IND_CB
60     .pL2CA_CongestionStatus_Cb =
__anon580d385b0902() 61         [](uint16_t lcid, bool is_congested) {},  // tL2CA_CONGESTION_STATUS_CB
62     .pL2CA_TxComplete_Cb = [](uint16_t lcid,
__anon580d385b0a02() 63                               uint16_t num_sdu) {},  // tL2CA_TX_COMPLETE_CB
64     .pL2CA_Error_Cb = [](uint16_t lcid,
__anon580d385b0b02() 65                          uint16_t error_type) {},  // tL2CA_ERROR_CB
66     .pL2CA_CreditBasedConnectInd_Cb =
67         [](const RawAddress& bdaddr, std::vector<uint16_t>& lcids, uint16_t psm,
68            uint16_t peer_mtu,
__anon580d385b0c02() 69            uint8_t identifier) {},  // tL2CA_CREDIT_BASED_CONNECT_IND_CB
70     .pL2CA_CreditBasedConnectCfm_Cb =
71         [](const RawAddress& bdaddr, uint16_t lcid, uint16_t peer_mtu,
__anon580d385b0d02() 72            uint16_t result) {},  // tL2CA_CREDIT_BASED_CONNECT_CFM_CB
73     .pL2CA_CreditBasedReconfigCompleted_Cb =
74         [](const RawAddress& bdaddr, uint16_t lcid, bool is_local_cfg,
__anon580d385b0e02() 75            tL2CAP_LE_CFG_INFO* p_cfg) {
76         },  // tL2CA_CREDIT_BASED_RECONFIG_COMPLETED_CB
77     .pL2CA_CreditBasedCollisionInd_Cb =
__anon580d385b0f02() 78         [](const RawAddress& bdaddr) {},  // tL2CA_CREDIT_BASED_COLLISION_IND_CB
79 };
80 
81 class FakeL2cap {
82  public:
FakeL2cap()83   FakeL2cap() {
84     test::mock::stack_l2cap_api::L2CA_ConnectReq.body =
85         [](uint16_t psm, const RawAddress& raw_address) { return kDummyCID; };
86     test::mock::stack_l2cap_api::L2CA_ConnectReqWithSecurity.body =
87         [](uint16_t psm, const RawAddress& p_bd_addr, uint16_t sec_level) {
88           return L2CA_ConnectReq(psm, p_bd_addr);
89         };
90     test::mock::stack_l2cap_api::L2CA_DataWrite.body = [](uint16_t cid,
91                                                           BT_HDR* p_data) {
92       auto len = p_data->len;
93       osi_free(p_data);
94       return (uint8_t)len;
95     };
96     test::mock::stack_l2cap_api::L2CA_DisconnectReq.body = [](uint16_t lcid) {
97       return true;
98     };
99     test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity.body =
100         [](uint16_t psm, const tL2CAP_APPL_INFO& p_cb_info, bool enable_snoop,
101            tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu,
102            uint16_t required_remote_mtu, uint16_t sec_level) {
103           cb_info = p_cb_info;
104           return psm;
105         };
106   }
107 
~FakeL2cap()108   ~FakeL2cap() {
109     test::mock::stack_l2cap_api::L2CA_ConnectReq = {};
110     test::mock::stack_l2cap_api::L2CA_ConnectReqWithSecurity = {};
111     test::mock::stack_l2cap_api::L2CA_DataWrite = {};
112     test::mock::stack_l2cap_api::L2CA_DisconnectReq = {};
113     test::mock::stack_l2cap_api::L2CA_RegisterWithSecurity = {};
114   }
115 };
116 
117 class FakeBtifConfig {
118  public:
FakeBtifConfig()119   FakeBtifConfig() {
120     test::mock::btif_config::btif_config_set_bin.body =
121         [](const std::string&, const std::string&, const uint8_t*, size_t) {
122           // This function is not properly mocked. The abort here allows us to
123           // catch any cases using this mock.
124           abort();
125           return true;
126         };
127     test::mock::btif_config::btif_config_set_int.body =
128         [](const std::string& section, const std::string& key, int value) {
129           // This function is not properly mocked. The abort here allows us to
130           // catch any cases using this mock.
131           abort();
132           return true;
133         };
134   }
135 
~FakeBtifConfig()136   ~FakeBtifConfig() {
137     test::mock::btif_config::btif_config_set_bin = {};
138     test::mock::btif_config::btif_config_set_int = {};
139   }
140 };
141 
142 class Fakes {
143  public:
144   test::fake::FakeOsi fake_osi;
145   FakeL2cap fake_l2cap;
146   FakeBtifConfig fake_btif_config;
147 };
148 
149 }  // namespace
150 
FuzzAsServer(FuzzedDataProvider & fdp)151 static void FuzzAsServer(FuzzedDataProvider& fdp) {
152   std::vector<std::vector<uint8_t>> attrs;
153 
154   sdp_init();
155   auto rec_num = fdp.ConsumeIntegralInRange<uint8_t>(0, 10);
156   for (uint8_t i = 0; i < rec_num; i++) {
157     auto handle = SDP_CreateRecord();
158     auto attr_num = fdp.ConsumeIntegralInRange<uint8_t>(0, 10);
159     for (uint8_t s = 0; s < attr_num; s++) {
160       auto id = (i == 0) ? ATTR_ID_BT_PROFILE_DESC_LIST
161                          : fdp.ConsumeIntegral<uint16_t>();
162       auto type = fdp.ConsumeIntegral<uint8_t>();
163       auto len = fdp.ConsumeIntegralInRange<uint16_t>(1, 512);
164       auto data = fdp.ConsumeBytes<uint8_t>(len);
165 
166       if (data.size() == 0) {
167         break;
168       }
169 
170       attrs.push_back(data);
171       SDP_AddAttribute(handle, id, type, data.size(), data.data());
172     }
173   }
174 
175   cb_info.pL2CA_ConnectInd_Cb(RawAddress(kDummyAddr), kDummyCID, kDummyPSM,
176                               kDummyID);
177 
178   tL2CAP_CFG_INFO cfg = {};
179   cb_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg);
180 
181   while (fdp.remaining_bytes() > 0) {
182     auto size = fdp.ConsumeIntegralInRange<uint16_t>(0, 1024);
183     auto bytes = fdp.ConsumeBytes<uint8_t>(size);
184     BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size());
185     hdr->len = bytes.size();
186     std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
187     cb_info.pL2CA_DataInd_Cb(kDummyCID, hdr);
188   }
189 
190   cb_info.pL2CA_DisconnectInd_Cb(kDummyCID, false);
191   sdp_free();
192 }
193 
FuzzAsClient(FuzzedDataProvider & fdp)194 static void FuzzAsClient(FuzzedDataProvider& fdp) {
195   std::shared_ptr<tSDP_DISCOVERY_DB> p_db(
196       (tSDP_DISCOVERY_DB*)malloc(SDP_DB_SIZE), free);
197 
198   std::vector<bluetooth::Uuid> init_uuids;
199   std::vector<uint16_t> init_attrs;
200 
201   sdp_init();
202 
203   uint8_t num_uuid =
204       fdp.ConsumeIntegralInRange<uint8_t>(0, SDP_MAX_UUID_FILTERS);
205   uint8_t num_attr =
206       fdp.ConsumeIntegralInRange<uint8_t>(0, SDP_MAX_ATTR_FILTERS);
207 
208   for (uint8_t i = 0; i < num_uuid; i++) {
209     init_uuids.push_back(
210         bluetooth::Uuid::From16Bit(fdp.ConsumeIntegral<uint16_t>()));
211   }
212 
213   for (uint8_t i = 0; i < num_attr; i++) {
214     init_attrs.push_back(fdp.ConsumeIntegral<uint16_t>());
215   }
216 
217   SDP_InitDiscoveryDb(p_db.get(), SDP_DB_SIZE, init_uuids.size(),
218                       init_uuids.data(), init_attrs.size(), init_attrs.data());
219 
220   bool is_di_discover = fdp.ConsumeBool();
221   if (is_di_discover) {
222     SDP_ServiceSearchRequest(
223         kDummyAddr, p_db.get(),
224         [](const RawAddress& bd_addr, tSDP_RESULT result) {});
225   } else {
226     SDP_ServiceSearchAttributeRequest(
227         kDummyAddr, p_db.get(),
228         [](const RawAddress& bd_addr, tSDP_RESULT result) {});
229   }
230   cb_info.pL2CA_ConnectCfm_Cb(kDummyCID, L2CAP_CONN_OK);
231 
232   tL2CAP_CFG_INFO cfg = {};
233   cb_info.pL2CA_ConfigCfm_Cb(kDummyCID, 0, &cfg);
234 
235   while (fdp.remaining_bytes() > 0) {
236     auto size = fdp.ConsumeIntegralInRange<uint16_t>(0, 1024);
237     auto bytes = fdp.ConsumeBytes<uint8_t>(size);
238     BT_HDR* hdr = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + bytes.size());
239     hdr->len = bytes.size();
240     std::copy(bytes.cbegin(), bytes.cend(), hdr->data);
241     cb_info.pL2CA_DataInd_Cb(kDummyCID, hdr);
242   }
243 
244   cb_info.pL2CA_DisconnectInd_Cb(kDummyCID, false);
245   sdp_free();
246 }
247 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)248 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
249   auto fakes = std::make_unique<Fakes>();
250 
251   FuzzedDataProvider fdp(data, size);
252 
253   if (fdp.ConsumeBool()) {
254     FuzzAsServer(fdp);
255   } else {
256     FuzzAsClient(fdp);
257   }
258 
259   return 0;
260 }
261