summaryrefslogtreecommitdiff
path: root/lib/Fuzzer
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer')
-rw-r--r--lib/Fuzzer/FuzzerDriver.cpp3
-rw-r--r--lib/Fuzzer/FuzzerFlags.def8
-rw-r--r--lib/Fuzzer/FuzzerInternal.h1
-rw-r--r--lib/Fuzzer/FuzzerLoop.cpp20
-rw-r--r--lib/Fuzzer/FuzzerMutate.cpp5
-rw-r--r--lib/Fuzzer/afl/afl_driver.cpp57
-rw-r--r--lib/Fuzzer/test/AFLDriverTest.cpp8
-rw-r--r--lib/Fuzzer/test/CMakeLists.txt1
-rw-r--r--lib/Fuzzer/test/OverwriteInputTest.cpp13
-rw-r--r--lib/Fuzzer/test/afl-driver.test26
-rw-r--r--lib/Fuzzer/test/overwrite-input.test2
11 files changed, 124 insertions, 20 deletions
diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp
index b85ba210afb3..e93c79cfcec6 100644
--- a/lib/Fuzzer/FuzzerDriver.cpp
+++ b/lib/Fuzzer/FuzzerDriver.cpp
@@ -656,7 +656,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
SMR.WaitClient();
size_t Size = SMR.ReadByteArraySize();
SMR.WriteByteArray(nullptr, 0);
- F->RunOne(SMR.GetByteArray(), Size);
+ const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size);
+ F->RunOne(tmp.data(), tmp.size());
SMR.PostServer();
}
return 0;
diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def
index 0a1ff1b1df6a..7ff196c8fa96 100644
--- a/lib/Fuzzer/FuzzerFlags.def
+++ b/lib/Fuzzer/FuzzerFlags.def
@@ -92,10 +92,10 @@ FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
FUZZER_FLAG_INT(print_corpus_stats, 0,
"If 1, print statistics on corpus elements at exit.")
-FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit."
- " Experimental, only with trace-pc-guard")
-FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information at exit."
- " Experimental, only with trace-pc-guard")
+FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
+ " at exit.")
+FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a"
+ " .sancov file at exit.")
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h
index ad067ee2c0d9..5f184c2316e2 100644
--- a/lib/Fuzzer/FuzzerInternal.h
+++ b/lib/Fuzzer/FuzzerInternal.h
@@ -91,6 +91,7 @@ public:
private:
void AlarmCallback();
void CrashCallback();
+ void CrashOnOverwrittenData();
void InterruptCallback();
void MutateAndTestOne();
void ReportNewCoverage(InputInfo *II, const Unit &U);
diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp
index d84c3dbdaf77..14caa203c5ef 100644
--- a/lib/Fuzzer/FuzzerLoop.cpp
+++ b/lib/Fuzzer/FuzzerLoop.cpp
@@ -422,6 +422,24 @@ size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
return CurrentUnitSize;
}
+void Fuzzer::CrashOnOverwrittenData() {
+ Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n",
+ GetPid());
+ DumpCurrentUnit("crash-");
+ Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+// Compare two arrays, but not all bytes if the arrays are large.
+static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
+ const size_t Limit = 64;
+ if (Size <= 64)
+ return !memcmp(A, B, Size);
+ // Compare first and last Limit/2 bytes.
+ return !memcmp(A, B, Limit / 2) &&
+ !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
+}
+
void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
assert(InFuzzingThread());
if (SMR.IsClient())
@@ -443,6 +461,8 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
(void)Res;
assert(Res == 0);
HasMoreMallocsThanFrees = AllocTracer.Stop();
+ if (!LooseMemeq(DataCopy, Data, Size))
+ CrashOnOverwrittenData();
CurrentUnitSize = 0;
delete[] DataCopy;
}
diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp
index cd846c7deec5..e60d4130de10 100644
--- a/lib/Fuzzer/FuzzerMutate.cpp
+++ b/lib/Fuzzer/FuzzerMutate.cpp
@@ -217,11 +217,12 @@ DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
size_t NumPositions = 0;
for (const uint8_t *Cur = Data;
Cur < End && NumPositions < kMaxNumPositions; Cur++) {
- Cur = (uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
+ Cur =
+ (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
if (!Cur) break;
Positions[NumPositions++] = Cur - Data;
}
- if (!NumPositions) break;
+ if (!NumPositions) continue;
return DictionaryEntry(W, Positions[Rand(NumPositions)]);
}
DictionaryEntry DE(W);
diff --git a/lib/Fuzzer/afl/afl_driver.cpp b/lib/Fuzzer/afl/afl_driver.cpp
index b3a54e57fceb..3815ed11cf60 100644
--- a/lib/Fuzzer/afl/afl_driver.cpp
+++ b/lib/Fuzzer/afl/afl_driver.cpp
@@ -59,6 +59,11 @@ statistics from the file. If that fails then the process will quit.
#include <signal.h>
#include <sys/resource.h>
#include <sys/time.h>
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+
// Platform detection. Copied from FuzzerInternal.h
#ifdef __linux__
#define LIBFUZZER_LINUX 1
@@ -245,17 +250,39 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
return 0;
}
+// Execute any files provided as parameters.
+int ExecuteFilesOnyByOne(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::ifstream in(argv[i]);
+ in.seekg(0, in.end);
+ size_t length = in.tellg();
+ in.seekg (0, in.beg);
+ std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
+ // Allocate exactly length bytes so that we reliably catch buffer overflows.
+ std::vector<char> bytes(length);
+ in.read(bytes.data(), bytes.size());
+ assert(in);
+ LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
+ bytes.size());
+ std::cout << "Execution successfull" << std::endl;
+ }
+ return 0;
+}
+
int main(int argc, char **argv) {
- fprintf(stderr, "======================= INFO =========================\n"
- "This binary is built for AFL-fuzz.\n"
- "To run the target function on a single input execute this:\n"
- " %s < INPUT_FILE\n"
- "To run the fuzzing execute this:\n"
- " afl-fuzz [afl-flags] %s [N] "
- "-- run N fuzzing iterations before "
- "re-spawning the process (default: 1000)\n"
- "======================================================\n",
- argv[0], argv[0]);
+ fprintf(stderr,
+ "======================= INFO =========================\n"
+ "This binary is built for AFL-fuzz.\n"
+ "To run the target function on individual input(s) execute this:\n"
+ " %s < INPUT_FILE\n"
+ "or\n"
+ " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
+ "To fuzz with afl-fuzz execute this:\n"
+ " afl-fuzz [afl-flags] %s [-N]\n"
+ "afl-fuzz will run N iterations before "
+ "re-spawning the process (default: 1000)\n"
+ "======================================================\n",
+ argv[0], argv[0], argv[0]);
if (LLVMFuzzerInitialize)
LLVMFuzzerInitialize(&argc, &argv);
// Do any other expensive one-time initialization here.
@@ -266,8 +293,14 @@ int main(int argc, char **argv) {
__afl_manual_init();
int N = 1000;
- if (argc >= 2)
- N = atoi(argv[1]);
+ if (argc == 2 && argv[1][0] == '-')
+ N = atoi(argv[1] + 1);
+ else if(argc == 2 && (N = atoi(argv[1])) > 0)
+ fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
+ argv[0], N);
+ else if (argc > 1)
+ return ExecuteFilesOnyByOne(argc, argv);
+
assert(N > 0);
time_t unit_time_secs;
int num_runs = 0;
diff --git a/lib/Fuzzer/test/AFLDriverTest.cpp b/lib/Fuzzer/test/AFLDriverTest.cpp
index 3dd0b6117305..e3f5f7100883 100644
--- a/lib/Fuzzer/test/AFLDriverTest.cpp
+++ b/lib/Fuzzer/test/AFLDriverTest.cpp
@@ -4,19 +4,25 @@
// Contains dummy functions used to avoid dependency on AFL.
#include <stdint.h>
#include <stdlib.h>
+#include <stdio.h>
extern "C" void __afl_manual_init() {}
-extern "C" int __afl_persistent_loop(unsigned int) {
+extern "C" int __afl_persistent_loop(unsigned int N) {
+ static int Count = N;
+ fprintf(stderr, "__afl_persistent_loop calle, Count = %d\n", Count);
+ if (Count--) return 1;
return 0;
}
// This declaration exists to prevent the Darwin linker
// from complaining about this being a missing weak symbol.
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ fprintf(stderr, "LLVMFuzzerInitialize called\n");
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ fprintf(stderr, "LLVMFuzzerTestOneInput called; Size = %zd\n", Size);
return 0;
}
diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt
index cd049d3f03d8..b39938a705f6 100644
--- a/lib/Fuzzer/test/CMakeLists.txt
+++ b/lib/Fuzzer/test/CMakeLists.txt
@@ -104,6 +104,7 @@ set(Tests
OneHugeAllocTest
OutOfMemoryTest
OutOfMemorySingleLargeMallocTest
+ OverwriteInputTest
RepeatedMemcmp
RepeatedBytesTest
SimpleCmpTest
diff --git a/lib/Fuzzer/test/OverwriteInputTest.cpp b/lib/Fuzzer/test/OverwriteInputTest.cpp
new file mode 100644
index 000000000000..e688682346a6
--- /dev/null
+++ b/lib/Fuzzer/test/OverwriteInputTest.cpp
@@ -0,0 +1,13 @@
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Simple test for a fuzzer. Make sure we abort if Data is overwritten.
+#include <cstdint>
+#include <iostream>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size)
+ *const_cast<uint8_t*>(Data) = 1;
+ return 0;
+}
+
diff --git a/lib/Fuzzer/test/afl-driver.test b/lib/Fuzzer/test/afl-driver.test
new file mode 100644
index 000000000000..6eab23cc3636
--- /dev/null
+++ b/lib/Fuzzer/test/afl-driver.test
@@ -0,0 +1,26 @@
+REQUIRES: linux
+RUN: echo -n "abc" > %t.file3
+RUN: echo -n "abcd" > %t.file4
+
+RUN: AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1
+CHECK1: __afl_persistent_loop calle, Count = 1000
+CHECK1: LLVMFuzzerTestOneInput called; Size = 3
+
+
+RUN: AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2
+CHECK2: __afl_persistent_loop calle, Count = 42
+CHECK2: LLVMFuzzerTestOneInput called; Size = 3
+
+
+RUN: AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3
+CHECK3: WARNING: using the deprecated call style
+CHECK3: __afl_persistent_loop calle, Count = 666
+CHECK3: LLVMFuzzerTestOneInput called; Size = 3
+
+
+RUN: AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4
+CHECK4: LLVMFuzzerTestOneInput called; Size = 3
+
+RUN: AFLDriverTest %t.file3 %t.file4 2>&1 | FileCheck %s --check-prefix=CHECK5
+CHECK5: LLVMFuzzerTestOneInput called; Size = 3
+CHECK5: LLVMFuzzerTestOneInput called; Size = 4
diff --git a/lib/Fuzzer/test/overwrite-input.test b/lib/Fuzzer/test/overwrite-input.test
new file mode 100644
index 000000000000..81c27909e8df
--- /dev/null
+++ b/lib/Fuzzer/test/overwrite-input.test
@@ -0,0 +1,2 @@
+RUN: not LLVMFuzzer-OverwriteInputTest 2>&1 | FileCheck %s
+CHECK: ERROR: libFuzzer: fuzz target overwrites it's const input