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