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 <dylan.katz@leviathansecurity.com>
Change-Id: I2f9f35c18b13338c282fb7f9c3ea4099ecb2c56f
This commit is contained in:
Dylan Katz 2020-07-02 11:51:44 -07:00
parent c8e4154d89
commit 7168f2726e
12 changed files with 732 additions and 39 deletions

View file

@ -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,

View file

@ -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 <memory.h>
#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<size_t>(0, MAX_IGNORE_DEPTH);
int logPriority = dataProvider.ConsumeIntegral<int>();
pid_t tid = dataProvider.ConsumeIntegral<pid_t>();
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<android_LogPriority>(logPriority));
android::CallStack::stackToString(prefixChars);
callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
callstackPtr->clear();
callstackPtr->getCurrent(ignoreDepth);
callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
callstackPtr->update(ignoreDepth, tid);
callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
return 0;
}

84
libutils/Looper_fuzz.cpp Normal file
View file

@ -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 <sys/select.h>
#include <iostream>
#include <utils/Looper.h>
#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<void*>(doNothing);
static int noopCallback(int, int, void*) {
return 0;
}
std::vector<std::function<void(FuzzedDataProvider*, sp<Looper>, Pipe)>> operations = {
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
looper->pollOnce(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
},
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
looper->pollAll(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
},
// events and callback are nullptr
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
dataProvider->ConsumeIntegral<int>(), nullptr, nullptr);
},
// Events is nullptr
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
dataProvider->ConsumeIntegral<int>(), noopCallback, nullptr);
},
// callback is nullptr
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
dataProvider->ConsumeIntegral<int>(), nullptr, doNothingPointer);
},
// callback and events both set
[](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
dataProvider->ConsumeIntegral<int>(), noopCallback, doNothingPointer);
},
[](FuzzedDataProvider*, sp<Looper> looper, Pipe) -> void { looper->wake(); },
[](FuzzedDataProvider*, sp<Looper>, Pipe pipeObj) -> void { pipeObj.writeSignal(); }};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
Pipe pipeObj;
FuzzedDataProvider dataProvider(data, size);
sp<Looper> looper = new Looper(dataProvider.ConsumeBool());
size_t opsRun = 0;
while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
operations[op](&dataProvider, looper, pipeObj);
}
// Clear our pointer
looper.clear();
return 0;
}

View file

@ -2,12 +2,13 @@
// Copyright 2010 The Android Open Source Project
//
#include <utils/Looper.h>
#include <utils/Timers.h>
#include <utils/StopWatch.h>
#include <gtest/gtest.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>
#include <utils/Looper.h>
#include <utils/StopWatch.h>
#include <utils/Timers.h>
#include "Looper_test_pipe.h"
#include <utils/threads.h>
@ -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;

View file

@ -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 <unistd.h>
/**
* 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;
}
};

View file

@ -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 <functional>
#include "fuzzer/FuzzedDataProvider.h"
#include "utils/LruCache.h"
#include "utils/StrongPointer.h"
typedef android::LruCache<size_t, size_t> FuzzCache;
static constexpr uint32_t MAX_CACHE_ENTRIES = 800;
class NoopRemovedCallback : public android::OnEntryRemoved<size_t, size_t> {
public:
void operator()(size_t&, size_t&) {
// noop
}
};
static NoopRemovedCallback callback;
static const std::vector<std::function<void(FuzzedDataProvider*, FuzzCache*)>> 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<size_t, size_t>::Iterator iter(*cache);
while (iter.next()) {
iter.key();
iter.value();
}
},
[](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
size_t key = dataProvider->ConsumeIntegral<size_t>();
size_t val = dataProvider->ConsumeIntegral<size_t>();
cache->put(key, val);
},
[](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
size_t key = dataProvider->ConsumeIntegral<size_t>();
cache->get(key);
},
[](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
size_t key = dataProvider->ConsumeIntegral<size_t>();
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<uint8_t>() % operations.size();
operations[op](&dataProvider, &cache);
}
return 0;
}

52
libutils/Printer_fuzz.cpp Executable file
View file

@ -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<uint>();
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<android_LogPriority>(dataProvider.ConsumeIntegral<int>());
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;
}

View file

@ -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 <atomic>
#include <thread>
#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<std::thread> threads = std::vector<std::thread>();
// Get the number of threads to generate
uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(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;
}

76
libutils/PropertyMap_fuzz.cpp Executable file
View file

@ -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<std::function<void(FuzzedDataProvider*, android::PropertyMap)>>
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<uint8_t>(0, operations.size() - 1);
operations[op](&dataProvider, proprtyMap);
}
return 0;
}

50
libutils/RWLock_fuzz.cpp Executable file
View file

@ -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 <functional>
#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<std::function<void(android::RWLock*)>> 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<int>();
android::RWLock rwLock = android::RWLock(type, nameStr.c_str());
std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
int opsRun = 0;
for (auto it : opsToRun) {
if (opsRun++ >= MAX_OPERATIONS) {
break;
}
it = it % operations.size();
operations[it](&rwLock);
}
rwLock.unlock();
return 0;
}

103
libutils/RefBase_fuzz.cpp Executable file
View file

@ -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 <atomic>
#include <thread>
#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<std::function<void(RefBaseSubclass*)>> 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<uint8_t>& fuzzOps) {
for (auto op : fuzzOps) {
operations[op % operations.size()](loopRef);
}
}
void spawnThreads(FuzzedDataProvider* dataProvider) {
std::vector<std::thread> threads = std::vector<std::thread>();
// Get the number of threads to generate
uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_THREADS);
// Generate threads
for (uint8_t i = 0; i < count; i++) {
RefBaseSubclass* threadRef = new RefBaseSubclass();
uint8_t opCount = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_OPERATIONS);
std::vector<uint8_t> threadOperations = dataProvider->ConsumeBytes<uint8_t>(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;
}

View file

@ -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<std::function<void(android::StopWatch)>> 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<int>();
android::StopWatch stopWatch = android::StopWatch(nameStr.c_str(), clockVal);
std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
int opsRun = 0;
for (auto it : opsToRun) {
if (opsRun++ >= MAX_OPERATIONS) {
break;
}
it = it % operations.size();
operations[it](stopWatch);
}
return 0;
}