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