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 BT_STACK_FUZZ_A2DP_CODEC_FUNCTIONS_H_
18 #define BT_STACK_FUZZ_A2DP_CODEC_FUNCTIONS_H_
19 
20 #include <fcntl.h>  // For fd
21 #include <fuzzer/FuzzedDataProvider.h>
22 #include <sys/stat.h>  // For fd
23 #include <vector>
24 #include "a2dp_codec_api.h"
25 #include "fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h"
26 #include "fuzzers/a2dp/codec/a2dpCodecInfoFuzzFunctions.h"
27 #include "fuzzers/common/commonFuzzHelpers.h"
28 
29 #include "fuzzers/a2dp/codec/a2dpCodecFuzzHelpers.h"
30 
31 #define MAX_NUM_PROPERTIES 128
32 #define A2DP_MAX_INIT_RUNS 16
33 
34 /* This is a vector of lambda functions the fuzzer will pull from.
35  *  This is done so new functions can be added to the fuzzer easily
36  *  without requiring modifications to the main fuzzer file. This also
37  *  allows multiple fuzzers to include this file, if functionality is needed.
38  */
39 std::vector<std::function<void(FuzzedDataProvider*)>> a2dp_codec_operations = {
40     // A2dpCodecs Constructor
41     [](FuzzedDataProvider* fdp) -> void {
42       // Build out a vector of codec objects
43       std::vector<btav_a2dp_codec_config_t> codec_priorities;
44       size_t num_priorities =
45           fdp->ConsumeIntegralInRange<size_t>(0, MAX_NUM_PROPERTIES);
46       for (size_t i = 0; i < num_priorities; i++) {
47         codec_priorities.push_back(getArbitraryBtavCodecConfig(fdp));
48       }
49       // Construct a const ref so we can pass to constructor
50       const std::vector<btav_a2dp_codec_config_t>& codec_priorities_const =
51           codec_priorities;
52       std::shared_ptr<A2dpCodecs> codecs(
53           new A2dpCodecs(codec_priorities_const));
54       if (codecs) {
55         a2dp_codecs_vect.push_back(codecs);
56       }
57     },
58 
59     // A2dpCodecs Destructor
60     [](FuzzedDataProvider* fdp) -> void {
61       if (a2dp_codecs_vect.empty()) {
62         return;
63       }
64       // Get random vector index
65       size_t index =
66           fdp->ConsumeIntegralInRange<size_t>(0, a2dp_codecs_vect.size() - 1);
67       // Remove from vector
68       a2dp_codecs_vect.erase(a2dp_codecs_vect.begin() + index);
69     },
70 
71     // init
72     [](FuzzedDataProvider* fdp) -> void {
73       // Limit the number of times we can call this function per iteration
74       // (This is to prevent slow-units)
75       if (a2dp_init_runs <= A2DP_MAX_INIT_RUNS) {
76         std::shared_ptr<A2dpCodecs> codecs =
77             getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
78         if (codecs) {
79           a2dp_init_runs++;
80           codecs->init();
81         }
82       }
83     },
84 
85     // findSourceCodecConfig
86     [](FuzzedDataProvider* fdp) -> void {
87       std::shared_ptr<A2dpCodecs> codecs =
88           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
89       uint8_t* p_codec_info =
90           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
91 
92       if (codecs && p_codec_info) {
93         codecs->findSourceCodecConfig(p_codec_info);
94       }
95     },
96 
97     // findSinkCodecConfig
98     [](FuzzedDataProvider* fdp) -> void {
99       std::shared_ptr<A2dpCodecs> codecs =
100           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
101       uint8_t* p_codec_info =
102           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
103 
104       if (codecs && p_codec_info) {
105         codecs->findSinkCodecConfig(p_codec_info);
106       }
107     },
108 
109     // isSupportedCodec
110     [](FuzzedDataProvider* fdp) -> void {
111       std::shared_ptr<A2dpCodecs> codecs =
112           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
113       if (codecs) {
114         codecs->isSupportedCodec(getArbitraryBtavCodecIndex(fdp));
115       }
116     },
117 
118     // getCurrentCodecConfig
119     [](FuzzedDataProvider* fdp) -> void {
120       std::shared_ptr<A2dpCodecs> codecs =
121           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
122       if (codecs) {
123         codecs->getCurrentCodecConfig();
124       }
125     },
126 
127     // orderedSourceCodecs
128     [](FuzzedDataProvider* fdp) -> void {
129       std::shared_ptr<A2dpCodecs> codecs =
130           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
131       if (codecs) {
132         codecs->orderedSourceCodecs();
133       }
134     },
135 
136     // orderedSinkCodecs
137     [](FuzzedDataProvider* fdp) -> void {
138       std::shared_ptr<A2dpCodecs> codecs =
139           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
140       if (codecs) {
141         codecs->orderedSinkCodecs();
142       }
143     },
144 
145     // setCodecConfig
146     [](FuzzedDataProvider* fdp) -> void {
147       std::shared_ptr<A2dpCodecs> codecs =
148           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
149       if (codecs == nullptr) {
150         return;
151       }
152 
153       const uint8_t* peer_codec_info =
154           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
155       if (peer_codec_info == nullptr) {
156         return;
157       }
158 
159       // Codec_config is actually some buffer
160       std::unique_ptr<uint8_t, void (*)(void*)> p_result_codec_config(
161           reinterpret_cast<uint8_t*>(calloc(500, sizeof(uint8_t))), free);
162       if (p_result_codec_config) {
163         codecs->setCodecConfig(peer_codec_info, fdp->ConsumeBool(),
164                                p_result_codec_config.get(), fdp->ConsumeBool());
165       }
166     },
167 
168     // setSinkCodecConfig
169     [](FuzzedDataProvider* fdp) -> void {
170       std::shared_ptr<A2dpCodecs> codecs =
171           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
172       if (codecs == nullptr) {
173         return;
174       }
175 
176       const uint8_t* peer_codec_info =
177           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
178       if (peer_codec_info == nullptr) {
179         return;
180       }
181 
182       // Codec_config is actually some buffer
183       std::unique_ptr<uint8_t, void (*)(void*)> p_result_codec_config(
184           reinterpret_cast<uint8_t*>(calloc(500, sizeof(uint8_t))), free);
185       if (p_result_codec_config) {
186         codecs->setSinkCodecConfig(peer_codec_info, fdp->ConsumeBool(),
187                                    p_result_codec_config.get(),
188                                    fdp->ConsumeBool());
189       }
190     },
191 
192     // setCodecUserConfig
193     [](FuzzedDataProvider* fdp) -> void {
194       std::shared_ptr<A2dpCodecs> codecs =
195           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
196       if (codecs == nullptr) {
197         return;
198       }
199 
200       const btav_a2dp_codec_config_t codec_user_config =
201           getArbitraryBtavCodecConfig(fdp);
202       const tA2DP_ENCODER_INIT_PEER_PARAMS p_peer_params =
203           getArbitraryA2dpEncoderInitPeerParams(fdp);
204       const uint8_t* p_peer_sink_capabilities =
205           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
206       if (p_peer_sink_capabilities == nullptr) {
207         return;
208       }
209 
210       // Craft our result variables (And possibly pass nullptrs)
211       btav_a2dp_codec_config_t result_codec_config;
212       bool restart_input, restart_output, config_updated;
213       uint8_t* p_result_codec_config =
214           reinterpret_cast<uint8_t*>(&result_codec_config);
215       codecs->setCodecUserConfig(codec_user_config, &p_peer_params,
216                                  p_peer_sink_capabilities,
217                                  p_result_codec_config, &restart_input,
218                                  &restart_output, &config_updated);
219     },
220 
221     // setCodecAudioConfig
222     [](FuzzedDataProvider* fdp) -> void {
223       std::shared_ptr<A2dpCodecs> codecs =
224           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
225       if (codecs == nullptr) {
226         return;
227       }
228 
229       const btav_a2dp_codec_config_t codec_audio_config =
230           getArbitraryBtavCodecConfig(fdp);
231       const tA2DP_ENCODER_INIT_PEER_PARAMS p_peer_params =
232           getArbitraryA2dpEncoderInitPeerParams(fdp);
233       const uint8_t* p_peer_sink_capabilities =
234           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
235       if (p_peer_sink_capabilities == nullptr) {
236         return;
237       }
238       btav_a2dp_codec_config_t result_codec_config;
239       uint8_t* p_result_codec_config =
240           reinterpret_cast<uint8_t*>(&result_codec_config);
241       bool p_restart_output, p_config_updated;
242       codecs->setCodecAudioConfig(
243           codec_audio_config, &p_peer_params, p_peer_sink_capabilities,
244           p_result_codec_config, &p_restart_output, &p_config_updated);
245     },
246 
247     // setCodecOtaConfig
248     [](FuzzedDataProvider* fdp) -> void {
249       std::shared_ptr<A2dpCodecs> codecs =
250           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
251       if (codecs == nullptr) {
252         return;
253       }
254 
255       const uint8_t* p_ota_codec_config =
256           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
257       if (p_ota_codec_config == nullptr) {
258         return;
259       }
260 
261       const tA2DP_ENCODER_INIT_PEER_PARAMS p_peer_params =
262           getArbitraryA2dpEncoderInitPeerParams(fdp);
263       btav_a2dp_codec_config_t result_codec_config;
264       uint8_t* p_result_codec_config =
265           reinterpret_cast<uint8_t*>(&result_codec_config);
266       bool p_restart_input, p_restart_output, p_config_updated;
267       codecs->setCodecOtaConfig(p_ota_codec_config, &p_peer_params,
268                                 p_result_codec_config, &p_restart_input,
269                                 &p_restart_output, &p_config_updated);
270     },
271 
272     // setPeerSinkCodecCapabilities
273     [](FuzzedDataProvider* fdp) -> void {
274       std::shared_ptr<A2dpCodecs> codecs =
275           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
276       if (codecs == nullptr) {
277         return;
278       }
279 
280       const uint8_t* p_peer_codec_capabilities =
281           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
282       if (p_peer_codec_capabilities == nullptr) {
283         return;
284       }
285       codecs->setPeerSinkCodecCapabilities(p_peer_codec_capabilities);
286     },
287 
288     // setPeerSourceCodecCapabilities
289     [](FuzzedDataProvider* fdp) -> void {
290       std::shared_ptr<A2dpCodecs> codecs =
291           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
292       if (codecs == nullptr) {
293         return;
294       }
295 
296       const uint8_t* p_peer_codec_capabilities =
297           getArbitraryVectorElement(fdp, a2dp_codec_info_vect, false);
298       if (p_peer_codec_capabilities == nullptr) {
299         return;
300       }
301       codecs->setPeerSourceCodecCapabilities(p_peer_codec_capabilities);
302     },
303 
304     // getCodecConfigAndCapabilities
305     [](FuzzedDataProvider* fdp) -> void {
306       std::shared_ptr<A2dpCodecs> codecs =
307           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
308       if (codecs == nullptr) {
309         return;
310       }
311 
312       // Return objects
313       std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
314       std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
315       btav_a2dp_codec_config_t codec_config;
316       codecs->getCodecConfigAndCapabilities(&codec_config,
317                                             &codecs_local_capabilities,
318                                             &codecs_selectable_capabilities);
319     },
320 
321     // debug_codec_dump
322     [](FuzzedDataProvider* fdp) -> void {
323       std::shared_ptr<A2dpCodecs> codecs =
324           getArbitraryVectorElement(fdp, a2dp_codecs_vect, false);
325       if (codecs == nullptr) {
326         return;
327       }
328 
329       // Dump this to /dev/null
330       int fd = open("/dev/null", O_WRONLY);
331       codecs->debug_codec_dump(fd);
332       close(fd);
333     },
334 
335     // Since we're dependent on having valid codec_info objects,
336     // have a change to call fuzz functions for that
337     [](FuzzedDataProvider* fdp) -> void {
338       callArbitraryCodecInfoFunction(fdp, a2dp_codec_info_operations);
339     }};
340 
341 #endif  // BT_STACK_FUZZ_A2DP_CODEC_FUNCTIONS_H_
342