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