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 <sys/select.h>
19
20 #include "osi/include/fixed_queue.h"
21 #include "osi/include/future.h"
22 #include "osi/include/thread.h"
23 #include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h"
24
25 #define MAX_START_SIZE 2048
26 #define MAX_NUM_FUNCTIONS 512
27 #define MAX_BUF_SIZE 512
28
29 static future_t* received_message_future = nullptr;
30
31 // Empty callback function
fqFreeCb(void *)32 void fqFreeCb(void* /*data*/) {}
fqCb(fixed_queue_t * queue,void *)33 void fqCb(fixed_queue_t* queue, void* /*data*/) {
34 void* msg = fixed_queue_try_dequeue(queue);
35 future_ready(received_message_future, msg);
36 }
37
38 // Returns either a nullptr or a function ptr to the placeholder cb function
cbOrNull(FuzzedDataProvider * dataProvider)39 fixed_queue_free_cb cbOrNull(FuzzedDataProvider* dataProvider) {
40 bool null_cb = dataProvider->ConsumeBool();
41 if (null_cb) {
42 return nullptr;
43 } else {
44 return fqFreeCb;
45 }
46 }
47
fdIsAvailable(int fd)48 bool fdIsAvailable(int fd) {
49 int nfds = 1;
50 fd_set readfds, writefds, exceptfds;
51 timeval timeout;
52
53 FD_ZERO(&readfds);
54 FD_ZERO(&writefds);
55 FD_ZERO(&exceptfds);
56 FD_SET(fd, &readfds);
57 timeout.tv_sec = 0;
58 timeout.tv_usec = 50;
59
60 return select(nfds, &readfds, &writefds, &exceptfds, &timeout) > 0;
61 }
62
createNewFuture()63 void createNewFuture() {
64 // Free the existing future if it exists
65 if (received_message_future != nullptr) {
66 future_ready(received_message_future, nullptr);
67 future_await(received_message_future);
68 }
69
70 // Create a new one
71 received_message_future = future_new();
72 }
73
callArbitraryFunction(fixed_queue_t * fixed_queue,std::vector<void * > * live_buffer_vector,std::vector<thread_t * > *,FuzzedDataProvider * dataProvider)74 void callArbitraryFunction(fixed_queue_t* fixed_queue, std::vector<void*>* live_buffer_vector,
75 std::vector<thread_t*>* /*live_thread_vector*/,
76 FuzzedDataProvider* dataProvider) {
77 void* buf_ptr = nullptr;
78 size_t index = 0;
79 int fd = 0;
80 // Get our function identifier
81 switch (dataProvider->ConsumeIntegralInRange<char>(0, 17)) {
82 // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer
83 // (This will likely bias whatever action is here to run more often)
84 case 0:
85 return;
86 // Clear the queue
87 case 1:
88 fixed_queue_flush(fixed_queue, cbOrNull(dataProvider));
89 return;
90 // Check if empty
91 case 2:
92 fixed_queue_is_empty(fixed_queue);
93 return;
94 // Check length
95 case 3:
96 fixed_queue_length(fixed_queue);
97 return;
98 // Check capacity (Cannot be null)
99 case 4:
100 if (fixed_queue) {
101 fixed_queue_capacity(fixed_queue);
102 }
103 return;
104 // Add to the queue (Cannot be null)
105 case 5:
106 if (fixed_queue) {
107 buf_ptr = generateBuffer(dataProvider, MAX_BUF_SIZE, false);
108 live_buffer_vector->push_back(buf_ptr);
109 if (buf_ptr) {
110 // Make sure we won't block
111 fd = fixed_queue_get_enqueue_fd(fixed_queue);
112 if (fdIsAvailable(fd)) {
113 fixed_queue_enqueue(fixed_queue, buf_ptr);
114 }
115 }
116 }
117 return;
118 case 6:
119 if (fixed_queue) {
120 buf_ptr = generateBuffer(dataProvider, MAX_BUF_SIZE, false);
121 live_buffer_vector->push_back(buf_ptr);
122 if (buf_ptr) {
123 fixed_queue_try_enqueue(fixed_queue, buf_ptr);
124 }
125 }
126 return;
127 // Remove from the queue (Cannot be null)
128 case 7:
129 if (fixed_queue && fixed_queue_length(fixed_queue) > 0) {
130 fixed_queue_dequeue(fixed_queue);
131 }
132 return;
133 case 8:
134 if (fixed_queue) {
135 fixed_queue_try_dequeue(fixed_queue);
136 }
137 return;
138 // Peeks
139 case 9:
140 fixed_queue_try_peek_first(fixed_queue);
141 return;
142 case 10:
143 fixed_queue_try_peek_last(fixed_queue);
144 return;
145 // Try to remove existing specific element
146 case 11:
147 if (live_buffer_vector->empty()) {
148 return;
149 }
150 // Grab an existing buffer
151 index = dataProvider->ConsumeIntegralInRange<size_t>(0, live_buffer_vector->size() - 1);
152 buf_ptr = live_buffer_vector->at(index);
153 if (buf_ptr != nullptr) {
154 fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr);
155 }
156 return;
157 // Try to remove nonexistant element
158 case 12:
159 buf_ptr = reinterpret_cast<void*>(dataProvider->ConsumeIntegral<uint64_t>());
160 if (buf_ptr != nullptr) {
161 fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr);
162 }
163 return;
164 // Convert the queue to a list (Cannot be null)
165 case 13:
166 if (fixed_queue) {
167 fixed_queue_get_list(fixed_queue);
168 }
169 return;
170 // Check if enqueue is blocking
171 case 14:
172 fixed_queue_get_enqueue_fd(fixed_queue);
173 return;
174 // Check if dequeue is blocking
175 case 15:
176 fixed_queue_get_dequeue_fd(fixed_queue);
177 return;
178 // NOTE: thread appears to have a memleak, disabling this for now.
179 case 16:
180 // if (fixed_queue) {
181 // createNewFuture();
182 // // Start up a thread and register with it.
183 // thread_t* tmp_thread = thread_new(
184 // dataProvider->ConsumeRandomLengthString().c_str());
185 // if (tmp_thread == nullptr) {
186 // return;
187 // }
188 // live_thread_vector->push_back(tmp_thread);
189 // reactor_t* reactor = thread_get_reactor(tmp_thread);
190 // if (reactor == nullptr) {
191 // return;
192 // }
193 // fixed_queue_register_dequeue(fixed_queue, reactor, fqCb, nullptr);
194 // fixed_queue_enqueue(fixed_queue, (void*)"test");
195 // future_await(received_message_future);
196 // }
197 return;
198 case 17:
199 fixed_queue_unregister_dequeue(fixed_queue);
200 return;
201 default:
202 return;
203 }
204 }
205
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)206 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
207 // Init our wrapper
208 FuzzedDataProvider dataProvider(Data, Size);
209
210 // Make vectors to keep track of objects we generate, for freeing
211 std::vector<void*> live_buffer_vector;
212 std::vector<thread_t*> live_thread_vector;
213
214 size_t start_capacity = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_START_SIZE);
215 fixed_queue_t* fixed_queue = fixed_queue_new(start_capacity);
216
217 // How many functions are we going to call?
218 size_t num_functions = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
219 for (size_t i = 0; i < num_functions; i++) {
220 callArbitraryFunction(fixed_queue, &live_buffer_vector, &live_thread_vector, &dataProvider);
221 }
222
223 // Free our queue (with either a null or placeholder callback)
224 fixed_queue_free(fixed_queue, cbOrNull(&dataProvider));
225
226 // Free buffers we've created through fn calls during this fuzzer loop.
227 for (const auto& buffer : live_buffer_vector) {
228 free(buffer);
229 }
230 for (const auto& thread : live_thread_vector) {
231 thread_free(thread);
232 }
233
234 return 0;
235 }
236