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