Skip to content

Commit

Permalink
A duplicate of libfuzzer
Browse files Browse the repository at this point in the history
  • Loading branch information
DonggeLiu committed Aug 4, 2024
1 parent aeae566 commit 5a1a3e3
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 0 deletions.
26 changes: 26 additions & 0 deletions fuzzers/libfuzzer_test/builder.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2020 Google LLC
#
# 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.

ARG parent_image
FROM $parent_image

RUN git clone https://github.com/llvm/llvm-project.git /llvm-project && \
cd /llvm-project && \
git checkout 5cda4dc7b4d28fcd11307d4234c513ff779a1c6f && \
cd compiler-rt/lib/fuzzer && \
(for f in *.cpp; do \
clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \
done && wait) && \
ar r libFuzzer.a *.o && \
cp libFuzzer.a /usr/lib
102 changes: 102 additions & 0 deletions fuzzers/libfuzzer_test/fuzzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Copyright 2020 Google LLC
#
# 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.
"""Integration code for libFuzzer fuzzer."""

import subprocess
import os

from fuzzers import utils


def build():
"""Build benchmark."""
# With LibFuzzer we use -fsanitize=fuzzer-no-link for build CFLAGS and then
# /usr/lib/libFuzzer.a as the FUZZER_LIB for the main fuzzing binary. This
# allows us to link against a version of LibFuzzer that we specify.
cflags = ['-fsanitize=fuzzer-no-link']
utils.append_flags('CFLAGS', cflags)
utils.append_flags('CXXFLAGS', cflags)

os.environ['CC'] = 'clang'
os.environ['CXX'] = 'clang++'
os.environ['FUZZER_LIB'] = '/usr/lib/libFuzzer.a'

utils.build_benchmark()


def fuzz(input_corpus, output_corpus, target_binary):
"""Run fuzzer. Wrapper that uses the defaults when calling
run_fuzzer."""
run_fuzzer(input_corpus, output_corpus, target_binary)


def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None):
"""Run fuzzer."""
if extra_flags is None:
extra_flags = []

# Seperate out corpus and crash directories as sub-directories of
# |output_corpus| to avoid conflicts when corpus directory is reloaded.
crashes_dir = os.path.join(output_corpus, 'crashes')
output_corpus = os.path.join(output_corpus, 'corpus')
os.makedirs(crashes_dir)
os.makedirs(output_corpus)

# Enable symbolization if needed.
# Note: if the flags are like `symbolize=0:..:symbolize=1` then
# only symbolize=1 is respected.
for flag in extra_flags:
if flag.startswith('-focus_function'):
if 'ASAN_OPTIONS' in os.environ:
os.environ['ASAN_OPTIONS'] += ':symbolize=1'
else:
os.environ['ASAN_OPTIONS'] = 'symbolize=1'
if 'UBSAN_OPTIONS' in os.environ:
os.environ['UBSAN_OPTIONS'] += ':symbolize=1'
else:
os.environ['UBSAN_OPTIONS'] = 'symbolize=1'
break

flags = [
'-print_final_stats=1',
# `close_fd_mask` to prevent too much logging output from the target.
'-close_fd_mask=3',
# Run in fork mode to allow ignoring ooms, timeouts, crashes and
# continue fuzzing indefinitely.
'-fork=1',
'-ignore_ooms=1',
'-ignore_timeouts=1',
'-ignore_crashes=1',
'-entropic=1',
'-keep_seed=1',
'-cross_over_uniform_dist=1',
'-entropic_scale_per_exec_time=1',

# Don't use LSAN's leak detection. Other fuzzers won't be using it and
# using it will cause libFuzzer to find "crashes" no one cares about.
'-detect_leaks=0',

# Store crashes along with corpus for bug based benchmarking.
f'-artifact_prefix={crashes_dir}/',
]
flags += extra_flags
if 'ADDITIONAL_ARGS' in os.environ:
flags += os.environ['ADDITIONAL_ARGS'].split(' ')
dictionary_path = utils.get_dictionary_path(target_binary)
if dictionary_path:
flags.append('-dict=' + dictionary_path)

command = [target_binary] + flags + [output_corpus, input_corpus]
print('[run_fuzzer] Running command: ' + ' '.join(command))
subprocess.check_call(command)
100 changes: 100 additions & 0 deletions fuzzers/libfuzzer_test/patch.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
diff --git a/compiler-rt/lib/fuzzer/FuzzerFork.cpp b/compiler-rt/lib/fuzzer/FuzzerFork.cpp
index 84725d2..4e1a506 100644
--- a/compiler-rt/lib/fuzzer/FuzzerFork.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerFork.cpp
@@ -26,6 +26,8 @@
#include <queue>
#include <sstream>
#include <thread>
+#include <sys/stat.h>
+#include <iostream>

