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