diff --git a/.gitignore b/.gitignore index 9594ae1719..3c5a9684eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ target Cargo.lock +*.o +*.a +*.so + .vscode diff --git a/fuzzers/libfuzzer/libfuzzer/Cargo.toml b/fuzzers/libfuzzer/Cargo.toml similarity index 77% rename from fuzzers/libfuzzer/libfuzzer/Cargo.toml rename to fuzzers/libfuzzer/Cargo.toml index 8a002251e0..33df7d86da 100644 --- a/fuzzers/libfuzzer/libfuzzer/Cargo.toml +++ b/fuzzers/libfuzzer/Cargo.toml @@ -7,4 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -afl = { path = "../../../" } +afl = { path = "../../" } + +[lib] +crate-type = ["staticlib", "cdylib"] diff --git a/fuzzers/libfuzzer/compiler b/fuzzers/libfuzzer/compiler new file mode 100755 index 0000000000..13ff4dc299 --- /dev/null +++ b/fuzzers/libfuzzer/compiler @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import subprocess +import sys +import os + +script_dir = os.path.dirname(os.path.realpath(os.path.abspath(__file__))) + +is_cxx = "++" in sys.argv[0] + +def cc_exec(args): + if os.getenv("AFL_CC"): + cc_name = os.environ["AFL_CC"] + else: + cc_name = "clang" + if is_cxx: + if os.getenv("AFL_CXX"): + cc_name = os.environ["AFL_CXX"] + else: + cc_name = "clang++" + argv = [cc_name] + args + #print(" ".join(argv)) + return subprocess.run(argv) + + +def common_opts(): + return [ + "-g", + ] + +def cc_mode(): + args = common_opts() + args += sys.argv[1:] + + if os.getenv("AFL_USE_ASAN"): + args += ["-fsanitize=address"] + if os.getenv("AFL_USE_MSAN"): + args += ["-fsanitize=memory"] + if os.getenv("AFL_USE_UBSAN"): + args += [ + "-fsanitize=undefined", + "-fsanitize-undefined-trap-on-error", + "-fno-sanitize-recover=all", + ] + + return cc_exec(args) + +def ld_mode(): + args = common_opts() + + args += sys.argv[1:] + args += [ + os.path.join(script_dir, "runtime", "rt.o"), + os.path.join(script_dir, "target", "release", "liblibfuzzer.a"), + ] + + if os.getenv("AFL_USE_ASAN"): + args += ["-fsanitize=address"] + if os.getenv("AFL_USE_MSAN"): + args += ["-fsanitize=memory"] + if os.getenv("AFL_USE_UBSAN"): + args += [ + "-fsanitize=undefined", + "-fsanitize-undefined-trap-on-error", + "-fno-sanitize-recover=all", + ] + + args += ["-pthread", "-ldl"] # for Rust + + return cc_exec(args) + +def is_ld_mode(): + return not ("--version" in sys.argv or "--target-help" in sys.argv or + "-c" in sys.argv or "-E" in sys.argv or "-S" in sys.argv or + "-shared" in sys.argv) + +#print("\x1b[0;36m" + os.path.basename(sys.argv[0]) + " 1.0a\x1b[0m by ") + +if len(sys.argv) <= 1: + cc_exec(sys.argv[1:]) +elif is_ld_mode(): + ld_mode() +else: + cc_mode() diff --git a/fuzzers/libfuzzer/runtime/Makefile b/fuzzers/libfuzzer/runtime/Makefile new file mode 100644 index 0000000000..87e5cb0759 --- /dev/null +++ b/fuzzers/libfuzzer/runtime/Makefile @@ -0,0 +1,10 @@ +CC ?= clang + +all: rt.o + +rt.o: rt.c + $(CC) -c rt.c + +clean: + rm -f rt.o + diff --git a/fuzzers/libfuzzer/runtime/rt.c b/fuzzers/libfuzzer/runtime/rt.c new file mode 100644 index 0000000000..32e5aa4890 --- /dev/null +++ b/fuzzers/libfuzzer/runtime/rt.c @@ -0,0 +1,15 @@ + + +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); + +void afl_libfuzzer_main(); + +int main(int argc, char** argv) { + + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + + afl_libfuzzer_main(); + return 0; + +} diff --git a/fuzzers/libfuzzer/libfuzzer/src/main.rs b/fuzzers/libfuzzer/src/lib.rs similarity index 70% rename from fuzzers/libfuzzer/libfuzzer/src/main.rs rename to fuzzers/libfuzzer/src/lib.rs index 5351933387..a6cf977b3c 100644 --- a/fuzzers/libfuzzer/libfuzzer/src/main.rs +++ b/fuzzers/libfuzzer/src/lib.rs @@ -5,17 +5,24 @@ use afl::engines::{DefaultEngine, DefaultState, Engine}; use afl::executors::inmemory::InMemoryExecutor; use afl::executors::{Executor, ExitKind}; use afl::inputs::bytes::BytesInput; -use afl::mutators::scheduled::{ - mutation_bitflip, ComposedByMutations, DefaultScheduledMutator, -}; +use afl::mutators::scheduled::{mutation_bitflip, ComposedByMutations, DefaultScheduledMutator}; use afl::stages::mutational::DefaultMutationalStage; use afl::utils::DefaultRand; -fn harness(_executor: &dyn Executor, _buf: &[u8]) -> ExitKind { +extern "C" { + /// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) + fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; +} + +fn harness(_executor: &dyn Executor, buf: &[u8]) -> ExitKind { + unsafe { + LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()); + } ExitKind::Ok } -pub fn main() { +#[no_mangle] +pub extern "C" fn afl_libfuzzer_main() { let rand = DefaultRand::new(0).into(); let mut corpus = InMemoryCorpus::::new(&rand); @@ -40,4 +47,3 @@ pub fn main() { } println!("OK"); } - diff --git a/fuzzers/libfuzzer/test/test.c b/fuzzers/libfuzzer/test/test.c new file mode 100755 index 0000000000..9f4f842383 --- /dev/null +++ b/fuzzers/libfuzzer/test/test.c @@ -0,0 +1,45 @@ +#include +#include + +// gcc -shared -o libdemo.so demo-so.c -w +int target_func(char *buf, int size) { + + printf("buffer:%p, size:%p\n", buf, size); + switch (buf[0]) { + + case 1: + puts("222"); + if (buf[1] == '\x44') { + + puts("null ptr deference"); + *(char *)(0) = 1; + + } + + break; + case 0xff: + if (buf[2] == '\xff') { + + if (buf[1] == '\x44') { + + puts("crash...."); + *(char *)(0xdeadbeef) = 1; + + } + + } + + break; + default: + puts("default action"); + break; + + } + + return 1; + +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return target_func(Data, Size); +}