aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--system/osi/test/fuzzers/Android.bp8
-rw-r--r--system/osi/test/fuzzers/alarm/Android.bp21
-rw-r--r--system/osi/test/fuzzers/alarm/fuzz_alarm.cc151
-rw-r--r--system/osi/test/fuzzers/allocation_tracker/Android.bp14
-rw-r--r--system/osi/test/fuzzers/allocation_tracker/fuzz_allocation_tracker.cc132
-rw-r--r--system/osi/test/fuzzers/allocator/Android.bp11
-rw-r--r--system/osi/test/fuzzers/allocator/fuzz_allocator.cc119
-rw-r--r--system/osi/test/fuzzers/array/Android.bp14
-rw-r--r--system/osi/test/fuzzers/array/fuzz_array.cc61
-rw-r--r--system/osi/test/fuzzers/buffer/Android.bp14
-rw-r--r--system/osi/test/fuzzers/buffer/fuzz_buffer.cc70
-rw-r--r--system/osi/test/fuzzers/compat/Android.bp15
-rw-r--r--system/osi/test/fuzzers/compat/fuzz_compat.cc62
-rw-r--r--system/osi/test/fuzzers/fixed_queue/Android.bp15
-rw-r--r--system/osi/test/fuzzers/fixed_queue/fuzz_fixed_queue.cc240
-rw-r--r--system/osi/test/fuzzers/future/Android.bp15
-rw-r--r--system/osi/test/fuzzers/future/fuzz_future.cc58
-rw-r--r--system/osi/test/fuzzers/include/libosiFuzzHelperFunctions.h45
-rw-r--r--system/osi/test/fuzzers/list/Android.bp11
-rw-r--r--system/osi/test/fuzzers/list/fuzz_list.cc277
-rw-r--r--system/osi/test/fuzzers/ringbuffer/Android.bp11
-rw-r--r--system/osi/test/fuzzers/ringbuffer/fuzz_ringbuffer.cc167
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;
+}