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