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