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