namespace fuzzer {

@@ -70,6 +72,8 @@ struct FuzzJob {
std::string SeedListPath;
std::string CFPath;
size_t JobId;
+ bool Executing = false;
+ Vector<std::string> CopiedSeeds;

int DftTimeInSeconds = 0;

@@ -124,7 +128,6 @@ struct GlobalEnv {
Cmd.addFlag("reload", "0"); // working in an isolated dir, no reload.
Cmd.addFlag("print_final_stats", "1");
Cmd.addFlag("print_funcs", "0"); // no need to spend time symbolizing.
- Cmd.addFlag("max_total_time", std::to_string(std::min((size_t)300, JobId)));
Cmd.addFlag("stop_file", StopFile());
if (!DataFlowBinary.empty()) {
Cmd.addFlag("data_flow_trace", DFTDir);
@@ -133,11 +136,10 @@ struct GlobalEnv {
}
auto Job = new FuzzJob;
std::string Seeds;
- if (size_t CorpusSubsetSize =
- std::min(Files.size(), (size_t)sqrt(Files.size() + 2))) {
+ if (size_t CorpusSubsetSize = Files.size()) {
auto Time1 = std::chrono::system_clock::now();
for (size_t i = 0; i < CorpusSubsetSize; i++) {
- auto &SF = Files[Rand->SkewTowardsLast(Files.size())];
+ auto &SF = Files[i];
Seeds += (Seeds.empty() ? "" : ",") + SF;
CollectDFT(SF);
}
@@ -213,11 +215,20 @@ struct GlobalEnv {
Set<uint32_t> NewFeatures, NewCov;
CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features,
&NewFeatures, Cov, &NewCov, Job->CFPath, false);
+ RemoveFile(Job->CFPath);
for (auto &Path : FilesToAdd) {
- auto U = FileToVector(Path);
- auto NewPath = DirPlusFile(MainCorpusDir, Hash(U));
- WriteToFile(U, NewPath);
- Files.push_back(NewPath);
+ // Only merge files that have not been merged already.
+ if (std::find(Job->CopiedSeeds.begin(), Job->CopiedSeeds.end(), Path) == Job->CopiedSeeds.end()) {
+ // NOT THREAD SAFE: Fast check whether file still exists.
+ struct stat buffer;
+ if (stat (Path.c_str(), &buffer) == 0) {
+ auto U = FileToVector(Path);
+ auto NewPath = DirPlusFile(MainCorpusDir, Hash(U));
+ WriteToFile(U, NewPath);
+ Files.push_back(NewPath);
+ Job->CopiedSeeds.push_back(Path);
+ }
+ }
}
Features.insert(NewFeatures.begin(), NewFeatures.end());
Cov.insert(NewCov.begin(), NewCov.end());
@@ -271,10 +282,19 @@ struct JobQueue {
}
};

-void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) {
+void WorkerThread(GlobalEnv *Env, JobQueue *FuzzQ, JobQueue *MergeQ) {
while (auto Job = FuzzQ->Pop()) {
- // Printf("WorkerThread: job %p\n", Job);
+ Job->Executing = true;
+ int Sleep_ms = 5 * 60 * 1000;
+ std::thread([=]() {
+ std::this_thread::sleep_for(std::chrono::milliseconds(Sleep_ms / 5));
+ while (Job->Executing) {
+ Env->RunOneMergeJob(Job);
+ std::this_thread::sleep_for(std::chrono::milliseconds(Sleep_ms));
+ }
+ }).detach();
Job->ExitCode = ExecuteCommand(Job->Cmd);
+ Job->Executing = false;
MergeQ->Push(Job);
}
}
@@ -335,7 +355,7 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
size_t JobId = 1;
Vector<std::thread> Threads;
for (int t = 0; t < NumJobs; t++) {
- Threads.push_back(std::thread(WorkerThread, &FuzzQ, &MergeQ));
+ Threads.push_back(std::thread(WorkerThread, &Env, &FuzzQ, &MergeQ));
FuzzQ.Push(Env.CreateNewJob(JobId++));
}

15 changes: 15 additions & 0 deletions fuzzers/libfuzzer_test/runner.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 Google LLC
#
# 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.

FROM gcr.io/fuzzbench/base-image

0 comments on commit 5a1a3e3

Please sign in to comment.