diff options
22 files changed, 1531 insertions, 0 deletions
diff --git a/system/osi/test/fuzzers/Android.bp b/system/osi/test/fuzzers/Android.bp new file mode 100644 index 0000000000..c39c0fd49b --- /dev/null +++ b/system/osi/test/fuzzers/Android.bp @@ -0,0 +1,8 @@ +cc_defaults { + name: "libosi_fuzz_defaults", + defaults: ["fluoride_osi_defaults"], + host_supported: true, + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/alarm/Android.bp b/system/osi/test/fuzzers/alarm/Android.bp new file mode 100644 index 0000000000..51b5e5601a --- /dev/null +++ b/system/osi/test/fuzzers/alarm/Android.bp @@ -0,0 +1,21 @@ +cc_fuzz { + name: "libosi_fuzz_alarm", + defaults: ["libosi_fuzz_defaults"], + host_supported: false, + srcs: [ + "fuzz_alarm.cc", + ], + shared_libs: [ + "liblog", + "libprotobuf-cpp-lite", + "libcutils", + "libcrypto", + ], + static_libs: [ + "libbt-common", + "libbt-protos-lite", + "libgmock", + "libosi", + ], + cflags: [ "-Wno-unused-function" ], +} diff --git a/system/osi/test/fuzzers/alarm/fuzz_alarm.cc b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc new file mode 100644 index 0000000000..e4e6a252e3 --- /dev/null +++ b/system/osi/test/fuzzers/alarm/fuzz_alarm.cc @@ -0,0 +1,151 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/alarm.h" +#include "osi/include/semaphore.h" + +#include "common/message_loop_thread.h" + +using base::Closure; +using base::TimeDelta; +using bluetooth::common::MessageLoopThread; + +#define MAX_CONCURRENT_ALARMS 25 +#define MAX_BUFFER_LEN 4096 +#define MAX_ALARM_DURATION 25 + +static semaphore_t* semaphore; +static int cb_counter; +static base::MessageLoop* message_loop_; + +base::MessageLoop* get_main_message_loop() { return message_loop_; } + +static void cb(void* data) { + ++cb_counter; + semaphore_post(semaphore); +} + +void setup() { + cb_counter = 0; + semaphore = semaphore_new(0); +} +void teardown() { semaphore_free(semaphore); } + +alarm_t* fuzz_init_alarm(FuzzedDataProvider* dataProvider) { + size_t name_len = + dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_LEN); + std::vector<char> alarm_name_vect = + dataProvider->ConsumeBytesWithTerminator<char>(name_len, '\0'); + char* alarm_name = alarm_name_vect.data(); + + // Determine if our alarm will be periodic + if (dataProvider->ConsumeBool()) { + return alarm_new_periodic(alarm_name); + } else { + return alarm_new(alarm_name); + } +} + +bool fuzz_set_alarm(alarm_t* alarm, uint64_t interval, alarm_callback_t cb, + FuzzedDataProvider* dataProvider) { + // Generate a random buffer (or null) + void* data_buffer = nullptr; + size_t buff_len = + dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_LEN); + if (buff_len == 0) { + return false; + } + + // allocate our space + std::vector<uint8_t> data_vector = + dataProvider->ConsumeBytes<uint8_t>(buff_len); + data_buffer = data_vector.data(); + + // Make sure alarm is non-null + if (alarm) { + // Should this alarm be regular or on mloop? + if (dataProvider->ConsumeBool()) { + alarm_set_on_mloop(alarm, interval, cb, data_buffer); + } else { + alarm_set(alarm, interval, cb, data_buffer); + } + } + + return true; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Perform setup + setup(); + + alarm_t* alarm = nullptr; + // Should our alarm be valid or null? + if (dataProvider.ConsumeBool()) { + // Init our alarm + alarm = fuzz_init_alarm(&dataProvider); + } + + // Set up the alarm & cancel + // Alarm must be non-null, or set() will trigger assert + if (alarm) { + if (!fuzz_set_alarm(alarm, MAX_ALARM_DURATION, cb, &dataProvider)) { + return 0; + } + alarm_cancel(alarm); + } + + // Check if scheduled + alarm_is_scheduled(alarm); + + if (alarm) { + // Set up another set of alarms & let these ones run + int num_alarms = + dataProvider.ConsumeIntegralInRange<uint8_t>(0, MAX_CONCURRENT_ALARMS); + for (int i = 0; i < num_alarms; i++) { + uint64_t interval = + dataProvider.ConsumeIntegralInRange<uint64_t>(0, MAX_ALARM_DURATION); + if (fuzz_set_alarm(alarm, interval, cb, &dataProvider)) { + return 0; + } + alarm_get_remaining_ms(alarm); + } + + // Wait for them to complete + for (int i = 1; i <= num_alarms; i++) { + semaphore_wait(semaphore); + } + } + + // Free the alarm object + alarm_free(alarm); + + // dump debug data to /dev/null + int debug_fd = open("/dev/null", O_RDWR); + alarm_debug_dump(debug_fd); + + // Cleanup + alarm_cleanup(); + + // Perform teardown + teardown(); + + return 0; +} diff --git a/system/osi/test/fuzzers/allocation_tracker/Android.bp b/system/osi/test/fuzzers/allocation_tracker/Android.bp new file mode 100644 index 0000000000..83194daf38 --- /dev/null +++ b/system/osi/test/fuzzers/allocation_tracker/Android.bp @@ -0,0 +1,14 @@ +cc_fuzz { + name: "libosi_fuzz_allocation_tracker", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_allocation_tracker.cc", + ], + shared_libs: [ + "liblog", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc b/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc new file mode 100644 index 0000000000..69299d0ba5 --- /dev/null +++ b/system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc @@ -0,0 +1,132 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/allocation_tracker.h" + +#define MAX_NUM_FUNCTIONS 512 +#define MAX_BUF_SIZE 256 + +struct alloc_struct { + allocator_id_t alloc_id; + void* ptr; +}; + +void freeAllocationVector(std::vector<alloc_struct>* alloc_vector) { + // Free our allocated buffers + for (const auto& alloc : *alloc_vector) { + void* real_ptr = allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr); + if (real_ptr) { + free(real_ptr); + } + } + alloc_vector->clear(); +} + +void callArbitraryFunction(std::vector<alloc_struct>* alloc_vector, + FuzzedDataProvider* dataProvider) { + // Get our function identifier + switch (dataProvider->ConsumeIntegralInRange<char>(0, 6)) { + // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer + // (This will likely bias whatever action is here to run more often) + case 0: + return; + // Init + case 1: + allocation_tracker_init(); + return; + case 2: + // NOTE: This will print to stderr if allocations exist. May clutter logs + allocation_tracker_expect_no_allocations(); + return; + case 3: { + alloc_struct alloc; + // Determine allocator ID & buffer size (without canaries) + alloc.alloc_id = dataProvider->ConsumeIntegral<allocator_id_t>(); + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE); + if (size == 0) { + return; + } + // Get our size with canaries & allocate + size_t real_size = allocation_tracker_resize_for_canary(size); + void* tmp_ptr = malloc(real_size); + if (tmp_ptr == nullptr) { + return; + } + alloc.ptr = + allocation_tracker_notify_alloc(alloc.alloc_id, tmp_ptr, size); + // Put our id/ptr pair in our tracking vector to be freed later + if (alloc.ptr) { + alloc_vector->push_back(alloc); + } + } + return; + case 4: { + // Grab a ptr from our tracking vector & free it + if (!alloc_vector->empty()) { + size_t index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, alloc_vector->size() - 1); + alloc_struct alloc = alloc_vector->at(index); + void* real_ptr = + allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr); + if (real_ptr) { + free(real_ptr); + } + alloc_vector->erase(alloc_vector->begin() + index); + } + } + return; + case 5: { + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE); + allocation_tracker_resize_for_canary(size); + } + return; + // Reset + // NOTE: Should this be exempted from fuzzing? Header says to not call this, + // but it's still exposed. It also doesn't perform a full reset. + case 6: + // Have to actually free the mem first as reset doesn't do it + freeAllocationVector(alloc_vector); + allocation_tracker_reset(); + return; + default: + return; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Keep a vector of our allocated pointers + std::vector<alloc_struct> alloc_vector; + + // How many functions are we going to call? + size_t num_functions = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS); + for (size_t i = 0; i < num_functions; i++) { + callArbitraryFunction(&alloc_vector, &dataProvider); + } + + // Free anything we've allocated over the course of the fuzzer loop + freeAllocationVector(&alloc_vector); + + // Reset our tracker for the next run + allocation_tracker_reset(); + return 0; +} diff --git a/system/osi/test/fuzzers/allocator/Android.bp b/system/osi/test/fuzzers/allocator/Android.bp new file mode 100644 index 0000000000..90db372852 --- /dev/null +++ b/system/osi/test/fuzzers/allocator/Android.bp @@ -0,0 +1,11 @@ +cc_fuzz { + name: "libosi_fuzz_allocator", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_allocator.cc", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/allocator/fuzz_allocator.cc b/system/osi/test/fuzzers/allocator/fuzz_allocator.cc new file mode 100644 index 0000000000..bdfd99a1d4 --- /dev/null +++ b/system/osi/test/fuzzers/allocator/fuzz_allocator.cc @@ -0,0 +1,119 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/allocator.h" +#include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h" + +#define MAX_NUM_FUNCTIONS 512 +#define MAX_BUF_SIZE 256 + +void callArbitraryFunction(std::vector<void*>* alloc_vector, + FuzzedDataProvider* dataProvider) { + // Get our function identifier + char func_id = dataProvider->ConsumeIntegralInRange<char>(0, 6); + + switch (func_id) { + // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer + // (This will likely bias whatever action is here to run more often) + case 0: + return; + // Let case 1 be osi_malloc, and 2 be osi_calloc + case 1: + case 2: { + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE); + void* ptr = nullptr; + if (size == 0) { + return; + } + if (func_id == 1) { + ptr = osi_malloc(size); + } else { + ptr = osi_calloc(size); + } + if (ptr) { + alloc_vector->push_back(ptr); + } + } + return; + // Let case 3 be osi_free, and 4 be osi_free_and_reset + case 3: + case 4: { + if (alloc_vector->size() == 0) { + return; + } + size_t index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, alloc_vector->size() - 1); + void* ptr = alloc_vector->at(index); + if (ptr) { + if (func_id == 3) { + osi_free(ptr); + } else { + osi_free_and_reset(&ptr); + } + } + alloc_vector->erase(alloc_vector->begin() + index); + } + return; + // Let case 5 be osi_strdup, and 6 be osi_strdup + case 5: + case 6: { + // Make a src buffer + char* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, true); + char* str = nullptr; + if (buf == nullptr) { + return; + } + if (func_id == 5) { + str = osi_strdup(buf); + } else { + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE); + str = osi_strndup(buf, size); + } + free(buf); + if (str) { + alloc_vector->push_back(str); + } + } + return; + default: + return; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Keep a vector of our allocated objects for freeing later + std::vector<void*> alloc_vector; + // Call some functions, create some buffers + size_t num_functions = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS); + for (size_t i = 0; i < num_functions; i++) { + callArbitraryFunction(&alloc_vector, &dataProvider); + } + // Free anything we've allocated + for (const auto& alloc : alloc_vector) { + if (alloc != nullptr) { + osi_free(alloc); + } + } + alloc_vector.clear(); + return 0; +} diff --git a/system/osi/test/fuzzers/array/Android.bp b/system/osi/test/fuzzers/array/Android.bp new file mode 100644 index 0000000000..ffcaf8c614 --- /dev/null +++ b/system/osi/test/fuzzers/array/Android.bp @@ -0,0 +1,14 @@ +cc_fuzz { + name: "libosi_fuzz_array", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_array.cc", + ], + shared_libs: [ + "liblog", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/array/fuzz_array.cc b/system/osi/test/fuzzers/array/fuzz_array.cc new file mode 100644 index 0000000000..eeabf952d5 --- /dev/null +++ b/system/osi/test/fuzzers/array/fuzz_array.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/array.h" + +// Capping the element size at sizeof(uint32_t)+1 +// because it looks like there's a buffer overread +#define MAX_ELEMENT_SIZE sizeof(uint32_t) +#define MAX_ARRAY_LEN 1024 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Attempt to init an array + size_t element_size = + dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_ELEMENT_SIZE); + array_t* arr = array_new(element_size); + + // Functions can only be called on a non-null array_t, according to the .h + if (arr != nullptr) { + // How large do we want our array? + size_t arr_len = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_ARRAY_LEN); + if (arr_len > 0) { + for (size_t i = 0; i < arr_len; i++) { + uint32_t new_val = dataProvider.ConsumeIntegral<uint32_t>(); + // append_value() just derefs and calls append_ptr(), + // so no need to fuzz separately + array_append_value(arr, new_val); + } + + // Pull the ptr to an element in the array + size_t get_index = + dataProvider.ConsumeIntegralInRange<size_t>(0, array_length(arr) - 1); + array_at(arr, get_index); + + // Grab the array pointer + array_ptr(arr); + } + } + + // Free the array (this can be performed on a nullptr) + array_free(arr); + + return 0; +} diff --git a/system/osi/test/fuzzers/buffer/Android.bp b/system/osi/test/fuzzers/buffer/Android.bp new file mode 100644 index 0000000000..3467e0d890 --- /dev/null +++ b/system/osi/test/fuzzers/buffer/Android.bp @@ -0,0 +1,14 @@ +cc_fuzz { + name: "libosi_fuzz_buffer", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_buffer.cc", + ], + shared_libs: [ + "liblog", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/buffer/fuzz_buffer.cc b/system/osi/test/fuzzers/buffer/fuzz_buffer.cc new file mode 100644 index 0000000000..b781a3171c --- /dev/null +++ b/system/osi/test/fuzzers/buffer/fuzz_buffer.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/buffer.h" + +#define MAX_BUFFER_SIZE 4096 +#define MAX_NUM_SLICES 100 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Create our buffer + size_t buf_size = + dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_SIZE); + buffer_t* buf = buffer_new(buf_size); + + // These functions require a non-null buffer, according to the header + // The size also needs to be over 1 to make slices + if (buf != nullptr && buf_size > 1) { + std::vector<buffer_t*> slices; + + // Make a bunch of refs to various slices of the buffer + size_t num_slices = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_SLICES); + for (size_t i = 0; i < num_slices; i++) { + // If slice_size is zero or GT buf_size, lib throws an exception + size_t slice_size = + dataProvider.ConsumeIntegralInRange<size_t>(1, buf_size - 1); + if (slice_size > 0) { + buffer_t* new_slice = nullptr; + if (slice_size == buf_size) { + new_slice = buffer_new_ref(buf); + } else { + new_slice = buffer_new_slice(buf, slice_size); + } + + // Add the slice to our vector so we can free it later + slices.push_back(new_slice); + } + } + + // Retrieve the buffer ptr + buffer_ptr(buf); + + // Free the slices + for (const auto& slice : slices) { + buffer_free(slice); + } + } + + // Free the root buffer + buffer_free(buf); + + return 0; +} diff --git a/system/osi/test/fuzzers/compat/Android.bp b/system/osi/test/fuzzers/compat/Android.bp new file mode 100644 index 0000000000..3d9178b1e7 --- /dev/null +++ b/system/osi/test/fuzzers/compat/Android.bp @@ -0,0 +1,15 @@ +cc_fuzz { + name: "libosi_fuzz_compat", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_compat.cc", + ], + shared_libs: [ + "liblog", + "libcutils", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/compat/fuzz_compat.cc b/system/osi/test/fuzzers/compat/fuzz_compat.cc new file mode 100644 index 0000000000..3feeaeb1cc --- /dev/null +++ b/system/osi/test/fuzzers/compat/fuzz_compat.cc @@ -0,0 +1,62 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/compat.h" + +#define MAX_BUFFER_SIZE 4096 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { +// Our functions are only defined with __GLIBC__ +#if __GLIBC__ + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + size_t buf_size = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE); + if (buf_size == 0) { + return 0; + } + + // Set up our buffers + // NOTE: If the src buffer is not NULL-terminated, the strlcpy will + // overread regardless of the len arg. Force null-term for now. + std::vector<char> bytes = + dataProvider.ConsumeBytesWithTerminator<char>(buf_size, '\0'); + if (bytes.empty()) { + return 0; + } + buf_size = bytes.size(); + void* dst_buf = malloc(buf_size); + if (dst_buf == nullptr) { + return 0; + } + + // Call the getId fn just to ensure things don't crash + gettid(); + + // Copy, then concat + size_t len_to_cpy = dataProvider.ConsumeIntegralInRange<size_t>(0, buf_size); + strlcpy(reinterpret_cast<char*>(dst_buf), + reinterpret_cast<char*>(bytes.data()), len_to_cpy); + strlcat(reinterpret_cast<char*>(dst_buf), + reinterpret_cast<char*>(bytes.data()), len_to_cpy); + + // Clear out our dest buffer + free(dst_buf); +#endif + + return 0; +} diff --git a/system/osi/test/fuzzers/fixed_queue/Android.bp b/system/osi/test/fuzzers/fixed_queue/Android.bp new file mode 100644 index 0000000000..d21ee7ce13 --- /dev/null +++ b/system/osi/test/fuzzers/fixed_queue/Android.bp @@ -0,0 +1,15 @@ +cc_fuzz { + name: "libosi_fuzz_fixed_queue", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_fixed_queue.cc", + ], + shared_libs: [ + "liblog", + "libcutils", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/fixed_queue/fuzz_fixed_queue.cc b/system/osi/test/fuzzers/fixed_queue/fuzz_fixed_queue.cc new file mode 100644 index 0000000000..f8a426a6a7 --- /dev/null +++ b/system/osi/test/fuzzers/fixed_queue/fuzz_fixed_queue.cc @@ -0,0 +1,240 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include <sys/select.h> +#include "osi/include/fixed_queue.h" +#include "osi/include/future.h" +#include "osi/include/thread.h" +#include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h" + +#define MAX_START_SIZE 2048 +#define MAX_NUM_FUNCTIONS 512 +#define MAX_BUF_SIZE 512 + +static future_t* received_message_future = nullptr; + +// Empty callback function +void fqFreeCb(void* data) {} +void fqCb(fixed_queue_t* queue, void* data) { + void* msg = fixed_queue_try_dequeue(queue); + future_ready(received_message_future, msg); +} + +// Returns either a nullptr or a function ptr to the placeholder cb function +fixed_queue_free_cb cbOrNull(FuzzedDataProvider* dataProvider) { + bool null_cb = dataProvider->ConsumeBool(); + if (null_cb) { + return nullptr; + } else { + return fqFreeCb; + } +} + +bool fdIsAvailable(int fd) { + int nfds = 1; + fd_set readfds, writefds, exceptfds; + timeval timeout; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(fd, &readfds); + timeout.tv_sec = 0; + timeout.tv_usec = 50; + + return select(nfds, &readfds, &writefds, &exceptfds, &timeout) > 0; +} + +void createNewFuture() { + // Free the existing future if it exists + if (received_message_future != nullptr) { + future_ready(received_message_future, nullptr); + future_await(received_message_future); + } + + // Create a new one + received_message_future = future_new(); +} + +void callArbitraryFunction(fixed_queue_t* fixed_queue, + std::vector<void*>* live_buffer_vector, + std::vector<thread_t*>* live_thread_vector, + FuzzedDataProvider* dataProvider) { + void* buf_ptr = nullptr; + size_t index = 0; + int fd = 0; + // Get our function identifier + switch (dataProvider->ConsumeIntegralInRange<char>(0, 17)) { + // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer + // (This will likely bias whatever action is here to run more often) + case 0: + return; + // Clear the queue + case 1: + fixed_queue_flush(fixed_queue, cbOrNull(dataProvider)); + return; + // Check if empty + case 2: + fixed_queue_is_empty(fixed_queue); + return; + // Check length + case 3: + fixed_queue_length(fixed_queue); + return; + // Check capacity (Cannot be null) + case 4: + if (fixed_queue) { + fixed_queue_capacity(fixed_queue); + } + return; + // Add to the queue (Cannot be null) + case 5: + if (fixed_queue) { + buf_ptr = generateBuffer(dataProvider, MAX_BUF_SIZE, false); + live_buffer_vector->push_back(buf_ptr); + if (buf_ptr) { + // Make sure we won't block + fd = fixed_queue_get_enqueue_fd(fixed_queue); + if (fdIsAvailable(fd)) { + fixed_queue_enqueue(fixed_queue, buf_ptr); + } + } + } + return; + case 6: + if (fixed_queue) { + buf_ptr = generateBuffer(dataProvider, MAX_BUF_SIZE, false); + live_buffer_vector->push_back(buf_ptr); + if (buf_ptr) { + fixed_queue_try_enqueue(fixed_queue, buf_ptr); + } + } + return; + // Remove from the queue (Cannot be null) + case 7: + if (fixed_queue && fixed_queue_length(fixed_queue) > 0) { + fixed_queue_dequeue(fixed_queue); + } + return; + case 8: + if (fixed_queue) { + fixed_queue_try_dequeue(fixed_queue); + } + return; + // Peeks + case 9: + fixed_queue_try_peek_first(fixed_queue); + return; + case 10: + fixed_queue_try_peek_last(fixed_queue); + return; + // Try to remove existing specific element + case 11: + if (live_buffer_vector->empty()) { + return; + } + // Grab an existing buffer + index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, live_buffer_vector->size() - 1); + buf_ptr = live_buffer_vector->at(index); + if (buf_ptr != nullptr) { + fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr); + } + return; + // Try to remove nonexistant element + case 12: + buf_ptr = + reinterpret_cast<void*>(dataProvider->ConsumeIntegral<uint64_t>()); + if (buf_ptr != nullptr) { + fixed_queue_try_remove_from_queue(fixed_queue, buf_ptr); + } + return; + // Convert the queue to a list (Cannot be null) + case 13: + if (fixed_queue) { + fixed_queue_get_list(fixed_queue); + } + return; + // Check if enqueue is blocking + case 14: + fixed_queue_get_enqueue_fd(fixed_queue); + return; + // Check if dequeue is blocking + case 15: + fixed_queue_get_dequeue_fd(fixed_queue); + return; + // NOTE: thread appears to have a memleak, disabling this for now. + case 16: + // if (fixed_queue) { + // createNewFuture(); + // // Start up a thread and register with it. + // thread_t* tmp_thread = thread_new( + // dataProvider->ConsumeRandomLengthString().c_str()); + // if (tmp_thread == nullptr) { + // return; + // } + // live_thread_vector->push_back(tmp_thread); + // reactor_t* reactor = thread_get_reactor(tmp_thread); + // if (reactor == nullptr) { + // return; + // } + // fixed_queue_register_dequeue(fixed_queue, reactor, fqCb, nullptr); + // fixed_queue_enqueue(fixed_queue, (void*)"test"); + // future_await(received_message_future); + // } + return; + case 17: + fixed_queue_unregister_dequeue(fixed_queue); + return; + default: + return; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Make vectors to keep track of objects we generate, for freeing + std::vector<void*> live_buffer_vector; + std::vector<thread_t*> live_thread_vector; + + size_t start_capacity = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_START_SIZE); + fixed_queue_t* fixed_queue = fixed_queue_new(start_capacity); + + // How many functions are we going to call? + size_t num_functions = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS); + for (size_t i = 0; i < num_functions; i++) { + callArbitraryFunction(fixed_queue, &live_buffer_vector, &live_thread_vector, + &dataProvider); + } + + // Free our queue (with either a null or placeholder callback) + fixed_queue_free(fixed_queue, cbOrNull(&dataProvider)); + + // Free buffers we've created through fn calls during this fuzzer loop. + for (const auto& buffer : live_buffer_vector) { + free(buffer); + } + for (const auto& thread : live_thread_vector) { + thread_free(thread); + } + + return 0; +} diff --git a/system/osi/test/fuzzers/future/Android.bp b/system/osi/test/fuzzers/future/Android.bp new file mode 100644 index 0000000000..4fdbafe4ec --- /dev/null +++ b/system/osi/test/fuzzers/future/Android.bp @@ -0,0 +1,15 @@ +cc_fuzz { + name: "libosi_fuzz_future", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_future.cc", + ], + shared_libs: [ + "liblog", + "libcutils", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/future/fuzz_future.cc b/system/osi/test/fuzzers/future/fuzz_future.cc new file mode 100644 index 0000000000..1df3e7da0f --- /dev/null +++ b/system/osi/test/fuzzers/future/fuzz_future.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/future.h" + +#define MAX_BUFFER_SIZE 8 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // The value of this result ptr shouldn't matter, but make a buffer to be safe + size_t buf_size = + dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_SIZE); + void* buf = malloc(buf_size); + if (buf == nullptr) { + return 0; + } + std::vector<uint8_t> bytes = dataProvider.ConsumeBytes<uint8_t>(buf_size); + memcpy(buf, bytes.data(), bytes.size()); + + // Is our future an immediate? + future_t* future = nullptr; + bool is_immediate = dataProvider.ConsumeBool(); + if (is_immediate) { + future = future_new_immediate(buf); + } else { + future = future_new(); + } + + // These functions require a non-null object, according to the header + if (future != nullptr) { + // If we need to, specify that the future is ready + if (!is_immediate) { + future_ready(future, buf); + } + + // Free the object + future_await(future); + } + + free(buf); + return 0; +} diff --git a/system/osi/test/fuzzers/include/libosiFuzzHelperFunctions.h b/system/osi/test/fuzzers/include/libosiFuzzHelperFunctions.h new file mode 100644 index 0000000000..395b85ec77 --- /dev/null +++ b/system/osi/test/fuzzers/include/libosiFuzzHelperFunctions.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBOSI_FUZZ_HELPERS_H_ +#define LIBOSI_FUZZ_HELPERS_H_ + +#include <fuzzer/FuzzedDataProvider.h> +#include <vector> + +char* generateBuffer(FuzzedDataProvider* dataProvider, size_t max_buffer_size, + bool null_terminate) { + // Get our buffer size + size_t buf_size = + dataProvider->ConsumeIntegralInRange<size_t>(0, max_buffer_size); + if (buf_size == 0) { + return nullptr; + } + + // Allocate and copy in data + char* buf = reinterpret_cast<char*>(malloc(buf_size)); + std::vector<char> bytes = dataProvider->ConsumeBytes<char>(buf_size); + memcpy(buf, bytes.data(), bytes.size()); + + if (null_terminate) { + // Force a null-termination + buf[buf_size - 1] = 0x00; + } + + return buf; +} + +#endif // LIBOSI_FUZZ_HELPERS_H_ diff --git a/system/osi/test/fuzzers/list/Android.bp b/system/osi/test/fuzzers/list/Android.bp new file mode 100644 index 0000000000..2b664bcae1 --- /dev/null +++ b/system/osi/test/fuzzers/list/Android.bp @@ -0,0 +1,11 @@ +cc_fuzz { + name: "libosi_fuzz_list", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_list.cc", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/list/fuzz_list.cc b/system/osi/test/fuzzers/list/fuzz_list.cc new file mode 100644 index 0000000000..a5814740a1 --- /dev/null +++ b/system/osi/test/fuzzers/list/fuzz_list.cc @@ -0,0 +1,277 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/list.h" +#include "osi/test/fuzzers/include/libosiFuzzHelperFunctions.h" + +#define MAX_NUM_FUNCTIONS 512 +#define MAX_BUF_SIZE 256 + +struct list_node_t { + struct list_node_t* next; + void* data; +}; + +void cb(void* data) {} +// Pass a ptr to FuzzedDataProvider in context +bool list_iter_cb_impl(void* data, void* context) { + FuzzedDataProvider* dataProvider = + reinterpret_cast<FuzzedDataProvider*>(context); + return dataProvider->ConsumeBool(); +} + +list_t* createList(FuzzedDataProvider* dataProvider) { + bool should_callback = dataProvider->ConsumeBool(); + if (should_callback) { + return list_new(cb); + } else { + return list_new(nullptr); + } +} + +void* getArbitraryElement(std::vector<void*>* vector, + FuzzedDataProvider* dataProvider) { + if (vector->size() == 0) { + return nullptr; + } + // Get an index + size_t index = + dataProvider->ConsumeIntegralInRange<size_t>(0, vector->size() - 1); + return vector->at(index); +} + +list_node_t* getArbitraryNode(list_t* list, FuzzedDataProvider* dataProvider) { + if (list == nullptr || list_is_empty(list)) { + return nullptr; + } + size_t index = + dataProvider->ConsumeIntegralInRange<size_t>(0, list_length(list) - 1); + list_node_t* node = list_begin(list); + for (size_t i = 0; i < index; i++) { + node = node->next; + } + + return node; +} + +void callArbitraryFunction(std::vector<void*>* list_vector, + std::vector<void*>* alloc_vector, + FuzzedDataProvider* dataProvider) { + list_t* list = nullptr; + // Get our function identifier + switch (dataProvider->ConsumeIntegralInRange<char>(0, 18)) { + // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer + // (This will likely bias whatever action is here to run more often) + case 0: + return; + // Create a new list + case 1: + list = createList(dataProvider); + list_vector->push_back(list); + return; + // Free a list + case 2: { + size_t index = 0; + if (list_vector->size() > 0) { + // Get an index + index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, list_vector->size() - 1); + list = reinterpret_cast<list_t*>(list_vector->at(index)); + } + list_free(list); + // Otherwise free a valid list + if (list != nullptr) { + list_vector->erase(list_vector->begin() + index); + } + return; + } + case 3: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_is_empty(list); + } + return; + case 4: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + void* search_buf = getArbitraryElement(alloc_vector, dataProvider); + if (search_buf != nullptr) { + list_contains(list, search_buf); + } + } + return; + case 5: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_length(list); + } + return; + case 6: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr && !list_is_empty(list)) { + list_front(list); + } + return; + case 7: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr && !list_is_empty(list)) { + list_back(list); + } + return; + case 8: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr && !list_is_empty(list)) { + list_back_node(list); + } + return; + case 9: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list == nullptr) { + return; + } + void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false); + alloc_vector->push_back(buf); + list_node_t* node = getArbitraryNode(list, dataProvider); + if (node != nullptr && buf != nullptr) { + list_insert_after(list, node, buf); + } + return; + } + case 10: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false); + alloc_vector->push_back(buf); + if (list != nullptr && buf != nullptr) { + list_prepend(list, buf); + } + return; + } + case 11: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + void* buf = generateBuffer(dataProvider, MAX_BUF_SIZE, false); + alloc_vector->push_back(buf); + if (list != nullptr && buf != nullptr) { + list_append(list, buf); + } + return; + } + case 12: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + // The buffer will be valid, but may be for a different list + void* buf = getArbitraryElement(alloc_vector, dataProvider); + if (list != nullptr && buf != nullptr) { + list_remove(list, buf); + } + return; + } + case 13: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_clear(list); + } + return; + case 14: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_foreach(list, list_iter_cb_impl, dataProvider); + } + return; + case 15: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_begin(list); + } + return; + case 16: + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list != nullptr) { + list_end(list); + } + return; + case 17: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list == nullptr) { + return; + } + list_node_t* node = getArbitraryNode(list, dataProvider); + if (node != nullptr) { + list_next(node); + } + return; + } + case 18: { + list = reinterpret_cast<list_t*>( + getArbitraryElement(list_vector, dataProvider)); + if (list == nullptr) { + return; + } + list_node_t* node = getArbitraryNode(list, dataProvider); + if (node != nullptr && node != list_end(list)) { + list_node(node); + } + return; + } + default: + return; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Keep a vector of our allocated objects for freeing later + std::vector<void*> list_vector; + std::vector<void*> alloc_vector; + + // Call some functions, create some buffers + size_t num_functions = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS); + for (size_t i = 0; i < num_functions; i++) { + callArbitraryFunction(&list_vector, &alloc_vector, &dataProvider); + } + + // Free anything we've allocated + for (const auto& list : list_vector) { + if (list != nullptr) { + list_free(reinterpret_cast<list_t*>(list)); + } + } + for (const auto& alloc : alloc_vector) { + if (alloc != nullptr) { + free(alloc); + } + } + list_vector.clear(); + + return 0; +} diff --git a/system/osi/test/fuzzers/ringbuffer/Android.bp b/system/osi/test/fuzzers/ringbuffer/Android.bp new file mode 100644 index 0000000000..4343e02bb7 --- /dev/null +++ b/system/osi/test/fuzzers/ringbuffer/Android.bp @@ -0,0 +1,11 @@ +cc_fuzz { + name: "libosi_fuzz_ringbuffer", + defaults: ["libosi_fuzz_defaults"], + host_supported: true, + srcs: [ + "fuzz_ringbuffer.cc", + ], + static_libs: [ + "libosi", + ], +} diff --git a/system/osi/test/fuzzers/ringbuffer/fuzz_ringbuffer.cc b/system/osi/test/fuzzers/ringbuffer/fuzz_ringbuffer.cc new file mode 100644 index 0000000000..adc219c22c --- /dev/null +++ b/system/osi/test/fuzzers/ringbuffer/fuzz_ringbuffer.cc @@ -0,0 +1,167 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fuzzer/FuzzedDataProvider.h> +#include "osi/include/ringbuffer.h" + +#define MAX_NUM_FUNCTIONS 512 +#define MAX_BUF_SIZE 2048 + +ringbuffer_t* getArbitraryRingBuf(std::vector<ringbuffer_t*>* ringbuf_vector, + FuzzedDataProvider* dataProvider) { + if (ringbuf_vector->empty()) { + return nullptr; + } + + size_t index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, ringbuf_vector->size() - 1); + return ringbuf_vector->at(index); +} + +void callArbitraryFunction(std::vector<ringbuffer_t*>* ringbuf_vector, + FuzzedDataProvider* dataProvider) { + // Get our function identifier + char func_id = dataProvider->ConsumeIntegralInRange<char>(0, 8); + + ringbuffer_t* buf = nullptr; + switch (func_id) { + // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer + // (This will likely bias whatever action is here to run more often) + case 0: + return; + case 1: { + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE); + buf = ringbuffer_init(size); + if (buf) { + ringbuf_vector->push_back(buf); + } + } + return; + case 2: { + if (ringbuf_vector->empty()) { + return; + } + size_t index = dataProvider->ConsumeIntegralInRange<size_t>( + 0, ringbuf_vector->size() - 1); + buf = ringbuf_vector->at(index); + if (buf) { + ringbuffer_free(buf); + ringbuf_vector->erase(ringbuf_vector->begin() + index); + } + } + return; + case 3: + buf = getArbitraryRingBuf(ringbuf_vector, dataProvider); + if (buf) { + ringbuffer_available(buf); + } + return; + case 4: + buf = getArbitraryRingBuf(ringbuf_vector, dataProvider); + if (buf) { + ringbuffer_size(buf); + } + return; + case 5: { + buf = getArbitraryRingBuf(ringbuf_vector, dataProvider); + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE); + if (buf == nullptr || size == 0) { + return; + } + void* src_buf = malloc(size); + if (src_buf == nullptr) { + return; + } + std::vector<uint8_t> bytes = dataProvider->ConsumeBytes<uint8_t>(size); + memcpy(src_buf, bytes.data(), bytes.size()); + + ringbuffer_insert(buf, reinterpret_cast<uint8_t*>(src_buf), size); + free(src_buf); + } + return; + case 6: + case 7: { + buf = getArbitraryRingBuf(ringbuf_vector, dataProvider); + if (buf == nullptr) { + return; + } + size_t max_size = ringbuffer_size(buf); + if (max_size == 0) { + return; + } + size_t size = dataProvider->ConsumeIntegralInRange<size_t>(1, max_size); + + // NOTE: 0-size may be a valid case, that crashes currently. + if (size == 0) { + return; + } + + void* dst_buf = malloc(size); + if (dst_buf == nullptr) { + return; + } + if (func_id == 6) { + off_t offset = dataProvider->ConsumeIntegral<off_t>(); + if (offset >= 0 && + static_cast<size_t>(offset) <= ringbuffer_size(buf)) { + ringbuffer_peek(buf, offset, reinterpret_cast<uint8_t*>(dst_buf), + size); + } + } else { + ringbuffer_pop(buf, reinterpret_cast<uint8_t*>(dst_buf), size); + } + free(dst_buf); + } + return; + case 8: { + buf = getArbitraryRingBuf(ringbuf_vector, dataProvider); + size_t size = + dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE); + if (buf) { + ringbuffer_delete(buf, size); + } + } + return; + default: + return; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + // Init our wrapper + FuzzedDataProvider dataProvider(Data, Size); + + // Keep a vector of our allocated objects for freeing later + std::vector<ringbuffer_t*> ringbuf_vector; + + // Call some functions, create some buffers + size_t num_functions = + dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS); + for (size_t i = 0; i < num_functions; i++) { + callArbitraryFunction(&ringbuf_vector, &dataProvider); + } + + // Free anything we've allocated + for (const auto& ringbuf : ringbuf_vector) { + if (ringbuf != nullptr) { + ringbuffer_free(ringbuf); + } + } + ringbuf_vector.clear(); + return 0; +} |
