From patchwork Thu Dec 8 13:54:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9466441 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 12ABC60231 for ; Thu, 8 Dec 2016 13:57:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F14462843C for ; Thu, 8 Dec 2016 13:57:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E5FE8284F6; Thu, 8 Dec 2016 13:57:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2DE4E2843C for ; Thu, 8 Dec 2016 13:57:13 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cEz9t-0005k4-52; Thu, 08 Dec 2016 13:54:49 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cEz9r-0005is-RZ for xen-devel@lists.xenproject.org; Thu, 08 Dec 2016 13:54:47 +0000 Received: from [193.109.254.147] by server-11.bemta-6.messagelabs.com id 41/C6-28490-72669485; Thu, 08 Dec 2016 13:54:47 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRWlGSWpSXmKPExsXitHRDpK5amme EwevvNhbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8asuz1MBc/CK3bNucjSwDjXqYuRk0NCwF/i zo8L7CA2m4CyxM/OXjYQW0RAT6LpwHPGLkYuDmaBF0wSF9+sZwRJCAsES1x5fg2oiIODRUBF4 uz2NJAwr4CzRPf96SwQM+Ukzh//yQxicwq4SLy90AfWKgRU87RpNxOErSDRMf0YE0SvoMTJmU /AepkFJCQOvnjBPIGRdxaS1CwkqQWMTKsY1YtTi8pSi3SN9JKKMtMzSnITM3N0DQ3M9HJTi4s T01NzEpOK9ZLzczcxAkOHAQh2MC7763SIUZKDSUmUd9cE9wghvqT8lMqMxOKM+KLSnNTiQ4wy HBxKEryyqZ4RQoJFqempFWmZOcAghklLcPAoifDqJgOleYsLEnOLM9MhUqcYdTmmPVv8lEmIJ S8/L1VKnPdCClCRAEhRRmke3AhYRF1ilJUS5mUEOkqIpyC1KDezBFX+FaM4B6OSMO8ckCk8mX klcJteAR3BBHTEvBvuIEeUJCKkpBoY14a8fv/kY+nGWRmG+xwu3ppeGD8xoD/459kDjT7btq3 /vYb77LuO41bddvkrT+dNrDkY47Find6JBemMWZdPLP8d5/1pWcgM/vy1Jksyi/JeJkxZoMUW warl0bi4iWdB9Zlskdlpuo5h2QFdYc0v18h+Vj672fNym9p6S/buabs3S/huK7djU2Ipzkg01 GIuKk4EADzfrlijAgAA X-Env-Sender: prvs=143286959=wei.liu2@citrix.com X-Msg-Ref: server-15.tower-27.messagelabs.com!1481205283!23517255!4 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.0.16; banners=-,-,- X-VirusChecked: Checked Received: (qmail 7498 invoked from network); 8 Dec 2016 13:54:46 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-15.tower-27.messagelabs.com with RC4-SHA encrypted SMTP; 8 Dec 2016 13:54:46 -0000 X-IronPort-AV: E=Sophos;i="5.33,319,1477958400"; d="scan'208";a="393731807" From: Wei Liu To: Xen-devel Date: Thu, 8 Dec 2016 13:54:39 +0000 Message-ID: <1481205281-18256-4-git-send-email-wei.liu2@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1481205281-18256-1-git-send-email-wei.liu2@citrix.com> References: <1481205281-18256-1-git-send-email-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: Stefano Stabellini , Wei Liu , George Dunlap , Andrew Cooper , Ian Jackson , George Dunlap , Tim Deegan , Jan Beulich Subject: [Xen-devel] [PATCH VERY RFC 3/5] tools/fuzz: introduce x86 instruction emulator target X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 Signed-off-by: George Dunlap Signed-off-by: Wei Liu --- Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu --- .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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) & 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: + */