/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FUZZER_SDP_HELPERS_H_ #define FUZZER_SDP_HELPERS_H_ // NOTE: This file should not be included directly. // It is included by the corresponding "...Functions.h" file. #include #include #include #include "fuzzers/common/commonFuzzHelpers.h" #include "osi/include/alarm.h" #include "stack/sdp/sdpint.h" #define SDP_MAX_NUM_ELEMS 128 #define SDP_MAX_ELEM_LEN 1024 #define SDP_MAX_ATTRS 1024 struct SDP_Sequence_Helper { uint8_t num_elem; std::shared_ptr type; std::shared_ptr len; std::shared_ptr p_val; std::vector> p_val_buffers; }; // Keep a vector of our initialized db objects // It will be up to the caller to free this array at the end of a fuzz loop std::vector> sdp_db_vect; std::vector sdp_record_handles; std::vector sdp_sequence_vect; std::vector> sdp_disc_rec_vect; std::vector> sdp_disc_attr_vect; std::vector> sdp_protolist_elem_vect; std::shared_ptr generateArbitrarySdpDiscAttr( FuzzedDataProvider*, bool); static bool initialized = false; void setupSdpFuzz() { if (!initialized) { sdp_init(); initialized = true; } } // Function to clean up and clear any allocated objects void cleanupSdpFuzz() { // Delete sdp_sequence_vect, sdp_disc_rec_vect, sdp_disc_attr_vect sdp_sequence_vect.clear(); sdp_disc_rec_vect.clear(); // Delete attributes & protolist elements sdp_disc_attr_vect.clear(); sdp_protolist_elem_vect.clear(); // Delete all records SDP_DeleteRecord(0); sdp_record_handles.clear(); // Delete Databases sdp_db_vect.clear(); // Set SDP Trace level back to default SDP_SetTraceLevel(0); } std::vector generateArbitraryAttrList(FuzzedDataProvider* fdp) { // build out attr_list uint16_t num_attrs = fdp->ConsumeIntegralInRange(0, SDP_MAX_ATTRS); std::vector attr_list; for (uint16_t i = 0; i < num_attrs; i++) { attr_list.push_back(fdp->ConsumeIntegral()); } return attr_list; } tSDP_DISC_ATVAL generateArbitrarySdpDiscAttrVal(FuzzedDataProvider* fdp) { tSDP_DISC_ATVAL new_attrval; new_attrval.v.u8 = fdp->ConsumeIntegral(); new_attrval.v.u16 = fdp->ConsumeIntegral(); new_attrval.v.u32 = fdp->ConsumeIntegral(); for (int i = 0; i < 4; i++) { new_attrval.v.array[i] = fdp->ConsumeIntegral(); } new_attrval.v.p_sub_attr = generateArbitrarySdpDiscAttr(fdp, true).get(); return new_attrval; } std::shared_ptr generateArbitrarySdpDiscAttr( FuzzedDataProvider* fdp, bool allow_null) { // Give it a chance to return a nullptr if (allow_null && !fdp->ConsumeBool()) { return nullptr; } std::shared_ptr new_attr(new tSDP_DISC_ATTR); sdp_disc_attr_vect.push_back(new_attr); new_attr->p_next_attr = generateArbitrarySdpDiscAttr(fdp, true).get(); new_attr->attr_id = fdp->ConsumeIntegral(); new_attr->attr_len_type = fdp->ConsumeBool() ? 16 : fdp->ConsumeIntegral(); new_attr->attr_value = generateArbitrarySdpDiscAttrVal(fdp); return new_attr; } std::shared_ptr generateArbitrarySdpDiscRecord( FuzzedDataProvider* fdp, bool allow_null) { // Give it a chance to return a nullptr if (allow_null && !fdp->ConsumeBool()) { return nullptr; } std::shared_ptr new_rec(new tSDP_DISC_REC); sdp_disc_rec_vect.push_back(new_rec); new_rec->p_first_attr = generateArbitrarySdpDiscAttr(fdp, true).get(); new_rec->p_next_rec = generateArbitrarySdpDiscRecord(fdp, true).get(); new_rec->time_read = fdp->ConsumeIntegral(); new_rec->remote_bd_addr = generateRawAddress(fdp); return new_rec; } tSDP_PROTOCOL_ELEM generateArbitrarySdpProtocolElements( FuzzedDataProvider* fdp) { tSDP_PROTOCOL_ELEM p_elem; // Set our protocol element values p_elem.protocol_uuid = fdp->ConsumeIntegral(); p_elem.num_params = fdp->ConsumeIntegralInRange(0, SDP_MAX_PROTOCOL_PARAMS); uint16_t num_loops = std::min( p_elem.num_params, static_cast(SDP_MAX_PROTOCOL_PARAMS)); // Regardless of number set above, fill out the entire allocated array for (uint16_t i = 0; i < num_loops; i++) { p_elem.params[i] = fdp->ConsumeIntegral(); } return p_elem; } std::shared_ptr generateArbitrarySdpProtocolElementList( FuzzedDataProvider* fdp) { std::shared_ptr p_elem_list(new tSDP_PROTO_LIST_ELEM); sdp_protolist_elem_vect.push_back(p_elem_list); // Populate our element list p_elem_list->num_elems = fdp->ConsumeIntegralInRange(0, SDP_MAX_LIST_ELEMS); uint16_t num_loops = std::min( p_elem_list->num_elems, static_cast(SDP_MAX_LIST_ELEMS)); for (uint16_t i = 0; i < num_loops; i++) { p_elem_list->list_elem[i] = generateArbitrarySdpProtocolElements(fdp); } return p_elem_list; } tSDP_PROTO_LIST_ELEM** generateArbitrarySdpProtocolElementListArray( FuzzedDataProvider* fdp, uint16_t* array_size) { *array_size = fdp->ConsumeIntegralInRange(0, SDP_MAX_ATTR_LEN); if (*array_size == 0) { return nullptr; } tSDP_PROTO_LIST_ELEM** p_list_array = static_cast( calloc(*array_size, sizeof(tSDP_PROTO_LIST_ELEM*))); if (p_list_array == nullptr) { return nullptr; } tSDP_PROTO_LIST_ELEM* p = p_list_array[0]; for (uint16_t i = 0; i < *array_size; i++, p++) { p = generateArbitrarySdpProtocolElementList(fdp).get(); } return p_list_array; } tSDP_DI_RECORD generateArbitrarySdpDiRecord(FuzzedDataProvider* fdp) { tSDP_DI_RECORD record; record.vendor = fdp->ConsumeIntegral(); record.vendor_id_source = fdp->ConsumeIntegral(); record.product = fdp->ConsumeIntegral(); record.version = fdp->ConsumeIntegral(); record.primary_record = fdp->ConsumeBool(); size_t num_executable_urls = fdp->ConsumeIntegralInRange(0, SDP_MAX_ATTR_LEN); for (size_t i = 0; i < num_executable_urls; i++) { record.client_executable_url[i] = fdp->ConsumeIntegral(); } size_t num_descriptions = fdp->ConsumeIntegralInRange(0, SDP_MAX_ATTR_LEN); for (size_t i = 0; i < num_descriptions; i++) { record.service_description[i] = fdp->ConsumeIntegral(); } size_t num_documentation_urls = fdp->ConsumeIntegralInRange(0, SDP_MAX_ATTR_LEN); for (size_t i = 0; i < num_documentation_urls; i++) { record.documentation_url[i] = fdp->ConsumeIntegral(); } return record; } tSDP_DI_GET_RECORD generateArbitrarySdpDiGetRecord(FuzzedDataProvider* fdp) { tSDP_DI_GET_RECORD get_record; get_record.spec_id = fdp->ConsumeIntegral(); get_record.rec = generateArbitrarySdpDiRecord(fdp); return get_record; } SDP_Sequence_Helper generateArbitrarySdpElemSequence(FuzzedDataProvider* fdp) { SDP_Sequence_Helper ret; // Get the number of our elements ret.num_elem = fdp->ConsumeIntegralInRange(1, SDP_MAX_NUM_ELEMS); ret.type.reset(new uint8_t[ret.num_elem]); ret.len.reset(new uint8_t[ret.num_elem]); ret.p_val.reset(new uint8_t*[ret.num_elem]); for (uint16_t i = 0; i < ret.num_elem; i++) { (ret.type.get())[i] = fdp->ConsumeIntegral(); if ((ret.len.get())[i] == 0) { (ret.p_val.get())[i] = nullptr; (ret.len.get())[i] = 0; } else { uint8_t buf_size = fdp->ConsumeIntegral(); // Link the size to the size of the buffer we're creating (ret.len.get())[i] = buf_size; std::shared_ptr p_val_sp( reinterpret_cast(calloc(buf_size, sizeof(uint8_t))), free); ret.p_val_buffers.push_back(p_val_sp); (ret.p_val.get())[i] = p_val_sp.get(); std::vector bytes = fdp->ConsumeBytes(buf_size); memcpy((ret.p_val.get())[i], bytes.data(), bytes.size()); } } // Push this struct to our array so we can delete later sdp_sequence_vect.push_back(ret); return ret; } // Define our callback functions we'll be using within our functions void sdp_disc_cmpl_cb(tSDP_STATUS result) {} void sdp_disc_cmpl_cb2(tSDP_STATUS result, void* user_data) {} #endif // FUZZER_SDP_HELPERS_H_