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 #include <fuzzer/FuzzedDataProvider.h>
18 #include "osi/include/list.h"
19 #include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h"
20 
21 #define MAX_NUM_FUNCTIONS 512
22 #define MAX_BUF_SIZE 256
23 
24 struct list_node_t {
25   struct list_node_t* next;
26   void* data;
27 };
28 
cb(void * data)29 void cb(void* data) {}
30 // Pass a ptr to FuzzedDataProvider in context
list_iter_cb_impl(void * data,void * context)31 bool list_iter_cb_impl(void* data, void* context) {
32   FuzzedDataProvider* dataProvider =
33       reinterpret_cast<FuzzedDataProvider*>(context);
34   return dataProvider->ConsumeBool();
35 }
36 
createList(FuzzedDataProvider * dataProvider)37 list_t* createList(FuzzedDataProvider* dataProvider) {
38   bool should_callback = dataProvider->ConsumeBool();
39   if (should_callback) {
40     return list_new(cb);
41   } else {
42     return list_new(nullptr);
43   }
44 }
45 
getArbitraryElement(std::vector<void * > * vector,FuzzedDataProvider * dataProvider)46 void* getArbitraryElement(std::vector<void*>* vector,
47                           FuzzedDataProvider* dataProvider) {
48   if (vector->size() == 0) {
49     return nullptr;
50   }
51   // Get an index
52   size_t index =
53       dataProvider->ConsumeIntegralInRange<size_t>(0, vector->size() - 1);
54   return vector->at(index);
55 }
56 
getArbitraryNode(list_t * list,FuzzedDataProvider * dataProvider)57 list_node_t* getArbitraryNode(list_t* list, FuzzedDataProvider* dataProvider) {
58   if (list == nullptr || list_is_empty(list)) {
59     return nullptr;
60   }
61   size_t index =
62       dataProvider->ConsumeIntegralInRange<size_t>(0, list_length(list) - 1);
63   list_node_t* node = list_begin(list);
64   for (size_t i = 0; i < index; i++) {
65     node = node->next;
66   }
67 
68   return node;
69 }
70 
callArbitraryFunction(std::vector<void * > * list_vector,std::vector<void * > * alloc_vector,FuzzedDataProvider * dataProvider)71 void callArbitraryFunction(std::vector<void*>* list_vector,
72                            std::vector<void*>* alloc_vector,
73                            FuzzedDataProvider* dataProvider) {
74   list_t* list = nullptr;
75   // Get our function identifier
76   switch (dataProvider->ConsumeIntegralInRange<char>(0, 18)) {
77     // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer
78     // (This will likely bias whatever action is here to run more often)
79     case 0:
80       return;
81     // Create a new list
82     case 1:
83       list = createList(dataProvider);
84       list_vector->push_back(list);
85       return;
86     // Free a list
87     case 2: {
88       size_t index = 0;
89       if (list_vector->size() > 0) {
90         // Get an index
91         index = dataProvider->ConsumeIntegralInRange<size_t>(
92             0, list_vector->size() - 1);
93         list = reinterpret_cast<list_t*>(list_vector->at(index));
94       }
95       list_free(list);
96       // Otherwise free a valid list
97       if (list != nullptr) {
98         list_vector->erase(list_vector->begin() + index);
99       }
100       return;
101     }
102     case 3:
103       list = reinterpret_cast<list_t*>(
104           getArbitraryElement(list_vector, dataProvider));
105       if (list != nullptr) {
106         list_is_empty(list);
107       }
108       return;
109     case 4:
110       list = reinterpret_cast<list_t*>(
111           getArbitraryElement(list_vector, dataProvider));
112       if (list != nullptr) {
113         void* search_buf = getArbitraryElement(alloc_vector, dataProvider);
114         if (search_buf != nullptr) {
115           list_contains(list, search_buf);
116         }
117       }
118       return;
119     case 5:
120       list = reinterpret_cast<list_t*>(
121           getArbitraryElement(list_vector, dataProvider));
122       if (list != nullptr) {
123         list_length(list);
124       }
125       return;
126     case 6:
127       list = reinterpret_cast<list_t*>(
128           getArbitraryElement(list_vector, dataProvider));
129       if (list != nullptr && !list_is_empty(list)) {
130         list_front(list);
131       }
132       return;
133     case 7:
134       list = reinterpret_cast<list_t*>(
135           getArbitraryElement(list_vector, dataProvider));
136       if (list != nullptr && !list_is_empty(list)) {
137         list_back(list);
138       }
139       return;
140     case 8:
141       list = reinterpret_cast<list_t*>(
142           getArbitraryElement(list_vector, dataProvider));
143       if (list != nullptr && !list_is_empty(list)) {
144         list_back_node(list);
145       }
146       return;
147     case 9: {
148       list = reinterpret_cast<list_t*>(
149           getArbitraryElement(list_vector, dataProvider));
150       if (list == nullptr) {
151         return;
152       }
153       void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false);
154       alloc_vector->push_back(buf);
155       list_node_t* node = getArbitraryNode(list, dataProvider);
156       if (node != nullptr && buf != nullptr) {
157         list_insert_after(list, node, buf);
158       }
159       return;
160     }
161     case 10: {
162       list = reinterpret_cast<list_t*>(
163           getArbitraryElement(list_vector, dataProvider));
164       void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false);
165       alloc_vector->push_back(buf);
166       if (list != nullptr && buf != nullptr) {
167         list_prepend(list, buf);
168       }
169       return;
170     }
171     case 11: {
172       list = reinterpret_cast<list_t*>(
173           getArbitraryElement(list_vector, dataProvider));
174       void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false);
175       alloc_vector->push_back(buf);
176       if (list != nullptr && buf != nullptr) {
177         list_append(list, buf);
178       }
179       return;
180     }
181     case 12: {
182       list = reinterpret_cast<list_t*>(
183           getArbitraryElement(list_vector, dataProvider));
184       // The buffer will be valid, but may be for a different list
185       void* buf = getArbitraryElement(alloc_vector, dataProvider);
186       if (list != nullptr && buf != nullptr) {
187         list_remove(list, buf);
188       }
189       return;
190     }
191     case 13:
192       list = reinterpret_cast<list_t*>(
193           getArbitraryElement(list_vector, dataProvider));
194       if (list != nullptr) {
195         list_clear(list);
196       }
197       return;
198     case 14:
199       list = reinterpret_cast<list_t*>(
200           getArbitraryElement(list_vector, dataProvider));
201       if (list != nullptr) {
202         list_foreach(list, list_iter_cb_impl, dataProvider);
203       }
204       return;
205     case 15:
206       list = reinterpret_cast<list_t*>(
207           getArbitraryElement(list_vector, dataProvider));
208       if (list != nullptr) {
209         list_begin(list);
210       }
211       return;
212     case 16:
213       list = reinterpret_cast<list_t*>(
214           getArbitraryElement(list_vector, dataProvider));
215       if (list != nullptr) {
216         list_end(list);
217       }
218       return;
219     case 17: {
220       list = reinterpret_cast<list_t*>(
221           getArbitraryElement(list_vector, dataProvider));
222       if (list == nullptr) {
223         return;
224       }
225       list_node_t* node = getArbitraryNode(list, dataProvider);
226       if (node != nullptr) {
227         list_next(node);
228       }
229       return;
230     }
231     case 18: {
232       list = reinterpret_cast<list_t*>(
233           getArbitraryElement(list_vector, dataProvider));
234       if (list == nullptr) {
235         return;
236       }
237       list_node_t* node = getArbitraryNode(list, dataProvider);
238       if (node != nullptr && node != list_end(list)) {
239         list_node(node);
240       }
241       return;
242     }
243     default:
244       return;
245   }
246 }
247 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)248 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
249   // Init our wrapper
250   FuzzedDataProvider dataProvider(Data, Size);
251 
252   // Keep a vector of our allocated objects for freeing later
253   std::vector<void*> list_vector;
254   std::vector<void*> alloc_vector;
255 
256   // Call some functions, create some buffers
257   size_t num_functions =
258       dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
259   for (size_t i = 0; i < num_functions; i++) {
260     callArbitraryFunction(&list_vector, &alloc_vector, &dataProvider);
261   }
262 
263   // Free anything we've allocated
264   for (const auto& list : list_vector) {
265     if (list != nullptr) {
266       list_free(reinterpret_cast<list_t*>(list));
267     }
268   }
269   for (const auto& alloc : alloc_vector) {
270     if (alloc != nullptr) {
271       free(alloc);
272     }
273   }
274   list_vector.clear();
275 
276   return 0;
277 }
278