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