diff options
Diffstat (limited to 'capstone/suite/fuzz')
-rw-r--r-- | capstone/suite/fuzz/Makefile | 112 | ||||
-rw-r--r-- | capstone/suite/fuzz/README | 2 | ||||
-rw-r--r-- | capstone/suite/fuzz/README.md | 34 | ||||
-rw-r--r-- | capstone/suite/fuzz/driverbin.c | 88 | ||||
-rw-r--r-- | capstone/suite/fuzz/drivermc.c | 138 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_decode_platform.c | 27 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_diff.c | 237 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_disasm.c | 99 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_disasm.options | 2 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_harness.c | 222 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzz_llvm.cpp | 41 | ||||
-rwxr-xr-x | capstone/suite/fuzz/fuzzit.sh | 27 | ||||
-rw-r--r-- | capstone/suite/fuzz/fuzzitid.txt | 3 | ||||
-rw-r--r-- | capstone/suite/fuzz/onefile.c | 51 | ||||
-rw-r--r-- | capstone/suite/fuzz/platform.c | 365 | ||||
-rw-r--r-- | capstone/suite/fuzz/platform.h | 24 |
16 files changed, 1472 insertions, 0 deletions
diff --git a/capstone/suite/fuzz/Makefile b/capstone/suite/fuzz/Makefile new file mode 100644 index 000000000..e0c0ef2b8 --- /dev/null +++ b/capstone/suite/fuzz/Makefile @@ -0,0 +1,112 @@ +# Capstone Disassembler Engine +# By Philippe Antoine <contact@catenacyber.fr>, 2018 + +include ../../config.mk +include ../../functions.mk + +ifneq ($(CAPSTONE_STATIC),yes) +$(error Needs static capstone.) +endif + +# Verbose output? +V ?= 0 + +INCDIR = ../../include +ifndef BUILDDIR +TESTDIR = . +OBJDIR = . +LIBDIR = ../.. +else +TESTDIR = $(BUILDDIR)/tests +OBJDIR = $(BUILDDIR)/obj/tests +LIBDIR = $(BUILDDIR) +endif + +CFLAGS += -Wall -I$(INCDIR) +LDFLAGS += -L$(LIBDIR) + +CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) +LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) +FUZZLDFLAGS = + +LIBNAME = capstone + +BIN_EXT = +AR_EXT = a + + +ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) + +.PHONY: all clean + +SOURCES = fuzz_disasm.c drivermc.c fuzz_harness.c driverbin.c platform.c +OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) +# reproducer using MC file as input +REPRODUCERMC = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT)) +# reproducer using raw binary file as input (as produced by fuzzer) +REPRODUCERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT)) +# fuzzer +FUZZERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm2$(BIN_EXT)) +PLATFORMDECODE = $(addprefix $(TESTDIR)/,fuzz_decode_platform$(BIN_EXT)) + +all: $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(PLATFORMDECODE) + +clean: + rm -rf fuzz_harness $(OBJS) $(PLATFORMDECODE) $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).* + rm -f *.d $(OBJDIR)/*.d + +$(REPRODUCERMC): fuzz_disasm.o drivermc.o platform.o + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,LINK,$(notdir $@)) + @$(link-static) +else + $(link-static) +endif + +$(REPRODUCERBIN): fuzz_disasm.o driverbin.o platform.o + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,LINK,$(notdir $@)) + @$(link-static) +else + $(link-static) +endif + +$(FUZZERBIN): FUZZLDFLAGS="-fsanitize=fuzzer" + +$(FUZZERBIN): fuzz_disasm.o platform.o + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,LINK,$(notdir $@)) + @$(link-static) || touch $(FUZZERBIN) +else + $(link-static) || touch $(FUZZERBIN) +endif + +$(PLATFORMDECODE): fuzz_decode_platform.o platform.o + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,LINK,$(notdir $@)) + @$(link-static) +else + $(link-static) +endif + +$(OBJDIR)/%.o: %.c + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,CC,$(@:$(OBJDIR)/%=%)) + @$(compile) +else + $(compile) +endif + + + +define link-static + $(CC) $(LDFLAGS) $(FUZZLDFLAGS) $^ $(ARCHIVE) -o $@ +endef + +fuzz_harness: fuzz_harness.o + ${CC} $< -O3 -Wall -l$(LIBNAME) -o $@ diff --git a/capstone/suite/fuzz/README b/capstone/suite/fuzz/README new file mode 100644 index 000000000..0e637936d --- /dev/null +++ b/capstone/suite/fuzz/README @@ -0,0 +1,2 @@ +This directory contains a fuzz testing harness for Capstone. +Run "make" to compile this code. diff --git a/capstone/suite/fuzz/README.md b/capstone/suite/fuzz/README.md new file mode 100644 index 000000000..27c1c0c36 --- /dev/null +++ b/capstone/suite/fuzz/README.md @@ -0,0 +1,34 @@ +Fuzzing +=============== + + +Build the fuzz target +------- + +To build the fuzz target, you can simply run `make` with appropriate flags set : +``` +ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=address" make +``` +You can replace `address` with another sanitizer : `memory` or `undefined` +The fuzz target is then `suite/fuzz/fuzz_bindisasm2` + +You can find this in travis configuration `.travis.yml` + +Another way is to use oss-fuzz, see https://github.com/google/oss-fuzz/blob/master/projects/capstone/build.sh + +Fuzz drivers +------ + +There are custom drivers : +- driverbin.c : prints cstool command before running one input +- drivermc.c : converts MC test data to raw binary data before running as many inputs as there are lines in a file +- onefile.c : simple one file driver + +For libfuzzer, the preferred main function is now to use linker option `-fsanitize=fuzzer` + +Fuzzit integration +------ + +Travis will build the fuzz target with the different sanitizers. +Then, Travis will launch sanity fuzzit jobs as part of continuous integration (for each of the sanitizers) +The fuzzit target ids are stored in a configuration file fuzzitid.txt and used by fuzzit.sh diff --git a/capstone/suite/fuzz/driverbin.c b/capstone/suite/fuzz/driverbin.c new file mode 100644 index 000000000..d5e3a0fcc --- /dev/null +++ b/capstone/suite/fuzz/driverbin.c @@ -0,0 +1,88 @@ +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <dirent.h> +#include <unistd.h> + +#include "platform.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t Data[0x1000]; + size_t Size; + DIR *d; + struct dirent *dir; + int r = 0; + int i; + + if (argc != 2) { + return 1; + } + + d = opendir(argv[1]); + if (d == NULL) { + printf("Invalid directory\n"); + return 2; + } + if (chdir(argv[1]) != 0) { + closedir(d); + printf("Invalid directory\n"); + return 2; + } + + while((dir = readdir(d)) != NULL) { + //opens the file, get its size, and reads it into a buffer + if (dir->d_type != DT_REG) { + continue; + } + printf("Running file %s ", dir->d_name); + fflush(stdout); + fp = fopen(dir->d_name, "rb"); + if (fp == NULL) { + r = 3; + break; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + r = 4; + break; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + r = 5; + break; + } else if (Size > 0x1000) { + fclose(fp); + continue; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + r = 7; + break; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + r = 8; + break; + } + if (Size > 0) { + printf("command cstool %s\n", get_platform_cstoolname(Data[0])); + } + for (i=0; i<Size; i++) { + printf("%02x", Data[i]); + } + printf("\n"); + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + fclose(fp); + } + closedir(d); + printf("Ok : whole directory finished\n"); + return r; +} + diff --git a/capstone/suite/fuzz/drivermc.c b/capstone/suite/fuzz/drivermc.c new file mode 100644 index 000000000..ff31ebdee --- /dev/null +++ b/capstone/suite/fuzz/drivermc.c @@ -0,0 +1,138 @@ +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +#define MAX_INSTR_SIZE 64 +#define MAX_LINE_SIZE 128 + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t Data[MAX_INSTR_SIZE]; + char line[MAX_LINE_SIZE]; + size_t Size; + char arch[MAX_LINE_SIZE]; + char mode[MAX_LINE_SIZE]; + unsigned int value; + int i; + + if (argc < 2) { + return 1; + } + for (i = 1; i < argc; i++) { + //opens the file, get its size, and reads it into a buffer + fp = fopen(argv[i], "rb"); + if (fp == NULL) { + return 2; + } + printf("Trying %s\n", argv[i]); + if (fgets(line, MAX_LINE_SIZE, fp) == NULL) { + break; + } + if (line[0] == '#') { + if (sscanf(line, "# %[^,], %[^,]", arch, mode) != 2) { + printf("Wrong mode %s\n", line); + return 1; + } + if (strcmp(arch, "CS_ARCH_X86") == 0 && strcmp(mode, "CS_MODE_32") == 0) { + Data[0] = 0; + } else if (strcmp(arch, "CS_ARCH_X86") == 0 && strcmp(mode, "CS_MODE_64") == 0) { + Data[0] = 1; + } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_ARM") == 0) { + Data[0] = 2; + } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB") == 0) { + Data[0] = 3; + } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_ARM+CS_MODE_V8") == 0) { + Data[0] = 4; + } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB+CS_MODE_V8") == 0) { + Data[0] = 5; + } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB+CS_MODE_MCLASS") == 0) { + Data[0] = 6; + } else if (strcmp(arch, "CS_ARCH_ARM64") == 0 && strcmp(mode, "0") == 0) { + Data[0] = 7; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 8; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_MICRO") == 0) { + Data[0] = 9; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS64") == 0) { + Data[0] = 10; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32") == 0) { + Data[0] = 11; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS64+CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 12; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_MICRO+CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 13; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_BIG_ENDIAN+CS_MODE_MICRO") == 0) { + Data[0] = 13; + } else if (strcmp(arch, "CS_ARCH_PPC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 14; + } else if (strcmp(arch, "CS_ARCH_SPARC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 15; + } else if (strcmp(arch, "CS_ARCH_SPARC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN + CS_MODE_V9") == 0) { + Data[0] = 16; + } else if (strcmp(arch, "CS_ARCH_SYSZ") == 0 && strcmp(mode, "0") == 0) { + Data[0] = 17; + } else if (strcmp(arch, "CS_ARCH_XCORE") == 0 && strcmp(mode, "0") == 0) { + Data[0] = 18; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 19; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_MICRO+CS_MODE_BIG_ENDIAN") == 0) { + Data[0] = 20; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6") == 0) { + Data[0] = 21; + } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_MICRO") == 0) { + Data[0] = 22; + } else if (strcmp(arch, "CS_ARCH_M68K") == 0 && strcmp(mode, "0") == 0) { + Data[0] = 23; + } else if (strcmp(arch, "CS_ARCH_M680X") == 0 && strcmp(mode, "CS_MODE_M680X_6809") == 0) { + Data[0] = 24; + } else if (strcmp(arch, "CS_ARCH_EVM") == 0 && strcmp(mode, "0") == 0) { + Data[0] = 25; + } else if (strcmp(arch, "CS_ARCH_BPF") == 0 && strstr(mode, "CS_MODE_BPF_CLASSIC") != NULL) { + Data[0] = 29; + } else if (strcmp(arch, "CS_ARCH_BPF") == 0 && strstr(mode, "CS_MODE_BPF_EXTENDED") != NULL) { + Data[0] = 30; + } else if (strcmp(arch, "CS_ARCH_RISCV") == 0 && strcmp(mode, "CS_MODE_RISCV32") == 0) { + Data[0] = 44; + } else if (strcmp(arch, "CS_ARCH_RISCV") == 0 && strcmp(mode, "CS_MODE_RISCV64") == 0) { + Data[0] = 45; + } else { + printf("Unknown mode\n"); + //fail instead of continue + return 1; + } + } else { + printf("No mode\n"); + //fail instead of continue + return 1; + } + + while(1) { + if (fgets(line, MAX_LINE_SIZE, fp) == NULL) { + break; + } + Size = 1; + // we start line at offset 0 and Data buffer at offset 1 + // since Data[0] is option : arch + mode + while (sscanf(line+(Size-1)*5, "0x%02x", &value) == 1) { + Data[Size] = value; + Size++; + if (line[(Size-1)*5-1] != ',') { + //end of pattern + break; + } else if (MAX_LINE_SIZE < (Size-1)*5) { + printf("Line overflow\n"); + return 1; + } + } + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + } + fclose(fp); + } + return 0; +} + diff --git a/capstone/suite/fuzz/fuzz_decode_platform.c b/capstone/suite/fuzz/fuzz_decode_platform.c new file mode 100644 index 000000000..d79c4ea34 --- /dev/null +++ b/capstone/suite/fuzz/fuzz_decode_platform.c @@ -0,0 +1,27 @@ +// this tool decodes first input byte feed to OSS fuzz, that encodes arch+mode +// by Nguyen Anh Quynh, 2019 + +#include <stdio.h> +#include <inttypes.h> + +#include <capstone/capstone.h> + +#include "platform.h" + +int main(int argc, char **argv) +{ + unsigned char data; + + if (argc != 2) { + printf("Decoding OSS fuzz platform\n"); + printf("Syntax: %s <hex-byte>\n", argv[0]); + return -1; + } + + data = (unsigned int)strtol(argv[1], NULL, 16); + + printf("cstool arch+mode = %s\n", get_platform_cstoolname(data)); + + return 0; +} + diff --git a/capstone/suite/fuzz/fuzz_diff.c b/capstone/suite/fuzz/fuzz_diff.c new file mode 100644 index 000000000..f0f39fdc6 --- /dev/null +++ b/capstone/suite/fuzz/fuzz_diff.c @@ -0,0 +1,237 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <assert.h> + +#include <capstone/capstone.h> + + +struct platform { + cs_arch arch; + cs_mode mode; + char *comment; +}; + +FILE * outfile = NULL; + +struct platform platforms[] = { + { + // item 0 + CS_ARCH_X86, + CS_MODE_32, + "X86 32 (Intel syntax)" + }, + { + // item 1 + CS_ARCH_X86, + CS_MODE_64, + "X86 64 (Intel syntax)" + }, + { + // item 2 + CS_ARCH_ARM, + CS_MODE_ARM, + "ARM" + }, + { + // item 3 + CS_ARCH_ARM, + CS_MODE_THUMB, + "THUMB" + }, + { + // item 4 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + "Arm-V8" + }, + { + // item 5 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB+CS_MODE_V8), + "THUMB+V8" + }, + { + // item 6 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + "Thumb-MClass" + }, + { + // item 7 + CS_ARCH_ARM64, + (cs_mode)0, + "ARM-64" + }, + { + // item 8 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + "MIPS-32 (Big-endian)" + }, + { + // item 9 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO), + "MIPS-32 (micro)" + }, + { + //item 10 + CS_ARCH_MIPS, + CS_MODE_MIPS64, + "MIPS-64-EL (Little-endian)" + }, + { + //item 11 + CS_ARCH_MIPS, + CS_MODE_MIPS32, + "MIPS-32-EL (Little-endian)" + }, + { + //item 12 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN), + "MIPS-64 (Big-endian)" + }, + { + //item 13 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + "MIPS-32 | Micro (Big-endian)" + }, + { + //item 14 + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + "PPC-64" + }, + { + //item 15 + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + "Sparc" + }, + { + //item 16 + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + "SparcV9" + }, + { + //item 17 + CS_ARCH_SYSZ, + (cs_mode)0, + "SystemZ" + }, + { + //item 18 + CS_ARCH_XCORE, + (cs_mode)0, + "XCore" + }, + { + //item 19 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 (Big-endian)" + }, + { + //item 20 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 (Micro+Big-endian)" + }, + { + //item 21 + CS_ARCH_MIPS, + CS_MODE_MIPS32R6, + "MIPS-32R6 (Little-endian)" + }, + { + //item 22 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO), + "MIPS-32R6 (Micro+Little-endian)" + }, + { + //item 23 + CS_ARCH_M68K, + (cs_mode)0, + "M68K" + }, + { + //item 24 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6809, + "M680X_M6809" + }, + { + //item 25 + CS_ARCH_EVM, + (cs_mode)0, + "EVM" + }, +}; + +void LLVMFuzzerInit(); +int LLVMFuzzerReturnOneInput(const uint8_t *Data, size_t Size, char * AssemblyText); + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + csh handle; + cs_insn *insn; + cs_err err; + const uint8_t **Datap = &Data; + size_t * Sizep = &Size; + uint64_t address = 0x1000; + char LLVMAssemblyText[80]; + char CapstoneAssemblyText[80]; + + if (Size < 1) { + // 1 byte for arch choice + return 0; + } else if (Size > 0x1000) { + //limit input to 4kb + Size = 0x1000; + } + if (outfile == NULL) { + // we compute the output + outfile = fopen("/dev/null", "w"); + if (outfile == NULL) { + return 0; + } + LLVMFuzzerInit(); + } + + if (Data[0] >= sizeof(platforms)/sizeof(platforms[0])) { + return 0; + } + + if (LLVMFuzzerReturnOneInput(Data, Size, LLVMAssemblyText) == 1) { + return 0; + } + + err = cs_open(platforms[Data[0]].arch, platforms[Data[0]].mode, &handle); + if (err) { + return 0; + } + + insn = cs_malloc(handle); + Data++; + Size--; + assert(insn); + if (cs_disasm_iter(handle, Datap, Sizep, &address, insn)) { + snprintf(CapstoneAssemblyText, 80, "\t%s\t%s", insn->mnemonic, insn->op_str); + if (strcmp(CapstoneAssemblyText, LLVMAssemblyText) != 0) { + printf("capstone %s != llvm %s", CapstoneAssemblyText, LLVMAssemblyText); + abort(); + } + } else { + printf("capstone failed with llvm %s", LLVMAssemblyText); + abort(); + } + cs_free(insn, 1); + cs_close(&handle); + + return 0; +} diff --git a/capstone/suite/fuzz/fuzz_disasm.c b/capstone/suite/fuzz/fuzz_disasm.c new file mode 100644 index 000000000..0dd7ef72d --- /dev/null +++ b/capstone/suite/fuzz/fuzz_disasm.c @@ -0,0 +1,99 @@ +// 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/capstone.h> + +#include "platform.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + + +static FILE *outfile = NULL; + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + csh handle; + cs_insn *all_insn; + cs_detail *detail; + cs_err err; + unsigned int i; + + if (Size < 1) { + // 1 byte for arch choice + return 0; + } else if (Size > 0x1000) { + //limit input to 4kb + Size = 0x1000; + } + + if (outfile == NULL) { + // we compute the output + outfile = fopen("/dev/null", "w"); + if (outfile == NULL) { + return 0; + } + } + + i = get_platform_entry((uint8_t)Data[0]); + + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + return 0; + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + if (Data[0]&0x80) { + //hack + cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + } + + uint64_t address = 0x1000; + size_t count = cs_disasm(handle, Data+1, Size-1, address, 0, &all_insn); + + if (count) { + size_t j; + unsigned 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/capstone/suite/fuzz/fuzz_disasm.options b/capstone/suite/fuzz/fuzz_disasm.options new file mode 100644 index 000000000..9fda93fcb --- /dev/null +++ b/capstone/suite/fuzz/fuzz_disasm.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 4096 diff --git a/capstone/suite/fuzz/fuzz_harness.c b/capstone/suite/fuzz/fuzz_harness.c new file mode 100644 index 000000000..b69d3ba47 --- /dev/null +++ b/capstone/suite/fuzz/fuzz_harness.c @@ -0,0 +1,222 @@ +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + char *comment; +}; + +int main(int argc, char **argv) +{ + if (argc != 2) { + printf("Usage: %s <testcase>\n", argv[0]); + return 1; + } + + 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" + }, + { + CS_ARCH_M68K, + (cs_mode)0, + "M68K" + }, + { + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6809, + "M680X_M6809" + }, + }; + + // Read input + long bufsize = 0; + unsigned char *buf = NULL; + FILE *fp = fopen(argv[1], "r"); + + if (fp == NULL) return 1; + + if (fseek(fp, 0L, SEEK_END) == 0) { + bufsize = ftell(fp); + + if (bufsize == -1) return 1; + + buf = malloc(bufsize + 1); + + if (buf == NULL) return 1; + if (fseek(fp, 0L, SEEK_SET) != 0) return 1; + + size_t len = fread(buf, sizeof(char), bufsize, fp); + + if (len == 0) return 2; + } + fclose(fp); + + // Disassemble + csh handle; + cs_insn *all_insn; + cs_detail *detail; + cs_err err; + + if (bufsize < 3) return 0; + + int platforms_len = sizeof(platforms)/sizeof(platforms[0]); + int i = (int)buf[0] % platforms_len; + + unsigned char *buf_ptr = buf + 1; + long buf_ptr_size = bufsize - 1; + + printf("Platform: %s (0x%.2x of 0x%.2x)\n", platforms[i].comment, i, platforms_len); + + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + return 1; + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + uint64_t address = 0x1000; + size_t count = cs_disasm(handle, buf_ptr, buf_ptr_size, address, 0, &all_insn); + + if (count) { + size_t j; + int n; + + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + cs_insn *i = &(all_insn[j]); + printf("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) { + printf("\tImplicit registers read: "); + for (n = 0; n < detail->regs_read_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_read[n])); + } + printf("\n"); + } + + if (detail->regs_write_count > 0) { + printf("\tImplicit registers modified: "); + for (n = 0; n < detail->regs_write_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_write[n])); + } + printf("\n"); + } + + if (detail->groups_count > 0) { + printf("\tThis instruction belongs to groups: "); + for (n = 0; n < detail->groups_count; n++) { + printf("%s ", cs_group_name(handle, detail->groups[n])); + } + printf("\n"); + } + } + printf("0x%"PRIx64":\n", all_insn[j-1].address + all_insn[j-1].size); + cs_free(all_insn, count); + } else { + printf("ERROR: Failed to disasm given code!\n"); + } + + printf("\n"); + + free(buf); + cs_close(&handle); + + return 0; +} diff --git a/capstone/suite/fuzz/fuzz_llvm.cpp b/capstone/suite/fuzz/fuzz_llvm.cpp new file mode 100644 index 000000000..7e713cb1e --- /dev/null +++ b/capstone/suite/fuzz/fuzz_llvm.cpp @@ -0,0 +1,41 @@ +#include "llvm-c/Disassembler.h" +#include "llvm-c/Target.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +extern "C" void LLVMFuzzerInit() { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); +} + + +extern "C" int LLVMFuzzerReturnOneInput(const uint8_t *Data, size_t Size, char * AssemblyText) { + LLVMDisasmContextRef Ctx; + std::vector<uint8_t> DataCopy(Data, Data + Size); + uint8_t *p = DataCopy.data(); + int r = 1; + + switch(Data[0]) { + case 0: + Ctx = LLVMCreateDisasmCPUFeatures("i386", "", "", nullptr, 0, nullptr, nullptr); + if (LLVMSetDisasmOptions(Ctx, LLVMDisassembler_Option_AsmPrinterVariant) == 0) { + abort(); + } + break; + //TODO other cases + default: + return 1; + } + assert(Ctx); + + if (LLVMDisasmInstruction(Ctx, p+1, Size-1, 0, AssemblyText, 80) > 0) { + r = 0; + } + LLVMDisasmDispose(Ctx); + + return r; +} diff --git a/capstone/suite/fuzz/fuzzit.sh b/capstone/suite/fuzz/fuzzit.sh new file mode 100755 index 000000000..b962b773e --- /dev/null +++ b/capstone/suite/fuzz/fuzzit.sh @@ -0,0 +1,27 @@ +FUZZIT_API_KEY=f10b19a56d96b29dfdfe459d41b3d82e475e49c737095c74c99d65a032d5c2ab84d44dad510886bc824f101a860b1754 + +[ -s ./suite/fuzz/fuzz_bindisasm2 ] || exit 0 + +if [ ${TRAVIS_EVENT_TYPE} -eq 'cron' ]; then + FUZZING_TYPE=fuzzing +else + FUZZING_TYPE=sanity +fi +if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then + FUZZIT_BRANCH="${TRAVIS_BRANCH}" +else + FUZZIT_BRANCH="PR-${TRAVIS_PULL_REQUEST}" +fi + +FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVIS_COMMIT}" +if [ -n "$UBSAN_OPTIONS" ]; then + FUZZIT_ARGS+=" --ubsan_options ${UBSAN_OPTIONS}" +fi +wget -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v1.2.5/fuzzit_1.2.5_Linux_x86_64 +chmod +x fuzzit +./fuzzit auth ${FUZZIT_API_KEY} +set -x +grep "$QA_FUZZIT" suite/fuzz/fuzzitid.txt | cut -d" " -f2 | while read i; do + ./fuzzit c job ${FUZZIT_ARGS} ${i} ./suite/fuzz/fuzz_bindisasm2 +done +set +x diff --git a/capstone/suite/fuzz/fuzzitid.txt b/capstone/suite/fuzz/fuzzitid.txt new file mode 100644 index 000000000..57bbe73ca --- /dev/null +++ b/capstone/suite/fuzz/fuzzitid.txt @@ -0,0 +1,3 @@ +asan A1NqPndmOVrguCNj95LZ +msan JchjH3j58fOnB8ZXGyWl +ubsan JqHqVabfDEqitOusrPFx
\ No newline at end of file diff --git a/capstone/suite/fuzz/onefile.c b/capstone/suite/fuzz/onefile.c new file mode 100644 index 000000000..74be3063a --- /dev/null +++ b/capstone/suite/fuzz/onefile.c @@ -0,0 +1,51 @@ +#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); + free(Data); + return 2; + } + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + free(Data); + fclose(fp); + return 0; +} + diff --git a/capstone/suite/fuzz/platform.c b/capstone/suite/fuzz/platform.c new file mode 100644 index 000000000..d70cdfef1 --- /dev/null +++ b/capstone/suite/fuzz/platform.c @@ -0,0 +1,365 @@ +#include "platform.h" + +struct platform platforms[] = { + { + // item 0 + CS_ARCH_X86, + CS_MODE_32, + "X86 32 (Intel syntax)", + "x32" + }, + { + // item 1 + CS_ARCH_X86, + CS_MODE_64, + "X86 64 (Intel syntax)", + "x64" + }, + { + // item 2 + CS_ARCH_ARM, + CS_MODE_ARM, + "ARM", + "arm" + }, + { + // item 3 + CS_ARCH_ARM, + CS_MODE_THUMB, + "THUMB", + "thumb" + }, + { + // item 4 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + "Arm-V8", + "armv8" + }, + { + // item 5 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB+CS_MODE_V8), + "THUMB+V8", + "thumbv8" + }, + { + // item 6 + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + "Thumb-MClass", + "cortexm" + }, + { + // item 7 + CS_ARCH_ARM64, + (cs_mode)0, + "ARM-64", + "arm64" + }, + { + // item 8 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + "MIPS-32 (Big-endian)", + "mipsbe" + }, + { + // item 9 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO), + "MIPS-32 (micro)", + "mipsmicro" + }, + { + //item 10 + CS_ARCH_MIPS, + CS_MODE_MIPS64, + "MIPS-64-EL (Little-endian)", + "mips64" + }, + { + //item 11 + CS_ARCH_MIPS, + CS_MODE_MIPS32, + "MIPS-32-EL (Little-endian)", + "mips" + }, + { + //item 12 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN), + "MIPS-64 (Big-endian)", + "mips64be" + }, + { + //item 13 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + "MIPS-32 | Micro (Big-endian)", + "mipsbemicro" + }, + { + //item 14 + CS_ARCH_PPC, + CS_MODE_64 | CS_MODE_BIG_ENDIAN, + "PPC-64", + "ppc64be" + }, + { + //item 15 + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + "Sparc", + "sparc" + }, + { + //item 16 + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + "SparcV9", + "sparcv9" + }, + { + //item 17 + CS_ARCH_SYSZ, + (cs_mode)0, + "SystemZ", + "systemz" + }, + { + //item 18 + CS_ARCH_XCORE, + (cs_mode)0, + "XCore", + "xcore" + }, + { + //item 19 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 (Big-endian)", + "mipsbe32r6" + }, + { + //item 20 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + "MIPS-32R6 (Micro+Big-endian)", + "mipsbe32r6micro" + }, + { + //item 21 + CS_ARCH_MIPS, + CS_MODE_MIPS32R6, + "MIPS-32R6 (Little-endian)", + "mips32r6" + }, + { + //item 22 + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO), + "MIPS-32R6 (Micro+Little-endian)", + "mips32r6micro" + }, + { + //item 23 + CS_ARCH_M68K, + (cs_mode)0, + "M68K", + "m68k" + }, + { + //item 24 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6809, + "M680X_M6809", + "m6809" + }, + { + //item 25 + CS_ARCH_EVM, + (cs_mode)0, + "EVM", + "evm" + }, + { + //item 26 + CS_ARCH_MOS65XX, + (cs_mode)0, + "MOS65XX", + "mos65xx" + }, + { + //item 27 + CS_ARCH_TMS320C64X, + CS_MODE_BIG_ENDIAN, + "tms320c64x", + "tms320c64x" + }, + { + //item 28 + CS_ARCH_WASM, + (cs_mode)0, + "WASM", + "wasm" + }, + { + //item 29 + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, + "cBPF", + "bpf" + }, + { + //item 30 + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + "eBPF", + "ebpf" + }, + { + //item 31 + CS_ARCH_BPF, + CS_MODE_BIG_ENDIAN | CS_MODE_BPF_CLASSIC, + "cBPF", + "bpfbe" + }, + { + //item 32 + CS_ARCH_BPF, + CS_MODE_BIG_ENDIAN | CS_MODE_BPF_EXTENDED, + "eBPF", + "ebpfbe" + }, + { + // item 33 + CS_ARCH_X86, + CS_MODE_16, + "X86 16 (Intel syntax)", + "x16" + }, + { + // item 34 + CS_ARCH_M68K, + CS_MODE_M68K_040, + "M68K mode 40", + "m68k40" + }, + { + //item 35 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6800, + "M680X_M6800", + "m6800" + }, + { + //item 36 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6801, + "M680X_M6801", + "m6801" + }, + { + //item 37 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6805, + "M680X_M6805", + "m6805" + }, + { + //item 38 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6808, + "M680X_M6808", + "m6808" + }, + { + //item 39 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6811, + "M680X_M6811", + "m6811" + }, + { + //item 40 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_CPU12, + "M680X_cpu12", + "cpu12" + }, + { + //item 41 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6301, + "M680X_M6808", + "hd6301" + }, + { + //item 42 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6309, + "M680X_M6808", + "hd6309" + }, + { + //item 43 + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_HCS08, + "M680X_M6808", + "hcs08" + }, + { + //item 44 + CS_ARCH_RISCV, + CS_MODE_RISCV32, + "RISCV", + "riscv32" + }, + { + //item 45 + CS_ARCH_RISCV, + CS_MODE_RISCV64, + "RISCV", + "riscv64" + }, + { + //item 46 + CS_ARCH_PPC, + CS_MODE_64 | CS_MODE_BIG_ENDIAN | CS_MODE_QPX, + "ppc+qpx", + "ppc64beqpx" + }, + + // dummy entry to mark the end of this array. + // DO NOT DELETE THIS + { + 0, + 0, + NULL, + NULL, + }, +}; + +// get length of platforms[] +unsigned int platform_len(void) +{ + unsigned int c; + + for(c = 0; platforms[c].cstoolname; c++); + + return c; +} + +// get platform entry encoded n (first byte for input data of OSS fuzz) +unsigned int get_platform_entry(uint8_t n) +{ + return n % platform_len(); +} + +// get cstoolname from encoded n (first byte for input data of OSS fuzz) +const char *get_platform_cstoolname(uint8_t n) +{ + return platforms[get_platform_entry(n)].cstoolname; +} + diff --git a/capstone/suite/fuzz/platform.h b/capstone/suite/fuzz/platform.h new file mode 100644 index 000000000..29e03f989 --- /dev/null +++ b/capstone/suite/fuzz/platform.h @@ -0,0 +1,24 @@ +#ifndef CS_FUZZ_PLATFORM_H +#define CS_FUZZ_PLATFORM_H + +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + const char *comment; + const char *cstoolname; +}; + +extern struct platform platforms[]; + +// get length of platforms[] +unsigned int platform_len(void); + +// get platform entry encoded n (first byte for input data of OSS fuzz) +unsigned int get_platform_entry(uint8_t n); + +// get cstoolname from encoded n (first byte for input data of OSS fuzz) +const char *get_platform_cstoolname(uint8_t n); + +#endif |