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