diff options
| author | Ben Harris <bjh21@bjh21.me.uk> | 2023-02-20 21:51:18 +0000 |
|---|---|---|
| committer | Ben Harris <bjh21@bjh21.me.uk> | 2023-02-23 11:34:20 +0000 |
| commit | 5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4 (patch) | |
| tree | 6bef4680923990c03ad4bcaa55849d8fad999884 | |
| parent | ecd868ac6e7ab3df4984ff29a16c7158339611a3 (diff) | |
| download | puzzles-5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4.zip puzzles-5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4.tar.gz puzzles-5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4.tar.bz2 puzzles-5ba227031c865aff55fdaf7c9a1b0e8abcbbabc4.tar.xz | |
Rough support for fuzzing with libFuzzer
For AFL++ and Honggfuzz, our approach is to build a standard fuzzpuzz
binary with extra hooks for interacting with an external fuzzer. This
works well for AFL++ and tolerably for Honggfuzz. LibFuzzer, though,
provides its own main() so that the resulting program has a very
different command-line interface from the normal one. Also, since
libFuzzer is a standard part of Clang, we can't decide whether to use it
based on the behaviour of the compiler.
So what I've done, at least for now, is to have CMake detect when we're
using Clang and in that case build a separate binary called
"fuzzpuzz-libfuzzer" which is built with -fsanitize=fuzzer, while the
ordinary fuzzpuzz is built without. I'm not sure if this is the right
approach, though.
| -rw-r--r-- | CMakeLists.txt | 10 | ||||
| -rw-r--r-- | fuzzpuzz.c | 43 |
2 files changed, 53 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0937d25..ceb4756 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,6 +282,16 @@ if(build_cli_programs) cliprogram(fuzzpuzz fuzzpuzz.c list.c ${puzzle_sources} COMPILE_DEFINITIONS COMBINED $<$<BOOL:${HAVE_HF_ITER}>:HAVE_HF_ITER>) target_include_directories(fuzzpuzz PRIVATE ${generated_include_dir}) + + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + cliprogram(fuzzpuzz-libfuzzer fuzzpuzz.c list.c ${puzzle_sources} + COMPILE_DEFINITIONS COMBINED OMIT_MAIN) + target_include_directories(fuzzpuzz-libfuzzer + PRIVATE ${generated_include_dir}) + target_compile_options(fuzzpuzz-libfuzzer PRIVATE -fsanitize=fuzzer) + set_target_properties(fuzzpuzz-libfuzzer + PROPERTIES LINK_FLAGS -fsanitize=fuzzer) + endif() endif() build_extras() @@ -43,6 +43,10 @@ __AFL_FUZZ_INIT(); extern int HF_ITER(unsigned char **, size_t *); #endif +/* This function is expected by libFuzzer. */ + +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size); + static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx, void (*rewindfn)(void *), void (*writefn)(void *, const void *, int), @@ -104,6 +108,44 @@ static void savefile_write(void *wctx, const void *buf, int len) fwrite(buf, 1, len, fp); } +struct memread { + const unsigned char *buf; + size_t pos; + size_t len; +}; + +static bool mem_read(void *wctx, void *buf, int len) +{ + struct memread *ctx = wctx; + + if (ctx->pos + len > ctx->len) return false; + memcpy(buf, ctx->buf + ctx->pos, len); + ctx->pos += len; + return true; +} + +static void mem_rewind(void *wctx) +{ + struct memread *ctx = wctx; + + ctx->pos = 0; +} + +static void null_write(void *wctx, const void *buf, int len) +{ +} + +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) { + struct memread ctx; + + ctx.buf = data; + ctx.len = size; + ctx.pos = 0; + fuzz_one(mem_read, &ctx, mem_rewind, null_write, NULL); + return 0; +} + +#ifndef OMIT_MAIN int main(int argc, char **argv) { const char *err; @@ -165,3 +207,4 @@ int main(int argc, char **argv) } return ret; } +#endif |