• 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 // Don't lint the next line, as cpplint will suggest adding
18 // /tools/security as an include_dir
19 // NOLINTNEXTLINE
20 #include "fuzz_ffi.h"
21 
22 #include <vector>
23 #include "include/ffi_common.h"
24 
25 // Empty functions we can use for our function targets
fn(int num_args,...)26 void fn(int num_args, ...) {}
closure_fn(ffi_cif * cif __UNUSED__,void * resp,void ** args,void * userdata)27 void closure_fn(ffi_cif* cif __UNUSED__,
28         void* resp, void** args, void* userdata) {}
raw_closure_fn(ffi_cif * cif __UNUSED__,void * resp,ffi_raw * args,void * userdata)29 void raw_closure_fn(ffi_cif* cif __UNUSED__,
30         void* resp, ffi_raw* args, void* userdata) {}
java_raw_closure_fn(ffi_cif * cif __UNUSED__,void * resp,ffi_java_raw * args,void * userdata)31 void java_raw_closure_fn(ffi_cif* cif __UNUSED__,
32         void* resp, ffi_java_raw* args, void* userdata) {}
33 
generateCustomType(FuzzedDataProvider * dataProvider)34 ffi_type* generateCustomType(FuzzedDataProvider* dataProvider) {
35     // Set our flag so we don't call a java-related function (triggers an abort)
36     args_contain_struct = true;
37 
38     ffi_type* new_type = reinterpret_cast<ffi_type*>(malloc(sizeof(ffi_type)));
39     ffi_alloc_vector.push_back(new_type);
40 
41     new_type->size = 0;
42     new_type->alignment = 0;
43     new_type->type = FFI_TYPE_STRUCT;
44 
45     // Generate our subobjects
46     size_t num_elements = dataProvider->ConsumeIntegralInRange<size_t>(0,
47             MAX_NUM_ELEMENTS);
48     new_type->elements = reinterpret_cast<ffi_type**>(
49             malloc(sizeof(ffi_type*)*(num_elements+1)));
50 
51     // Nested custom structs will cause an assert, so disable them
52     // TODO(michael.ensing@leviathansecurity.com):
53     //     change the 'false' here to true once libffi supports nested structs.
54     //     It'll just throw an assert currently.
55     for (size_t i=0; i < num_elements; i++) {
56         new_type->elements[i] = getRandomType(dataProvider, false);
57     }
58 
59     // The final element must be a nullptr
60     new_type->elements[num_elements] = NULL;
61 
62     // Get our size/alignment
63     ffi_get_struct_offsets(abi, new_type, NULL);
64 
65     return new_type;
66 }
67 
getTotalSize(ffi_type * type)68 size_t getTotalSize(ffi_type* type) {
69     if (type == NULL) {
70         return 0;
71     }
72 
73     // Start the total as the size of the object itself
74     size_t total_size = type->size > WORDSIZE_BYTES ?
75             type->size : WORDSIZE_BYTES;
76 
77     // Recursively add the size of the subelements
78     if (type->elements != NULL) {
79         for (size_t i=0; type->elements[i] != NULL; i++) {
80             total_size += getTotalSize(type->elements[i]);
81         }
82     }
83 
84     return total_size;
85 }
86 
getRandomType(FuzzedDataProvider * dataProvider,bool allowCustomTypes)87 ffi_type* getRandomType(FuzzedDataProvider* dataProvider,
88         bool allowCustomTypes) {
89     // Which type? Let type==NUM_TYPES be our custom struct case
90     size_t type_index = dataProvider->ConsumeIntegralInRange<size_t>(0,
91             NUM_TYPES);
92     ffi_type* type;
93     if (type_index == NUM_TYPES) {
94         if (allowCustomTypes) {
95             type = generateCustomType(dataProvider);
96         } else {
97             return NULL;
98         }
99     } else {
100         type = ffi_types[type_index];
101     }
102 
103     return type;
104 }
105 
genArg(ffi_type * type,FuzzedDataProvider * dataProvider)106 void* genArg(ffi_type* type, FuzzedDataProvider* dataProvider) {
107     // Allocate the space for our arg
108     // TODO(michael.ensing@leviathansecurity.com):
109     //    Properly allocate the correct amount of aligned-space,
110     //    don't just double (which should contain any alignment)
111     size_t type_size = getTotalSize(type)*2;
112 
113     if (type_size == 0) {
114         return NULL;
115     }
116 
117     void* ret = malloc(type_size);
118 
119     std::vector<uint8_t> bytes = dataProvider->ConsumeBytes<uint8_t>(type_size);
120     memcpy(ret, bytes.data(), bytes.size());
121 
122     return ret;
123 }
124 
buildArgArrays(ffi_type * arg_types[],void * arg_array[],size_t num_args,FuzzedDataProvider * dataProvider)125 bool buildArgArrays(ffi_type* arg_types[], void* arg_array[], size_t num_args,
126         FuzzedDataProvider* dataProvider) {
127     // The first value in our array should be the number of arguments
128     arg_types[0] = &ffi_type_sint;
129     size_t* size_ptr = reinterpret_cast<size_t*>(malloc(sizeof(size_t)));
130     *size_ptr = num_args;
131     arg_array[0] = size_ptr;
132 
133     // Grab our arguments
134     for (size_t i = 1; i <= num_args; i++) {
135         // Determine what type we're using
136         ffi_type* type = getRandomType(dataProvider, true);
137         if (type == NULL) {
138             return false;
139         }
140         arg_types[i] = type;
141 
142         // Generate a value for it and add to our arguments array
143         arg_array[i] = genArg(type, dataProvider);
144     }
145 
146     // Our arrays of pointers need to be nullptr-terminated
147     arg_types[num_args+1] = NULL;
148     arg_array[num_args+1] = NULL;
149 
150     return true;
151 }
152 
runMainFunctions(ffi_cif * cif,void * resp_buf,void ** arg_array,FuzzedDataProvider * dataProvider)153 void runMainFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
154         FuzzedDataProvider* dataProvider) {
155     // Call function
156     ffi_call(cif, FFI_FN(fn), resp_buf, arg_array);
157 
158     // Prep Closure
159     ffi_closure* pcl = NULL;
160     void* code;
161     ffi_status ret;
162 
163     pcl = reinterpret_cast<ffi_closure*>(
164             ffi_closure_alloc(sizeof(ffi_closure), &code));
165     if (pcl == NULL) {
166         return;
167     }
168 
169     size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
170             MAX_RESP_SIZE);
171     std::vector<uint8_t> data_vector =
172             dataProvider->ConsumeBytes<uint8_t>(buf_size);
173     ret = ffi_prep_closure_loc(
174             pcl,
175             cif,
176             closure_fn,
177             data_vector.data(),
178             code);
179     if (ret != FFI_OK) {
180         ffi_closure_free(pcl);
181     }
182 }
183 
runRawFunctions(ffi_cif * cif,void * resp_buf,void ** arg_array,FuzzedDataProvider * dataProvider)184 void runRawFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
185         FuzzedDataProvider* dataProvider) {
186     #if !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
187     // Allocate our ffi_raw and put our args there
188     size_t rsize = ffi_raw_size(cif);
189     ffi_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize));
190     raw_alloc_vector.push_back(raw_args);
191     ffi_ptrarray_to_raw(cif, arg_array, raw_args);
192 
193     // Call
194     ffi_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
195 
196     // Prep Closure
197     #if FFI_CLOSURES
198     ffi_raw_closure* pcl = NULL;
199     void* code;
200     ffi_status ret;
201 
202     pcl = static_cast<ffi_raw_closure*>(
203             ffi_closure_alloc(sizeof(ffi_raw_closure), &code));
204     if (pcl == NULL) {
205         return;
206     }
207     size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
208             MAX_RESP_SIZE);
209     std::vector<uint8_t> data_vector =
210             dataProvider->ConsumeBytes<uint8_t>(buf_size);
211     ret = ffi_prep_raw_closure_loc(
212             pcl,
213             cif,
214             raw_closure_fn,
215             data_vector.data(),
216             code);
217     if (ret != FFI_OK) {
218         ffi_closure_free(pcl);
219     }
220 
221     #endif  // FFI_CLOSURES
222     #endif  // !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
223 }
224 
runJavaFunctions(ffi_cif * cif,void * resp_buf,void ** arg_array,FuzzedDataProvider * dataProvider)225 void runJavaFunctions(ffi_cif* cif, void* resp_buf, void** arg_array,
226         FuzzedDataProvider* dataProvider) {
227     #if !defined(NO_JAVA_RAW_API)
228     #if  !FFI_NO_RAW_API && !FFI_NATIVE_RAW_API
229 
230     // Allocate our ffi_java_raw and put our args there
231     size_t rsize = ffi_java_raw_size(cif);
232     // NOTE: a buffer overread will occasionally happen if we don't
233     //       increase rsize.
234     ffi_java_raw* raw_args = reinterpret_cast<ffi_raw*>(malloc(rsize*2));
235     raw_alloc_vector.push_back(raw_args);
236     ffi_ptrarray_to_raw(cif, arg_array, raw_args);
237 
238     // Call
239     ffi_java_raw_call(cif, FFI_FN(fn), resp_buf, raw_args);
240 
241     // Prep Closure
242     #if FFI_CLOSURES
243     ffi_java_raw_closure* pcl = NULL;
244     void* code;
245     ffi_status ret;
246 
247     pcl = static_cast<ffi_java_raw_closure*>(
248             ffi_closure_alloc(sizeof(ffi_java_raw_closure), &code));
249     if (pcl == NULL) {
250         return;
251     }
252     size_t buf_size = dataProvider->ConsumeIntegralInRange<size_t>(0,
253             MAX_RESP_SIZE);
254     std::vector<uint8_t> data_vector =
255             dataProvider->ConsumeBytes<uint8_t>(buf_size);
256     ret = ffi_prep_java_raw_closure_loc(
257             pcl,
258             cif,
259             raw_closure_fn,
260             data_vector.data(),
261             code);
262     if (ret != FFI_OK) {
263         ffi_closure_free(pcl);
264     }
265 
266     #endif  // FFI_CLOSURES
267     #endif  // !FFI_NATIVE_RAW_API
268     #endif  // !NO_JAVA_RAW_API
269 }
270 
freeFFI(ffi_type * ffi_type)271 void freeFFI(ffi_type* ffi_type) {
272     // Make sure it's one of our structs
273     if (ffi_type == NULL || ffi_type->type != FFI_TYPE_STRUCT) {
274         return;
275     }
276 
277     if (ffi_type->elements != NULL) {
278         free(ffi_type->elements);
279     }
280 
281     // Finally, free our object
282     free(ffi_type);
283 }
284 
freeAll(void * arg_array[],size_t num_args,void * resp_buf)285 void freeAll(void* arg_array[], size_t num_args, void* resp_buf) {
286     // Free our custom struct objects
287     for (const auto& ffi : ffi_alloc_vector) {
288         freeFFI(ffi);
289     }
290     ffi_alloc_vector.clear();
291     for (const auto& raw : raw_alloc_vector) {
292         free(raw);
293     }
294     raw_alloc_vector.clear();
295 
296     for (size_t i=0; i <= num_args; i++) {
297         free(arg_array[i]);
298     }
299 
300     if (resp_buf) {
301         free(resp_buf);
302     }
303 }
304 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)305 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
306     // Init our wrapper
307     FuzzedDataProvider dataProvider(Data, Size);
308     ffi_cif cif;
309     ffi_status ret;
310     void* resp_buf = NULL;
311     args_contain_struct = false;
312     ffi_type* rtype;
313 
314     // How many args are we sending?
315     size_t num_args = dataProvider.ConsumeIntegralInRange<size_t>(0,
316             MAX_NUM_ARGS);
317 
318     // Build our array of args (+2 for leading arg_count and trailing nullptr)
319     ffi_type* arg_types[num_args+2];
320     void* arg_array[num_args+2];
321     bool success = buildArgArrays(arg_types, arg_array, num_args,
322             &dataProvider);
323     if (!success) {
324         goto free;
325     }
326 
327     // Get return type
328     rtype = dataProvider.PickValueInArray<ffi_type*, NUM_TYPES>(ffi_types);
329 
330     // Create a buffer for our return value
331     resp_buf = malloc(MAX_RESP_SIZE);
332     if (resp_buf == NULL) {
333         goto free;
334     }
335 
336     // Set up our ABI
337     // NOTE: fuzzing abi triggers an abort on linux-x86_64,
338     //       so only fuzz it on ARM
339     #if MAX_ABI > 0 && defined(ARM)
340     abi = static_cast<ffi_abi>(
341            dataProvider.ConsumeIntegralInRange<uint32_t>(0, MAX_ABI));
342     #endif
343     #if HAVE_LONG_DOUBLE_VARIANT
344     ffi_prep_types(abi);
345     #endif
346 
347     // ============= Call Functions =============
348     ret = ffi_prep_cif_var(&cif, abi, 1, num_args, rtype,
349             arg_types);
350     if (ret != FFI_OK) {
351         goto free;
352     }
353 
354     runMainFunctions(&cif, resp_buf, arg_array, &dataProvider);
355     runRawFunctions(&cif, resp_buf, arg_array, &dataProvider);
356     if (!args_contain_struct) {
357         runJavaFunctions(&cif, resp_buf, arg_array, &dataProvider);
358     }
359 
360 free:
361     freeAll(arg_array, num_args, resp_buf);
362     return 0;
363 }
364