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/ringbuffer.h"
19 
20 #define MAX_NUM_FUNCTIONS 512
21 #define MAX_BUF_SIZE 2048
22 
getArbitraryRingBuf(std::vector<ringbuffer_t * > * ringbuf_vector,FuzzedDataProvider * dataProvider)23 ringbuffer_t* getArbitraryRingBuf(std::vector<ringbuffer_t*>* ringbuf_vector,
24                                   FuzzedDataProvider* dataProvider) {
25   if (ringbuf_vector->empty()) {
26     return nullptr;
27   }
28 
29   size_t index = dataProvider->ConsumeIntegralInRange<size_t>(
30       0, ringbuf_vector->size() - 1);
31   return ringbuf_vector->at(index);
32 }
33 
callArbitraryFunction(std::vector<ringbuffer_t * > * ringbuf_vector,FuzzedDataProvider * dataProvider)34 void callArbitraryFunction(std::vector<ringbuffer_t*>* ringbuf_vector,
35                            FuzzedDataProvider* dataProvider) {
36   // Get our function identifier
37   char func_id = dataProvider->ConsumeIntegralInRange<char>(0, 8);
38 
39   ringbuffer_t* buf = nullptr;
40   switch (func_id) {
41     // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer
42     // (This will likely bias whatever action is here to run more often)
43     case 0:
44       return;
45     case 1: {
46       size_t size =
47           dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE);
48       buf = ringbuffer_init(size);
49       if (buf) {
50         ringbuf_vector->push_back(buf);
51       }
52     }
53       return;
54     case 2: {
55       if (ringbuf_vector->empty()) {
56         return;
57       }
58       size_t index = dataProvider->ConsumeIntegralInRange<size_t>(
59           0, ringbuf_vector->size() - 1);
60       buf = ringbuf_vector->at(index);
61       if (buf) {
62         ringbuffer_free(buf);
63         ringbuf_vector->erase(ringbuf_vector->begin() + index);
64       }
65     }
66       return;
67     case 3:
68       buf = getArbitraryRingBuf(ringbuf_vector, dataProvider);
69       if (buf) {
70         ringbuffer_available(buf);
71       }
72       return;
73     case 4:
74       buf = getArbitraryRingBuf(ringbuf_vector, dataProvider);
75       if (buf) {
76         ringbuffer_size(buf);
77       }
78       return;
79     case 5: {
80       buf = getArbitraryRingBuf(ringbuf_vector, dataProvider);
81       size_t size =
82           dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE);
83       if (buf == nullptr || size == 0) {
84         return;
85       }
86       void* src_buf = malloc(size);
87       if (src_buf == nullptr) {
88         return;
89       }
90       std::vector<uint8_t> bytes = dataProvider->ConsumeBytes<uint8_t>(size);
91       memcpy(src_buf, bytes.data(), bytes.size());
92 
93       ringbuffer_insert(buf, reinterpret_cast<uint8_t*>(src_buf), size);
94       free(src_buf);
95     }
96       return;
97     case 6:
98     case 7: {
99       buf = getArbitraryRingBuf(ringbuf_vector, dataProvider);
100       if (buf == nullptr) {
101         return;
102       }
103       size_t max_size = ringbuffer_size(buf);
104       if (max_size == 0) {
105         return;
106       }
107       size_t size = dataProvider->ConsumeIntegralInRange<size_t>(1, max_size);
108 
109       // NOTE: 0-size may be a valid case, that crashes currently.
110       if (size == 0) {
111         return;
112       }
113 
114       void* dst_buf = malloc(size);
115       if (dst_buf == nullptr) {
116         return;
117       }
118       if (func_id == 6) {
119         off_t offset = dataProvider->ConsumeIntegral<off_t>();
120         if (offset >= 0 &&
121             static_cast<size_t>(offset) <= ringbuffer_size(buf)) {
122           ringbuffer_peek(buf, offset, reinterpret_cast<uint8_t*>(dst_buf),
123                           size);
124         }
125       } else {
126         ringbuffer_pop(buf, reinterpret_cast<uint8_t*>(dst_buf), size);
127       }
128       free(dst_buf);
129     }
130       return;
131     case 8: {
132       buf = getArbitraryRingBuf(ringbuf_vector, dataProvider);
133       size_t size =
134           dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE);
135       if (buf) {
136         ringbuffer_delete(buf, size);
137       }
138     }
139       return;
140     default:
141       return;
142   }
143 }
144 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)145 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
146   // Init our wrapper
147   FuzzedDataProvider dataProvider(Data, Size);
148 
149   // Keep a vector of our allocated objects for freeing later
150   std::vector<ringbuffer_t*> ringbuf_vector;
151 
152   // Call some functions, create some buffers
153   size_t num_functions =
154       dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
155   for (size_t i = 0; i < num_functions; i++) {
156     callArbitraryFunction(&ringbuf_vector, &dataProvider);
157   }
158 
159   // Free anything we've allocated
160   for (const auto& ringbuf : ringbuf_vector) {
161     if (ringbuf != nullptr) {
162       ringbuffer_free(ringbuf);
163     }
164   }
165   ringbuf_vector.clear();
166   return 0;
167 }
168