Integrate capstone with oss-fuzz (#1150)
Compile the fuzz target with the rest of the tests
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be5060f..37b19d6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -360,6 +360,9 @@
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 0000000..496bf59
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <capstone.h>
+
+
+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 0000000..9fda93f
--- /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 0000000..3146cc0
--- /dev/null
+++ b/suite/fuzz/onefile.c
@@ -0,0 +1,49 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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;
+}
+