From 170904d5f1704efd89f3bc27072576971be2ab5b Mon Sep 17 00:00:00 2001 From: Catena cyber <35799796+catenacyber@users.noreply.github.com> Date: Fri, 1 Jun 2018 14:46:20 +0200 Subject: [PATCH] Integrate capstone with oss-fuzz (#1150) Compile the fuzz target with the rest of the tests --- CMakeLists.txt | 3 + suite/fuzz/fuzz_disasm.c | 184 +++++++++++++++++++++++++++++++++ suite/fuzz/fuzz_disasm.options | 2 + suite/fuzz/onefile.c | 49 +++++++++ 4 files changed, 238 insertions(+) create mode 100644 suite/fuzz/fuzz_disasm.c create mode 100644 suite/fuzz/fuzz_disasm.options create mode 100644 suite/fuzz/onefile.c diff --git a/CMakeLists.txt b/CMakeLists.txt index be5060f0..37b19d6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,6 +360,9 @@ if (CAPSTONE_BUILD_TESTS) add_executable(${ARM_REGRESS_BIN} "suite/arm/${ARM_REGRESS_TEST}") target_link_libraries(${ARM_REGRESS_BIN} ${default-target}) endif() + # fuzz target built with the tests + add_executable(fuzz_disasm suite/fuzz/onefile.c suite/fuzz/fuzz_disasm.c) + target_link_libraries(fuzz_disasm ${default-target}) endif () source_group("Source\\Engine" FILES ${SOURCES_ENGINE}) diff --git a/suite/fuzz/fuzz_disasm.c b/suite/fuzz/fuzz_disasm.c new file mode 100644 index 00000000..496bf596 --- /dev/null +++ b/suite/fuzz/fuzz_disasm.c @@ -0,0 +1,184 @@ +// the following must precede stdio (woo, thanks msft) +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include + +#include + + +struct platform { + cs_arch arch; + cs_mode mode; + char *comment; +}; + +FILE * outfile = NULL; + +struct platform platforms[] = { + { + CS_ARCH_X86, + CS_MODE_32, + "X86 32 (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_64, + "X86 64 (Intel syntax)" + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + "ARM" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + "THUMB-2" + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + "ARM: Cortex-A15 + NEON" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + "THUMB" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + "Thumb-MClass" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + "Arm-V8" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + "MIPS-32 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), + "MIPS-64-EL (Little-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 | Micro (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 (Big-endian)" + }, + { + CS_ARCH_ARM64, + CS_MODE_ARM, + "ARM-64" + }, + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + "PPC-64" + }, + { + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + "Sparc" + }, + { + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + "SparcV9" + }, + { + CS_ARCH_SYSZ, + (cs_mode)0, + "SystemZ" + }, + { + CS_ARCH_XCORE, + (cs_mode)0, + "XCore" + }, +}; + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + csh handle; + cs_insn *all_insn; + cs_detail *detail; + cs_err err; + + if (Size < 1) { + // 1 byte for arch choice + return 0; + } + if (outfile == NULL) { + // we compute the output + outfile = fopen("/dev/null", "w"); + if (outfile == NULL) { + return 0; + } + } + + int platforms_len = sizeof(platforms)/sizeof(platforms[0]); + int i = (int)Data[0] % platforms_len; + + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + return 0; + } + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + uint64_t address = 0x1000; + size_t count = cs_disasm(handle, Data+1, Size-1, address, 0, &all_insn); + + if (count) { + size_t j; + int n; + + for (j = 0; j < count; j++) { + cs_insn *i = &(all_insn[j]); + fprintf(outfile, "0x%"PRIx64":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", + i->address, i->mnemonic, i->op_str, + i->id, cs_insn_name(handle, i->id)); + + detail = i->detail; + + if (detail->regs_read_count > 0) { + fprintf(outfile, "\tImplicit registers read: "); + for (n = 0; n < detail->regs_read_count; n++) { + fprintf(outfile, "%s ", cs_reg_name(handle, detail->regs_read[n])); + } + } + + if (detail->regs_write_count > 0) { + fprintf(outfile, "\tImplicit registers modified: "); + for (n = 0; n < detail->regs_write_count; n++) { + fprintf(outfile, "%s ", cs_reg_name(handle, detail->regs_write[n])); + } + } + + if (detail->groups_count > 0) { + fprintf(outfile, "\tThis instruction belongs to groups: "); + for (n = 0; n < detail->groups_count; n++) { + fprintf(outfile, "%s ", cs_group_name(handle, detail->groups[n])); + } + } + } + fprintf(outfile, "0x%"PRIx64":\n", all_insn[j-1].address + all_insn[j-1].size); + cs_free(all_insn, count); + } + + cs_close(&handle); + + return 0; +} diff --git a/suite/fuzz/fuzz_disasm.options b/suite/fuzz/fuzz_disasm.options new file mode 100644 index 00000000..9fda93fc --- /dev/null +++ b/suite/fuzz/fuzz_disasm.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 4096 diff --git a/suite/fuzz/onefile.c b/suite/fuzz/onefile.c new file mode 100644 index 00000000..3146cc07 --- /dev/null +++ b/suite/fuzz/onefile.c @@ -0,0 +1,49 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t *Data; + size_t Size; + + if (argc != 2) { + return 1; + } + //opens the file, get its size, and reads it into a buffer + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + return 2; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + return 2; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + return 2; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + return 2; + } + Data = malloc(Size); + if (Data == NULL) { + fclose(fp); + return 2; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + return 2; + } + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + fclose(fp); + return 0; +} +