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 #include "osi/include/fixed_queue.h"
20 #include "osi/include/future.h"
21 #include "osi/include/thread.h"
22 #include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h"
23
24 #define MAX_START_SIZE 2048
25 #define MAX_NUM_FUNCTIONS 512
26 #define MAX_BUF_SIZE 512
27
28 static future_t* received_message_future = nullptr;
29
30 // Empty callback function
fqFreeCb(void * data)31 void fqFreeCb(void* data) {}
fqCb(fixed_queue_t * queue,void * data)32 void fqCb(fixed_queue_t* queue, void* data) {
33 void* msg = fixed_queue_try_dequeue(queue);
34 future_ready(received_message_future, msg);
35 }
36
37 // Returns either a nullptr or a function ptr to the placeholder cb function
cbOrNull(FuzzedDataProvider * dataProvider)38 fixed_queue_free_cb cbOrNull(FuzzedDataProvider* dataProvider) {
39 bool null_cb = dataProvider->ConsumeBool();
40 if (null_cb) {
41 return nullptr;
42 } else {
43 return fqFreeCb;
44 }
45 }
46
fdIsAvailable(int fd)47 bool fdIsAvailable(int fd) {
48 int nfds = 1;
49 fd_set readfds, writefds, exceptfds;
50 timeval timeout;
51
52 FD_ZERO(&readfds);
53 FD_ZERO(&writefds);
54 FD_ZERO(&exceptfds);
55 FD_SET(fd, &readfds);
56 timeout.tv_sec = 0;
57 timeout.tv_usec = 50;
58
59 return select(nfds, &readfds, &writefds, &exceptfds, &timeout) > 0;
60 }
61
createNewFuture()62 void createNewFuture() {
63 // Free the existing future if it exists
64 if (received_message_future != nullptr) {
65 future_ready(received_message_future, nullptr);
66 future_await(received_message_future);
67 }
68
69 // Create a new one
70 received_message_future = future_new();
71 }
72
callArbitraryFunction(fixed_queue_t * fixed_queue,std::vector<void * > * live_buffer_vector,std::vector<thread_t * > * live_thread_vector,FuzzedDataProvider * dataProvider)73 void callArbitraryFunction(fixed_queue_t* fixed_queue,
74 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>(
152 0, live_buffer_vector->size() - 1);
153 buf_ptr = live_buffer_vector->at(index);
154 if (buf_ptr != nullptr) {
155 fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr);
156 }
157 return;
158 // Try to remove nonexistant element
159 case 12:
160 buf_ptr =
161 reinterpret_cast<void*>(dataProvider->ConsumeIntegral<uint64_t>());
162 if (buf_ptr != nullptr) {
163 fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr);
164 }
165 return;
166 // Convert the queue to a list (Cannot be null)
167 case 13:
168 if (fixed_queue) {
169 fixed_queue_get_list(fixed_queue);
170 }
171 return;
172 // Check if enqueue is blocking
173 case 14:
174 fixed_queue_get_enqueue_fd(fixed_queue);
175 return;
176 // Check if dequeue is blocking
177 case 15:
178 fixed_queue_get_dequeue_fd(fixed_queue);
179 return;
180 // NOTE: thread appears to have a memleak, disabling this for now.
181 case 16:
182 // if (fixed_queue) {
183 // createNewFuture();
184 // // Start up a thread and register with it.
185 // thread_t* tmp_thread = thread_new(
186 // dataProvider->ConsumeRandomLengthString().c_str());
187 // if (tmp_thread == nullptr) {
188 // return;
189 // }
190 // live_thread_vector->push_back(tmp_thread);
191 // reactor_t* reactor = thread_get_reactor(tmp_thread);
192 // if (reactor == nullptr) {
193 // return;
194 // }
195 // fixed_queue_register_dequeue(fixed_queue, reactor, fqCb, nullptr);
196 // fixed_queue_enqueue(fixed_queue, (void*)"test");
197 // future_await(received_message_future);
198 // }
199 return;
200 case 17:
201 fixed_queue_unregister_dequeue(fixed_queue);
202 return;
203 default:
204 return;
205 }
206 }
207
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)208 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
209 // Init our wrapper
210 FuzzedDataProvider dataProvider(Data, Size);
211
212 // Make vectors to keep track of objects we generate, for freeing
213 std::vector<void*> live_buffer_vector;
214 std::vector<thread_t*> live_thread_vector;
215
216 size_t start_capacity =
217 dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_START_SIZE);
218 fixed_queue_t* fixed_queue = fixed_queue_new(start_capacity);
219
220 // How many functions are we going to call?
221 size_t num_functions =
222 dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
223 for (size_t i = 0; i < num_functions; i++) {
224 callArbitraryFunction(fixed_queue, &live_buffer_vector, &live_thread_vector,
225 &dataProvider);
226 }
227
228 // Free our queue (with either a null or placeholder callback)
229 fixed_queue_free(fixed_queue, cbOrNull(&dataProvider));
230
231 // Free buffers we've created through fn calls during this fuzzer loop.
232 for (const auto& buffer : live_buffer_vector) {
233 free(buffer);
234 }
235 for (const auto& thread : live_thread_vector) {
236 thread_free(thread);
237 }
238
239 return 0;
240 }
241