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/allocator.h"
19 #include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h"
20 
21 #define MAX_NUM_FUNCTIONS 512
22 #define MAX_BUF_SIZE 256
23 
callArbitraryFunction(std::vector<void * > * alloc_vector,FuzzedDataProvider * dataProvider)24 void callArbitraryFunction(std::vector<void*>* alloc_vector,
25                            FuzzedDataProvider* dataProvider) {
26   // Get our function identifier
27   char func_id = dataProvider->ConsumeIntegralInRange<char>(0, 6);
28 
29   switch (func_id) {
30     // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer
31     // (This will likely bias whatever action is here to run more often)
32     case 0:
33       return;
34     // Let case 1 be osi_malloc, and 2 be osi_calloc
35     case 1:
36     case 2: {
37       size_t size =
38           dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE);
39       void* ptr = nullptr;
40       if (size == 0) {
41         return;
42       }
43       if (func_id == 1) {
44         ptr = osi_malloc(size);
45       } else {
46         ptr = osi_calloc(size);
47       }
48       if (ptr) {
49         alloc_vector->push_back(ptr);
50       }
51     }
52       return;
53     // Let case 3 be osi_free, and 4 be osi_free_and_reset
54     case 3:
55     case 4: {
56       if (alloc_vector->size() == 0) {
57         return;
58       }
59       size_t index = dataProvider->ConsumeIntegralInRange<size_t>(
60           0, alloc_vector->size() - 1);
61       void* ptr = alloc_vector->at(index);
62       if (ptr) {
63         if (func_id == 3) {
64           osi_free(ptr);
65         } else {
66           osi_free_and_reset(&ptr);
67         }
68       }
69       alloc_vector->erase(alloc_vector->begin() + index);
70     }
71       return;
72     // Let case 5 be osi_strdup, and 6 be osi_strdup
73     case 5:
74     case 6: {
75       // Make a src buffer
76       char* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, true);
77       char* str = nullptr;
78       if (buf == nullptr) {
79         return;
80       }
81       if (func_id == 5) {
82         str = osi_strdup(buf);
83       } else {
84         size_t size =
85             dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE);
86         str = osi_strndup(buf, size);
87       }
88       free(buf);
89       if (str) {
90         alloc_vector->push_back(str);
91       }
92     }
93       return;
94     default:
95       return;
96   }
97 }
98 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)99 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
100   // Init our wrapper
101   FuzzedDataProvider dataProvider(Data, Size);
102 
103   // Keep a vector of our allocated objects for freeing later
104   std::vector<void*> alloc_vector;
105   // Call some functions, create some buffers
106   size_t num_functions =
107       dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
108   for (size_t i = 0; i < num_functions; i++) {
109     callArbitraryFunction(&alloc_vector, &dataProvider);
110   }
111   // Free anything we've allocated
112   for (const auto& alloc : alloc_vector) {
113     if (alloc != nullptr) {
114       osi_free(alloc);
115     }
116   }
117   alloc_vector.clear();
118   return 0;
119 }
120