From 7168f2726eccdc00210ba59563a4ed3b821cca9d Mon Sep 17 00:00:00 2001 From: Dylan Katz Date: Thu, 2 Jul 2020 11:51:44 -0700 Subject: [PATCH] Add second batch of fuzzers for libutils This adds fuzzers for: - CallStack - Looper - LruCache - Printer - ProcessCallStack - PropertyMap - RWLock - RefBase - StopWatch. Test: Ran each fuzzer for 10 minutes. Rough coverage est. (likely far below actual value): 10.97% Signed-off-by: Dylan Katz Change-Id: I2f9f35c18b13338c282fb7f9c3ea4099ecb2c56f --- libutils/Android.bp | 61 +++++++++++++++++ libutils/CallStack_fuzz.cpp | 50 ++++++++++++++ libutils/Looper_fuzz.cpp | 84 +++++++++++++++++++++++ libutils/Looper_test.cpp | 44 ++---------- libutils/Looper_test_pipe.h | 55 +++++++++++++++ libutils/LruCache_fuzz.cpp | 74 +++++++++++++++++++++ libutils/Printer_fuzz.cpp | 52 +++++++++++++++ libutils/ProcessCallStack_fuzz.cpp | 77 +++++++++++++++++++++ libutils/PropertyMap_fuzz.cpp | 76 +++++++++++++++++++++ libutils/RWLock_fuzz.cpp | 50 ++++++++++++++ libutils/RefBase_fuzz.cpp | 103 +++++++++++++++++++++++++++++ libutils/StopWatch_fuzz.cpp | 45 +++++++++++++ 12 files changed, 732 insertions(+), 39 deletions(-) create mode 100644 libutils/CallStack_fuzz.cpp create mode 100644 libutils/Looper_fuzz.cpp create mode 100644 libutils/Looper_test_pipe.h create mode 100644 libutils/LruCache_fuzz.cpp create mode 100755 libutils/Printer_fuzz.cpp create mode 100644 libutils/ProcessCallStack_fuzz.cpp create mode 100755 libutils/PropertyMap_fuzz.cpp create mode 100755 libutils/RWLock_fuzz.cpp create mode 100755 libutils/RefBase_fuzz.cpp create mode 100644 libutils/StopWatch_fuzz.cpp diff --git a/libutils/Android.bp b/libutils/Android.bp index 9bd15c68e..05be220db 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -205,6 +205,7 @@ cc_defaults { shared_libs: [ "libutils", "libbase", + "liblog", ], } @@ -238,6 +239,66 @@ cc_fuzz { srcs: ["Vector_fuzz.cpp"], } +cc_fuzz { + name: "libutils_fuzz_printer", + defaults: ["libutils_fuzz_defaults"], + srcs: ["Printer_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_callstack", + defaults: ["libutils_fuzz_defaults"], + srcs: ["CallStack_fuzz.cpp"], + shared_libs: [ + "libutilscallstack", + ], +} + +cc_fuzz { + name: "libutils_fuzz_process_callstack", + defaults: ["libutils_fuzz_defaults"], + srcs: ["ProcessCallStack_fuzz.cpp"], + shared_libs: [ + "libutilscallstack", + ], +} + +cc_fuzz { + name: "libutils_fuzz_stopwatch", + defaults: ["libutils_fuzz_defaults"], + srcs: ["StopWatch_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_propertymap", + defaults: ["libutils_fuzz_defaults"], + srcs: ["PropertyMap_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_rwlock", + defaults: ["libutils_fuzz_defaults"], + srcs: ["RWLock_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_refbase", + defaults: ["libutils_fuzz_defaults"], + srcs: ["RefBase_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_lrucache", + defaults: ["libutils_fuzz_defaults"], + srcs: ["LruCache_fuzz.cpp"], +} + +cc_fuzz { + name: "libutils_fuzz_looper", + defaults: ["libutils_fuzz_defaults"], + srcs: ["Looper_fuzz.cpp"], +} + cc_test { name: "libutils_test", host_supported: true, diff --git a/libutils/CallStack_fuzz.cpp b/libutils/CallStack_fuzz.cpp new file mode 100644 index 000000000..e89b5b7ca --- /dev/null +++ b/libutils/CallStack_fuzz.cpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/CallStack.h" + +static constexpr int MAX_STRING_SIZE = 500; +static constexpr int MAX_IGNORE_DEPTH = 200; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + size_t ignoreDepth = dataProvider.ConsumeIntegralInRange(0, MAX_IGNORE_DEPTH); + int logPriority = dataProvider.ConsumeIntegral(); + pid_t tid = dataProvider.ConsumeIntegral(); + std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE); + std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE); + + const char* logTagChars = logTag.c_str(); + const char* prefixChars = prefix.c_str(); + + android::CallStack::CallStackUPtr callStack = android::CallStack::getCurrent(ignoreDepth); + android::CallStack* callstackPtr = callStack.get(); + android::CallStack::logStack(logTagChars, callstackPtr, + static_cast(logPriority)); + android::CallStack::stackToString(prefixChars); + + callstackPtr->log(logTagChars, static_cast(logPriority), prefixChars); + callstackPtr->clear(); + callstackPtr->getCurrent(ignoreDepth); + callstackPtr->log(logTagChars, static_cast(logPriority), prefixChars); + callstackPtr->update(ignoreDepth, tid); + callstackPtr->log(logTagChars, static_cast(logPriority), prefixChars); + + return 0; +} diff --git a/libutils/Looper_fuzz.cpp b/libutils/Looper_fuzz.cpp new file mode 100644 index 000000000..c3ae54ece --- /dev/null +++ b/libutils/Looper_fuzz.cpp @@ -0,0 +1,84 @@ +/* + * 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 + +#include + +#include + +#include "Looper_test_pipe.h" +#include "fuzzer/FuzzedDataProvider.h" + +using android::Looper; +using android::sp; + +// We don't want this to bog down fuzzing +static constexpr int MAX_POLL_DELAY = 50; +static constexpr int MAX_OPERATIONS = 500; + +void doNothing() {} +void* doNothingPointer = reinterpret_cast(doNothing); + +static int noopCallback(int, int, void*) { + return 0; +} + +std::vector, Pipe)>> operations = { + [](FuzzedDataProvider* dataProvider, sp looper, Pipe) -> void { + looper->pollOnce(dataProvider->ConsumeIntegralInRange(0, MAX_POLL_DELAY)); + }, + [](FuzzedDataProvider* dataProvider, sp looper, Pipe) -> void { + looper->pollAll(dataProvider->ConsumeIntegralInRange(0, MAX_POLL_DELAY)); + }, + // events and callback are nullptr + [](FuzzedDataProvider* dataProvider, sp looper, Pipe pipeObj) -> void { + looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral(), + dataProvider->ConsumeIntegral(), nullptr, nullptr); + }, + // Events is nullptr + [](FuzzedDataProvider* dataProvider, sp looper, Pipe pipeObj) -> void { + looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral(), + dataProvider->ConsumeIntegral(), noopCallback, nullptr); + }, + // callback is nullptr + [](FuzzedDataProvider* dataProvider, sp looper, Pipe pipeObj) -> void { + looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral(), + dataProvider->ConsumeIntegral(), nullptr, doNothingPointer); + }, + // callback and events both set + [](FuzzedDataProvider* dataProvider, sp looper, Pipe pipeObj) -> void { + looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral(), + dataProvider->ConsumeIntegral(), noopCallback, doNothingPointer); + }, + + [](FuzzedDataProvider*, sp looper, Pipe) -> void { looper->wake(); }, + [](FuzzedDataProvider*, sp, Pipe pipeObj) -> void { pipeObj.writeSignal(); }}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + Pipe pipeObj; + FuzzedDataProvider dataProvider(data, size); + sp looper = new Looper(dataProvider.ConsumeBool()); + + size_t opsRun = 0; + while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { + uint8_t op = dataProvider.ConsumeIntegralInRange(0, operations.size() - 1); + operations[op](&dataProvider, looper, pipeObj); + } + // Clear our pointer + looper.clear(); + return 0; +} diff --git a/libutils/Looper_test.cpp b/libutils/Looper_test.cpp index 37bdf0544..34f424b83 100644 --- a/libutils/Looper_test.cpp +++ b/libutils/Looper_test.cpp @@ -2,12 +2,13 @@ // Copyright 2010 The Android Open Source Project // -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include "Looper_test_pipe.h" #include @@ -24,41 +25,6 @@ enum { MSG_TEST4 = 4, }; -class Pipe { -public: - int sendFd; - int receiveFd; - - Pipe() { - int fds[2]; - ::pipe(fds); - - receiveFd = fds[0]; - sendFd = fds[1]; - } - - ~Pipe() { - if (sendFd != -1) { - ::close(sendFd); - } - - if (receiveFd != -1) { - ::close(receiveFd); - } - } - - status_t writeSignal() { - ssize_t nWritten = ::write(sendFd, "*", 1); - return nWritten == 1 ? 0 : -errno; - } - - status_t readSignal() { - char buf[1]; - ssize_t nRead = ::read(receiveFd, buf, 1); - return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno; - } -}; - class DelayedTask : public Thread { int mDelayMillis; diff --git a/libutils/Looper_test_pipe.h b/libutils/Looper_test_pipe.h new file mode 100644 index 000000000..77b7b8b36 --- /dev/null +++ b/libutils/Looper_test_pipe.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#pragma once +#include +/** + * A pipe class for use when testing or fuzzing Looper + */ +class Pipe { + public: + int sendFd; + int receiveFd; + + Pipe() { + int fds[2]; + ::pipe(fds); + + receiveFd = fds[0]; + sendFd = fds[1]; + } + + ~Pipe() { + if (sendFd != -1) { + ::close(sendFd); + } + + if (receiveFd != -1) { + ::close(receiveFd); + } + } + + android::status_t writeSignal() { + ssize_t nWritten = ::write(sendFd, "*", 1); + return nWritten == 1 ? 0 : -errno; + } + + android::status_t readSignal() { + char buf[1]; + ssize_t nRead = ::read(receiveFd, buf, 1); + return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno; + } +}; diff --git a/libutils/LruCache_fuzz.cpp b/libutils/LruCache_fuzz.cpp new file mode 100644 index 000000000..f8bacfcbc --- /dev/null +++ b/libutils/LruCache_fuzz.cpp @@ -0,0 +1,74 @@ +/* + * 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 + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/LruCache.h" +#include "utils/StrongPointer.h" + +typedef android::LruCache FuzzCache; + +static constexpr uint32_t MAX_CACHE_ENTRIES = 800; + +class NoopRemovedCallback : public android::OnEntryRemoved { + public: + void operator()(size_t&, size_t&) { + // noop + } +}; + +static NoopRemovedCallback callback; + +static const std::vector> operations = { + [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->removeOldest(); }, + [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->peekOldestValue(); }, + [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->clear(); }, + [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->size(); }, + [](FuzzedDataProvider*, FuzzCache* cache) -> void { + android::LruCache::Iterator iter(*cache); + while (iter.next()) { + iter.key(); + iter.value(); + } + }, + [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void { + size_t key = dataProvider->ConsumeIntegral(); + size_t val = dataProvider->ConsumeIntegral(); + cache->put(key, val); + }, + [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void { + size_t key = dataProvider->ConsumeIntegral(); + cache->get(key); + }, + [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void { + size_t key = dataProvider->ConsumeIntegral(); + cache->remove(key); + }, + [](FuzzedDataProvider*, FuzzCache* cache) -> void { + cache->setOnEntryRemovedListener(&callback); + }}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + FuzzCache cache(MAX_CACHE_ENTRIES); + while (dataProvider.remaining_bytes() > 0) { + uint8_t op = dataProvider.ConsumeIntegral() % operations.size(); + operations[op](&dataProvider, &cache); + } + + return 0; +} diff --git a/libutils/Printer_fuzz.cpp b/libutils/Printer_fuzz.cpp new file mode 100755 index 000000000..0180d41f6 --- /dev/null +++ b/libutils/Printer_fuzz.cpp @@ -0,0 +1,52 @@ +/* + * 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 "android-base/file.h" +#include "android/log.h" +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/Printer.h" +#include "utils/String8.h" +static constexpr int MAX_STR_SIZE = 1000; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + android::String8 outStr = android::String8(); + // Line indent/formatting + uint indent = dataProvider.ConsumeIntegral(); + std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE); + std::string line = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE); + + // Misc properties + std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE); + android_LogPriority priority = + static_cast(dataProvider.ConsumeIntegral()); + bool ignoreBlankLines = dataProvider.ConsumeBool(); + + TemporaryFile tf; + android::FdPrinter filePrinter = android::FdPrinter(tf.fd, indent, prefix.c_str()); + android::String8Printer stringPrinter = android::String8Printer(&outStr); + android::PrefixPrinter printer = android::PrefixPrinter(stringPrinter, prefix.c_str()); + android::LogPrinter logPrinter = + android::LogPrinter(logTag.c_str(), priority, prefix.c_str(), ignoreBlankLines); + + printer.printLine(line.c_str()); + printer.printFormatLine("%s", line.c_str()); + logPrinter.printLine(line.c_str()); + logPrinter.printFormatLine("%s", line.c_str()); + filePrinter.printLine(line.c_str()); + filePrinter.printFormatLine("%s", line.c_str()); + return 0; +} diff --git a/libutils/ProcessCallStack_fuzz.cpp b/libutils/ProcessCallStack_fuzz.cpp new file mode 100644 index 000000000..30136cda7 --- /dev/null +++ b/libutils/ProcessCallStack_fuzz.cpp @@ -0,0 +1,77 @@ +/* + * 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 +#include + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/ProcessCallStack.h" +using android::ProcessCallStack; + +static constexpr int MAX_NAME_SIZE = 1000; +static constexpr int MAX_LOG_META_SIZE = 1000; +static constexpr uint8_t MAX_THREADS = 10; + +std::atomic_bool ranCallStackUpdate(false); +void loop() { + while (!ranCallStackUpdate.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } +} + +void spawnThreads(FuzzedDataProvider* dataProvider) { + std::vector threads = std::vector(); + + // Get the number of threads to generate + uint8_t count = dataProvider->ConsumeIntegralInRange(1, MAX_THREADS); + + // Generate threads + for (uint8_t i = 0; i < count; i++) { + std::string threadName = + dataProvider->ConsumeRandomLengthString(MAX_NAME_SIZE).append(std::to_string(i)); + std::thread th = std::thread(loop); + pthread_setname_np(th.native_handle(), threadName.c_str()); + threads.push_back(move(th)); + } + + // Collect thread information + ProcessCallStack callStack = ProcessCallStack(); + callStack.update(); + + // Tell our patiently waiting threads they can be done now. + ranCallStackUpdate.store(true); + + std::string logTag = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE); + std::string prefix = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE); + // Both of these, along with dump, all call print() under the hood, + // Which is covered by the Printer fuzzer. + callStack.log(logTag.c_str()); + callStack.toString(prefix.c_str()); + + // Check size + callStack.size(); + + // wait for any remaining threads + for (auto& thread : threads) { + thread.join(); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + spawnThreads(&dataProvider); + return 0; +} diff --git a/libutils/PropertyMap_fuzz.cpp b/libutils/PropertyMap_fuzz.cpp new file mode 100755 index 000000000..fd50729f2 --- /dev/null +++ b/libutils/PropertyMap_fuzz.cpp @@ -0,0 +1,76 @@ +/* + * 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 "android-base/file.h" +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/PropertyMap.h" +#include "utils/String8.h" + +static constexpr int MAX_FILE_SIZE = 256; +static constexpr int MAX_STR_LEN = 2048; +static constexpr int MAX_OPERATIONS = 1000; + +static const std::vector> + operations = { + [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { + propertyMap.getProperties(); + }, + [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { + propertyMap.clear(); + }, + [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { + std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + android::String8 key = android::String8(keyStr.c_str()); + propertyMap.hasProperty(key); + }, + [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { + std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + android::String8 key = android::String8(keyStr.c_str()); + android::String8 out; + propertyMap.tryGetProperty(key, out); + }, + [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { + TemporaryFile tf; + // Generate file contents + std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE); + // If we have string contents, dump them into the file. + // Otherwise, just leave it as an empty file. + if (contents.length() > 0) { + const char* bytes = contents.c_str(); + android::base::WriteStringToFd(bytes, tf.fd); + } + android::PropertyMap* mapPtr = &propertyMap; + android::PropertyMap::load(android::String8(tf.path), &mapPtr); + }, + [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { + std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + android::String8 key = android::String8(keyStr.c_str()); + android::String8 val = android::String8(valStr.c_str()); + propertyMap.addProperty(key, val); + }, +}; +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + android::PropertyMap proprtyMap = android::PropertyMap(); + + int opsRun = 0; + while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { + uint8_t op = dataProvider.ConsumeIntegralInRange(0, operations.size() - 1); + operations[op](&dataProvider, proprtyMap); + } + return 0; +} diff --git a/libutils/RWLock_fuzz.cpp b/libutils/RWLock_fuzz.cpp new file mode 100755 index 000000000..e07590549 --- /dev/null +++ b/libutils/RWLock_fuzz.cpp @@ -0,0 +1,50 @@ +/* + * 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 + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/RWLock.h" + +static constexpr int MAX_OPERATIONS = 100; +static constexpr int MAX_NAME_LEN = 2048; + +static const std::vector> operations = { + [](android::RWLock* lock) -> void { + // This might return a non-zero value if already locked + // Either way we are definitely locked now. + lock->tryWriteLock(); + }, + [](android::RWLock* lock) -> void { lock->tryReadLock(); }, + [](android::RWLock* lock) -> void { lock->unlock(); }, +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN); + int type = dataProvider.ConsumeIntegral(); + android::RWLock rwLock = android::RWLock(type, nameStr.c_str()); + std::vector opsToRun = dataProvider.ConsumeRemainingBytes(); + int opsRun = 0; + for (auto it : opsToRun) { + if (opsRun++ >= MAX_OPERATIONS) { + break; + } + it = it % operations.size(); + operations[it](&rwLock); + } + rwLock.unlock(); + return 0; +} diff --git a/libutils/RefBase_fuzz.cpp b/libutils/RefBase_fuzz.cpp new file mode 100755 index 000000000..2a92531ee --- /dev/null +++ b/libutils/RefBase_fuzz.cpp @@ -0,0 +1,103 @@ +/* + * 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 +#include + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/RefBase.h" +#include "utils/StrongPointer.h" +using android::RefBase; +using android::sp; +using android::wp; + +static constexpr int REFBASE_INITIAL_STRONG_VALUE = (1 << 28); +static constexpr int REFBASE_MAX_COUNT = 0xfffff; + +static constexpr int MAX_OPERATIONS = 100; +static constexpr int MAX_THREADS = 10; + +bool canDecrementStrong(RefBase* ref) { + // There's an assert around decrementing the strong count too much that causes an artificial + // crash This is just running BAD_STRONG from RefBase + const int32_t count = ref->getStrongCount() - 1; + return !(count == 0 || ((count) & (~(REFBASE_MAX_COUNT | REFBASE_INITIAL_STRONG_VALUE))) != 0); +} +bool canDecrementWeak(RefBase* ref) { + const int32_t count = ref->getWeakRefs()->getWeakCount() - 1; + return !((count) == 0 || ((count) & (~REFBASE_MAX_COUNT)) != 0); +} + +struct RefBaseSubclass : public RefBase { + RefBaseSubclass() {} + virtual ~RefBaseSubclass() {} +}; + +std::vector> operations = { + [](RefBaseSubclass* ref) -> void { ref->getStrongCount(); }, + [](RefBaseSubclass* ref) -> void { ref->printRefs(); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->getWeakCount(); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->refBase(); }, + [](RefBaseSubclass* ref) -> void { ref->incStrong(nullptr); }, + [](RefBaseSubclass* ref) -> void { + if (canDecrementStrong(ref)) { + ref->decStrong(nullptr); + } + }, + [](RefBaseSubclass* ref) -> void { ref->forceIncStrong(nullptr); }, + [](RefBaseSubclass* ref) -> void { ref->createWeak(nullptr); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncStrong(nullptr); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncWeak(nullptr); }, + [](RefBaseSubclass* ref) -> void { + if (canDecrementWeak(ref)) { + ref->getWeakRefs()->decWeak(nullptr); + } + }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->incWeak(nullptr); }, + [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); }, +}; + +void loop(RefBaseSubclass* loopRef, const std::vector& fuzzOps) { + for (auto op : fuzzOps) { + operations[op % operations.size()](loopRef); + } +} + +void spawnThreads(FuzzedDataProvider* dataProvider) { + std::vector threads = std::vector(); + + // Get the number of threads to generate + uint8_t count = dataProvider->ConsumeIntegralInRange(1, MAX_THREADS); + + // Generate threads + for (uint8_t i = 0; i < count; i++) { + RefBaseSubclass* threadRef = new RefBaseSubclass(); + uint8_t opCount = dataProvider->ConsumeIntegralInRange(1, MAX_OPERATIONS); + std::vector threadOperations = dataProvider->ConsumeBytes(opCount); + std::thread tmp = std::thread(loop, threadRef, threadOperations); + threads.push_back(move(tmp)); + } + + for (auto& th : threads) { + th.join(); + } +} +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + spawnThreads(&dataProvider); + return 0; +} diff --git a/libutils/StopWatch_fuzz.cpp b/libutils/StopWatch_fuzz.cpp new file mode 100644 index 000000000..63d8a28c9 --- /dev/null +++ b/libutils/StopWatch_fuzz.cpp @@ -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. + */ + +#include "fuzzer/FuzzedDataProvider.h" +#include "utils/StopWatch.h" + +static constexpr int MAX_OPERATIONS = 100; +static constexpr int MAX_NAME_LEN = 2048; + +static const std::vector> operations = { + [](android::StopWatch stopWatch) -> void { stopWatch.reset(); }, + [](android::StopWatch stopWatch) -> void { stopWatch.lap(); }, + [](android::StopWatch stopWatch) -> void { stopWatch.elapsedTime(); }, + [](android::StopWatch stopWatch) -> void { stopWatch.name(); }, +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider dataProvider(data, size); + std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN); + int clockVal = dataProvider.ConsumeIntegral(); + android::StopWatch stopWatch = android::StopWatch(nameStr.c_str(), clockVal); + std::vector opsToRun = dataProvider.ConsumeRemainingBytes(); + int opsRun = 0; + for (auto it : opsToRun) { + if (opsRun++ >= MAX_OPERATIONS) { + break; + } + it = it % operations.size(); + operations[it](stopWatch); + } + return 0; +}