1 /*
2  * Copyright 2020 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 #ifndef FUZZER_SDP_HELPERS_H_
18 #define FUZZER_SDP_HELPERS_H_
19 
20 // NOTE: This file should not be included directly.
21 //       It is included by the corresponding "...Functions.h" file.
22 
23 #include <fuzzer/FuzzedDataProvider.h>
24 
25 #include <algorithm>
26 #include <vector>
27 
28 #include "fuzzers/common/commonFuzzHelpers.h"
29 #include "stack/include/sdp_api.h"
30 #include "stack/include/sdpdefs.h"
31 #include "stack/sdp/sdpint.h"
32 #include "types/raw_address.h"
33 
34 using namespace bluetooth::legacy::stack::sdp;
35 
36 #define SDP_MAX_NUM_ELEMS 128
37 #define SDP_MAX_ELEM_LEN 1024
38 #define SDP_MAX_ATTRS 1024
39 
40 constexpr int32_t kMaxVectorSize = 1000;
41 
42 struct SDP_Sequence_Helper {
43   uint8_t num_elem;
44   std::shared_ptr<uint8_t> type;
45   std::shared_ptr<uint8_t> len;
46   std::shared_ptr<uint8_t*> p_val;
47   std::vector<std::shared_ptr<uint8_t>> p_val_buffers;
48 };
49 
50 // Keep a vector of our initialized db objects
51 // It will be up to the caller to free this array at the end of a fuzz loop
52 std::vector<std::shared_ptr<tSDP_DISCOVERY_DB>> sdp_db_vect;
53 std::vector<uint32_t> sdp_record_handles;
54 std::vector<SDP_Sequence_Helper> sdp_sequence_vect;
55 std::vector<std::shared_ptr<tSDP_DISC_REC>> sdp_disc_rec_vect;
56 std::vector<std::shared_ptr<tSDP_DISC_ATTR>> sdp_disc_attr_vect;
57 std::vector<std::shared_ptr<tSDP_PROTO_LIST_ELEM>> sdp_protolist_elem_vect;
58 
59 std::shared_ptr<tSDP_DISC_ATTR> generateArbitrarySdpDiscAttr(FuzzedDataProvider*, bool);
60 
61 static bool initialized = false;
setupSdpFuzz()62 void setupSdpFuzz() {
63   if (!initialized) {
64     sdp_init();
65     initialized = true;
66   }
67 }
68 
69 // Function to clean up and clear any allocated objects
cleanupSdpFuzz()70 void cleanupSdpFuzz() {
71   // Delete sdp_sequence_vect, sdp_disc_rec_vect, sdp_disc_attr_vect
72   sdp_sequence_vect.clear();
73 
74   sdp_disc_rec_vect.clear();
75 
76   // Delete attributes & protolist elements
77   sdp_disc_attr_vect.clear();
78   sdp_protolist_elem_vect.clear();
79 
80   // Delete all records
81   [[maybe_unused]] bool rc = get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(0);
82   sdp_record_handles.clear();
83 
84   // Delete Databases
85   sdp_db_vect.clear();
86 }
87 
generateArbitraryAttrList(FuzzedDataProvider * fdp)88 std::vector<uint16_t> generateArbitraryAttrList(FuzzedDataProvider* fdp) {
89   // build out attr_list
90   uint16_t num_attrs = fdp->ConsumeIntegralInRange<uint16_t>(0, SDP_MAX_ATTRS);
91 
92   std::vector<uint16_t> attr_list;
93   for (uint16_t i = 0; i < num_attrs; i++) {
94     attr_list.push_back(fdp->ConsumeIntegral<uint16_t>());
95   }
96 
97   return attr_list;
98 }
99 
generateArbitrarySdpDiscAttrVal(FuzzedDataProvider * fdp)100 tSDP_DISC_ATVAL generateArbitrarySdpDiscAttrVal(FuzzedDataProvider* fdp) {
101   tSDP_DISC_ATVAL new_attrval;
102 
103   new_attrval.v.u8 = fdp->ConsumeIntegral<uint8_t>();
104   new_attrval.v.u16 = fdp->ConsumeIntegral<uint16_t>();
105   new_attrval.v.u32 = fdp->ConsumeIntegral<uint32_t>();
106   for (int i = 0; i < 4; i++) {
107     new_attrval.v.array[i] = fdp->ConsumeIntegral<uint8_t>();
108   }
109   new_attrval.v.p_sub_attr = generateArbitrarySdpDiscAttr(fdp, true).get();
110 
111   return new_attrval;
112 }
113 
generateArbitrarySdpDiscAttr(FuzzedDataProvider * fdp,bool allow_null)114 std::shared_ptr<tSDP_DISC_ATTR> generateArbitrarySdpDiscAttr(FuzzedDataProvider* fdp,
115                                                              bool allow_null) {
116   // Give it a chance to return a nullptr
117   if ((allow_null && !fdp->ConsumeBool()) || sdp_disc_attr_vect.size() > kMaxVectorSize) {
118     return nullptr;
119   }
120 
121   std::shared_ptr<tSDP_DISC_ATTR> new_attr(new tSDP_DISC_ATTR);
122   sdp_disc_attr_vect.push_back(new_attr);
123 
124   new_attr->p_next_attr = generateArbitrarySdpDiscAttr(fdp, true).get();
125   new_attr->attr_id =
126           fdp->ConsumeBool() ? ATTR_ID_BT_PROFILE_DESC_LIST : fdp->ConsumeIntegral<uint16_t>();
127   new_attr->attr_len_type = fdp->ConsumeBool() ? 16 : fdp->ConsumeIntegral<uint16_t>();
128   new_attr->attr_value = generateArbitrarySdpDiscAttrVal(fdp);
129 
130   return new_attr;
131 }
132 
generateArbitrarySdpDiscRecord(FuzzedDataProvider * fdp,bool allow_null)133 std::shared_ptr<tSDP_DISC_REC> generateArbitrarySdpDiscRecord(FuzzedDataProvider* fdp,
134                                                               bool allow_null) {
135   // Give it a chance to return a nullptr
136   if (allow_null && !fdp->ConsumeBool()) {
137     return nullptr;
138   }
139 
140   std::shared_ptr<tSDP_DISC_REC> new_rec(new tSDP_DISC_REC);
141   sdp_disc_rec_vect.push_back(new_rec);
142 
143   new_rec->p_first_attr = generateArbitrarySdpDiscAttr(fdp, true).get();
144   new_rec->p_next_rec = generateArbitrarySdpDiscRecord(fdp, true).get();
145   new_rec->time_read = fdp->ConsumeIntegral<uint32_t>();
146   new_rec->remote_bd_addr = generateRawAddress(fdp);
147 
148   return new_rec;
149 }
150 
generateArbitrarySdpProtocolElements(FuzzedDataProvider * fdp)151 tSDP_PROTOCOL_ELEM generateArbitrarySdpProtocolElements(FuzzedDataProvider* fdp) {
152   tSDP_PROTOCOL_ELEM p_elem;
153 
154   // Set our protocol element values
155   p_elem.protocol_uuid = fdp->ConsumeIntegral<uint16_t>();
156   p_elem.num_params = fdp->ConsumeIntegralInRange<uint16_t>(0, SDP_MAX_PROTOCOL_PARAMS);
157   uint16_t num_loops = std::min(p_elem.num_params, static_cast<uint16_t>(SDP_MAX_PROTOCOL_PARAMS));
158   // Regardless of number set above, fill out the entire allocated array
159   for (uint16_t i = 0; i < num_loops; i++) {
160     p_elem.params[i] = fdp->ConsumeIntegral<uint16_t>();
161   }
162 
163   return p_elem;
164 }
165 
generateArbitrarySdpProtocolElementList(FuzzedDataProvider * fdp)166 std::shared_ptr<tSDP_PROTO_LIST_ELEM> generateArbitrarySdpProtocolElementList(
167         FuzzedDataProvider* fdp) {
168   std::shared_ptr<tSDP_PROTO_LIST_ELEM> p_elem_list(new tSDP_PROTO_LIST_ELEM);
169   sdp_protolist_elem_vect.push_back(p_elem_list);
170 
171   // Populate our element list
172   p_elem_list->num_elems = fdp->ConsumeIntegralInRange<uint16_t>(0, SDP_MAX_LIST_ELEMS);
173   uint16_t num_loops = std::min(p_elem_list->num_elems, static_cast<uint16_t>(SDP_MAX_LIST_ELEMS));
174   for (uint16_t i = 0; i < num_loops; i++) {
175     p_elem_list->list_elem[i] = generateArbitrarySdpProtocolElements(fdp);
176   }
177 
178   return p_elem_list;
179 }
180 
generateArbitrarySdpProtocolElementListArray(FuzzedDataProvider * fdp,uint16_t * array_size)181 tSDP_PROTO_LIST_ELEM** generateArbitrarySdpProtocolElementListArray(FuzzedDataProvider* fdp,
182                                                                     uint16_t* array_size) {
183   *array_size = fdp->ConsumeIntegralInRange<uint16_t>(0, SDP_MAX_ATTR_LEN);
184   if (*array_size == 0) {
185     return nullptr;
186   }
187   tSDP_PROTO_LIST_ELEM** p_list_array =
188           static_cast<tSDP_PROTO_LIST_ELEM**>(calloc(*array_size, sizeof(tSDP_PROTO_LIST_ELEM*)));
189   if (p_list_array == nullptr) {
190     return nullptr;
191   }
192 
193   tSDP_PROTO_LIST_ELEM* p = p_list_array[0];
194   for (uint16_t i = 0; i < *array_size; i++, p++) {
195     p = generateArbitrarySdpProtocolElementList(fdp).get();
196   }
197 
198   return p_list_array;
199 }
200 
generateArbitrarySdpDiRecord(FuzzedDataProvider * fdp)201 tSDP_DI_RECORD generateArbitrarySdpDiRecord(FuzzedDataProvider* fdp) {
202   tSDP_DI_RECORD record;
203 
204   record.vendor = fdp->ConsumeIntegral<uint16_t>();
205   record.vendor_id_source = fdp->ConsumeIntegral<uint16_t>();
206   record.product = fdp->ConsumeIntegral<uint16_t>();
207   record.version = fdp->ConsumeIntegral<uint16_t>();
208   record.primary_record = fdp->ConsumeBool();
209   size_t num_executable_urls = fdp->ConsumeIntegralInRange<size_t>(0, SDP_MAX_ATTR_LEN);
210   for (size_t i = 0; i < num_executable_urls; i++) {
211     record.client_executable_url[i] = fdp->ConsumeIntegral<char>();
212   }
213   size_t num_descriptions = fdp->ConsumeIntegralInRange<size_t>(0, SDP_MAX_ATTR_LEN);
214   for (size_t i = 0; i < num_descriptions; i++) {
215     record.service_description[i] = fdp->ConsumeIntegral<char>();
216   }
217   size_t num_documentation_urls = fdp->ConsumeIntegralInRange<size_t>(0, SDP_MAX_ATTR_LEN);
218   for (size_t i = 0; i < num_documentation_urls; i++) {
219     record.documentation_url[i] = fdp->ConsumeIntegral<char>();
220   }
221 
222   return record;
223 }
224 
generateArbitrarySdpDiGetRecord(FuzzedDataProvider * fdp)225 tSDP_DI_GET_RECORD generateArbitrarySdpDiGetRecord(FuzzedDataProvider* fdp) {
226   tSDP_DI_GET_RECORD get_record;
227   get_record.spec_id = fdp->ConsumeIntegral<uint16_t>();
228   get_record.rec = generateArbitrarySdpDiRecord(fdp);
229 
230   return get_record;
231 }
232 
generateArbitrarySdpElemSequence(FuzzedDataProvider * fdp)233 SDP_Sequence_Helper generateArbitrarySdpElemSequence(FuzzedDataProvider* fdp) {
234   SDP_Sequence_Helper ret;
235 
236   // Get the number of our elements
237   ret.num_elem = fdp->ConsumeIntegralInRange<uint16_t>(1, SDP_MAX_NUM_ELEMS);
238   ret.type.reset(new uint8_t[ret.num_elem]);
239   ret.len.reset(new uint8_t[ret.num_elem]);
240   ret.p_val.reset(new uint8_t*[ret.num_elem]);
241   for (uint16_t i = 0; i < ret.num_elem; i++) {
242     (ret.type.get())[i] = fdp->ConsumeIntegral<uint8_t>();
243     if ((ret.len.get())[i] == 0) {
244       (ret.p_val.get())[i] = nullptr;
245       (ret.len.get())[i] = 0;
246     } else {
247       uint8_t buf_size = fdp->ConsumeIntegral<uint8_t>();
248       // Link the size to the size of the buffer we're creating
249       (ret.len.get())[i] = buf_size;
250       std::shared_ptr<uint8_t> p_val_sp(
251               reinterpret_cast<uint8_t*>(calloc(buf_size, sizeof(uint8_t))), free);
252       ret.p_val_buffers.push_back(p_val_sp);
253       (ret.p_val.get())[i] = p_val_sp.get();
254       std::vector<uint8_t> bytes = fdp->ConsumeBytes<uint8_t>(buf_size);
255       memcpy((ret.p_val.get())[i], bytes.data(), bytes.size());
256     }
257   }
258 
259   // Push this struct to our array so we can delete later
260   sdp_sequence_vect.push_back(ret);
261 
262   return ret;
263 }
264 
265 // Define our callback functions we'll be using within our functions
sdp_disc_cmpl_cb(const RawAddress &,tSDP_STATUS)266 void sdp_disc_cmpl_cb(const RawAddress& /*bd_addr*/, tSDP_STATUS /*result*/) {}
sdp_disc_cmpl_cb2(std::vector<uint8_t>,const RawAddress &,tSDP_STATUS)267 void sdp_disc_cmpl_cb2(std::vector<uint8_t> /*data*/, const RawAddress& /*bd_addr*/,
268                        tSDP_STATUS /*result*/) {}
269 
270 #endif  // FUZZER_SDP_HELPERS_H_
271