• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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