|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH VERY RFC 3/5] tools/fuzz: introduce x86 instruction emulator target
Instruction emulator fuzzing code is from code previous written by
Andrew and George. Adapted to llvm fuzzer and hook up the build system.
Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxx>
Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Tim Deegan <tim@xxxxxxx>
Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
---
.gitignore | 1 +
tools/fuzz/x86_instruction_emulator/Makefile | 33 ++
.../x86-insn-emulator-fuzzer.c | 335 +++++++++++++++++++++
3 files changed, 369 insertions(+)
create mode 100644 tools/fuzz/x86_instruction_emulator/Makefile
create mode 100644
tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
diff --git a/.gitignore b/.gitignore
index a2f34a1..d507243 100644
--- a/.gitignore
+++ b/.gitignore
@@ -145,6 +145,7 @@ tools/flask/utils/flask-loadpolicy
tools/flask/utils/flask-setenforce
tools/flask/utils/flask-set-bool
tools/flask/utils/flask-label-pci
+tools/fuzz/x86_instruction_emulator/x86_emulate*
tools/helpers/_paths.h
tools/helpers/init-xenstore-domain
tools/helpers/xen-init-dom0
diff --git a/tools/fuzz/x86_instruction_emulator/Makefile
b/tools/fuzz/x86_instruction_emulator/Makefile
new file mode 100644
index 0000000..374c84a
--- /dev/null
+++ b/tools/fuzz/x86_instruction_emulator/Makefile
@@ -0,0 +1,33 @@
+XEN_ROOT=$(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+x86-instruction-emulator-fuzzer-all: x86-insn-emulator.a
x86-insn-emulator-fuzzer.o
+
+x86_emulate/x86_emulate.c x86_emulate/x86_emulate.h:
+ [ -L x86_emulate ] || ln -sf $(XEN_ROOT)/xen/arch/x86/x86_emulate .
+
+x86_emulate.c:
+ [ -L x86_emulate.c ] || ln -sf
$(XEN_ROOT)/tools/tests/x86_emulator/x86_emulate.c
+
+x86_emulate.h:
+ [ -L x86_emulate.h ] || ln -sf
$(XEN_ROOT)/tools/tests/x86_emulator/x86_emulate.h
+
+CFLAGS += $(CFLAGS_xeninclude)
+
+x86_emulate.o: x86_emulate.c x86_emulate.h x86_emulate/x86_emulate.c
x86_emulate/x86_emulate.h
+
+x86-insn-emulator.a: x86_emulate.o
+ $(AR) rc $@ $^
+
+x86-insn-emulator-fuzzer.o: x86-insn-emulator-fuzzer.c
+
+# Common targets
+.PHONY: all
+all: x86-instruction-emulator-fuzzer-all
+
+.PHONY: distclean
+distclean: clean
+
+.PHONY: clean
+clean:
+ rm -f *.a *.o
diff --git a/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
new file mode 100644
index 0000000..01ee7a4
--- /dev/null
+++ b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
@@ -0,0 +1,335 @@
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <xen/xen.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#define __packed __attribute__((packed))
+#define ASSERT assert
+
+#include "x86_emulate/x86_emulate.h"
+
+/* EFLAGS bit definitions. */
+#define EFLG_OF (1<<11)
+#define EFLG_DF (1<<10)
+#define EFLG_SF (1<<7)
+#define EFLG_ZF (1<<6)
+#define EFLG_AF (1<<4)
+#define EFLG_PF (1<<2)
+#define EFLG_CF (1<<0)
+
+static unsigned char data[4096];
+static unsigned int data_index = 0;
+static unsigned int data_max;
+
+int data_read(const char *why, void *dst, unsigned int bytes) {
+
+ if ( data_index + bytes > data_max )
+ return X86EMUL_EXCEPTION;
+
+ memcpy(dst, data+data_index, bytes);
+ data_index += bytes;
+
+ return X86EMUL_OKAY;
+}
+
+static int emul_read(
+ unsigned int seg,
+ unsigned long offset,
+ void *p_data,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return data_read("read", p_data, bytes);
+}
+
+static int emul_fetch(
+ unsigned int seg,
+ unsigned long offset,
+ void *p_data,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return data_read("fetch", p_data, bytes);
+}
+
+static int emul_write(
+ unsigned int seg,
+ unsigned long offset,
+ void *p_data,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return X86EMUL_OKAY;
+}
+
+static int emul_cmpxchg(
+ unsigned int seg,
+ unsigned long offset,
+ void *old,
+ void *new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return X86EMUL_OKAY;
+}
+
+static int emul_cpuid(
+ unsigned int *eax,
+ unsigned int *ebx,
+ unsigned int *ecx,
+ unsigned int *edx,
+ struct x86_emulate_ctxt *ctxt)
+{
+ unsigned int leaf = *eax;
+
+ asm ("cpuid" : "+a" (*eax), "+c" (*ecx), "=d" (*edx), "=b" (*ebx));
+
+ /* The emulator doesn't itself use MOVBE, so we can always run the test. */
+ if ( leaf == 1 )
+ *ecx |= 1U << 22;
+
+ return X86EMUL_OKAY;
+}
+
+#define cache_line_size() ({ \
+ unsigned int eax = 1, ebx, ecx = 0, edx; \
+ emul_cpuid(&eax, &ebx, &ecx, &edx, NULL); \
+ edx & (1U << 19) ? (ebx >> 5) & 0x7f8 : 0; \
+})
+
+#define cpu_has_mmx ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ emul_cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 23)) != 0; \
+})
+
+#define cpu_has_sse ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ emul_cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 25)) != 0; \
+})
+
+#define cpu_has_sse2 ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ emul_cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 26)) != 0; \
+})
+
+#define cpu_has_xsave ({ \
+ unsigned int eax = 1, ecx = 0; \
+ emul_cpuid(&eax, &eax, &ecx, &eax, NULL); \
+ /* Intentionally checking OSXSAVE here. */ \
+ (ecx & (1U << 27)) != 0; \
+})
+
+static inline uint64_t xgetbv(uint32_t xcr)
+{
+ uint32_t lo, hi;
+
+ asm ( ".byte 0x0f, 0x01, 0xd0" : "=a" (lo), "=d" (hi) : "c" (xcr) );
+
+ return ((uint64_t)hi << 32) | lo;
+}
+
+#define cpu_has_avx ({ \
+ unsigned int eax = 1, ecx = 0; \
+ emul_cpuid(&eax, &eax, &ecx, &eax, NULL); \
+ if ( !(ecx & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \
+ ecx = 0; \
+ (ecx & (1U << 28)) != 0; \
+})
+
+#define cpu_has_avx2 ({ \
+ unsigned int eax = 1, ebx, ecx = 0; \
+ emul_cpuid(&eax, &ebx, &ecx, &eax, NULL); \
+ if ( !(ecx & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \
+ ebx = 0; \
+ else { \
+ eax = 7, ecx = 0; \
+ cpuid(&eax, &ebx, &ecx, &eax, NULL); \
+ } \
+ (ebx & (1U << 5)) != 0; \
+})
+
+static int emul_read_cr(
+ unsigned int reg,
+ unsigned long *val,
+ struct x86_emulate_ctxt *ctxt)
+{
+ /* Fake just enough state for the emulator's _get_fpu() to be happy. */
+ switch ( reg )
+ {
+ case 0:
+ *val = 0x00000001; /* PE */
+ return X86EMUL_OKAY;
+
+ case 4:
+ /* OSFXSR, OSXMMEXCPT, and maybe OSXSAVE */
+ *val = 0x00000600 | (cpu_has_xsave ? 0x00040000 : 0);
+ return X86EMUL_OKAY;
+ }
+
+ return X86EMUL_UNHANDLEABLE;
+}
+
+int emul_get_fpu(
+ void (*exception_callback)(void *, struct cpu_user_regs *),
+ void *exception_callback_arg,
+ enum x86_emulate_fpu_type type,
+ struct x86_emulate_ctxt *ctxt)
+{
+ switch ( type )
+ {
+ case X86EMUL_FPU_fpu:
+ break;
+ case X86EMUL_FPU_mmx:
+ if ( cpu_has_mmx )
+ break;
+ case X86EMUL_FPU_xmm:
+ if ( cpu_has_sse )
+ break;
+ case X86EMUL_FPU_ymm:
+ if ( cpu_has_avx )
+ break;
+ default:
+ return X86EMUL_UNHANDLEABLE;
+ }
+ return X86EMUL_OKAY;
+}
+
+struct x86_emulate_ops emulops = {
+ .read = emul_read,
+ .insn_fetch = emul_fetch,
+ .write = emul_write,
+ .cmpxchg = emul_cmpxchg,
+ .cpuid = emul_cpuid,
+ .read_cr = emul_read_cr,
+ .get_fpu = emul_get_fpu,
+};
+
+bool make_stack_executable(void) {
+ unsigned long sp;
+ bool stack_exec;
+
+ /*
+ * Mark the entire stack executable so that the stub executions
+ * don't fault
+ */
+#define MMAP_SZ 16384
+
+#ifdef __x86_64__
+ asm ("movq %%rsp, %0" : "=g" (sp));
+#else
+ asm ("movl %%esp, %0" : "=g" (sp));
+#endif
+
+ stack_exec = mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000),
+ MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0;
+ if ( !stack_exec )
+ printf("Warning: Stack could not be made executable (%d).\n", errno);
+
+ return stack_exec;
+}
+
+#define CANONICALIZE(x) \
+ do { \
+ uint64_t _y = (x); \
+ if ( _y & (1ULL<<47) ) { \
+ _y |= (~0ULL)<<48; \
+ } else { \
+ _y &= (1ULL<<48)-1; \
+ } \
+ printf("Canonicalized %" PRIx64 " to %" PRIx64 "\n", x, _y); \
+ (x) = _y; \
+ } while(0)
+
+#define ADDR_SIZE_SHIFT 60
+#define ADDR_SIZE_64 (2ULL<<ADDR_SIZE_SHIFT)
+#define ADDR_SIZE_32 (1ULL<<ADDR_SIZE_SHIFT)
+#define ADDR_SIZE_16 (0)
+
+int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size) {
+ struct cpu_user_regs regs = {};
+ struct x86_emulate_ctxt ctxt =
+ {
+ .regs = ®s,
+ .addr_size = 8 * sizeof(void *),
+ .sp_size = 8 * sizeof(void *),
+ };
+
+ int nr = 0;
+ int rc;
+ unsigned x;
+ const uint8_t *p = data_p;
+
+ make_stack_executable();
+
+ memset(data, 0, sizeof(data));
+
+ nr = size < sizeof(regs) ? size : sizeof(regs);
+
+ memcpy(®s, p, nr);
+ p += sizeof(regs);
+ nr += sizeof(regs);
+
+ if (nr <= size) {
+ memcpy(data, p, size - nr);
+ data_max = size - nr;
+ }
+
+ ctxt.force_writeback = 0;
+
+ /* Zero 'private' entries */
+ regs.error_code = 0;
+ regs.entry_vector = 0;
+
+ /* Use the upper bits of regs.eip to determine addr_size */
+ x = (regs.rip >> ADDR_SIZE_SHIFT) & 0x3;
+ if (x == 3)
+ x = 2;
+ ctxt.addr_size = 16 << x;
+ printf("addr_size: %d\n", ctxt.addr_size);
+
+ /* Use the upper bit of regs.rsp to determine sp_size (if appropriate) */
+ if ( ctxt.addr_size == 64) {
+ ctxt.sp_size = 64;
+ } else {
+ /* If addr_size isn't 64-bits, sp_size can only be 16 or 32 bits */
+ x = (regs.rsp >> ADDR_SIZE_SHIFT) & 0x1;
+ ctxt.sp_size = 16 << x;
+ }
+ printf("sp_size: %d\n", ctxt.sp_size);
+ CANONICALIZE(regs.rip);
+ CANONICALIZE(regs.rsp);
+ CANONICALIZE(regs.rbp);
+
+ /* Zero all segments for now */
+ regs.cs = regs.ss = regs.es = regs.ds = regs.fs = regs.gs = 0;
+
+ do {
+ rc = x86_emulate(&ctxt, &emulops);
+ printf("Emulation result: %d\n", rc);
+ } while (rc == X86EMUL_OKAY);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.1.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |