From patchwork Tue Jan 31 11:08:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9546939 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 98AF0604A0 for ; Tue, 31 Jan 2017 11:19:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 89AAF26224 for ; Tue, 31 Jan 2017 11:19:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7E31C28338; Tue, 31 Jan 2017 11:19:26 +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 9572B26224 for ; Tue, 31 Jan 2017 11:19:22 +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 1cYWQa-0002R8-N0; Tue, 31 Jan 2017 11:16:48 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYWQa-0002Qp-1j for xen-devel@lists.xenproject.org; Tue, 31 Jan 2017 11:16:48 +0000 Received: from [85.158.137.68] by server-4.bemta-3.messagelabs.com id 4B/7F-01392-F1270985; Tue, 31 Jan 2017 11:16:47 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprIIsWRWlGSWpSXmKPExsXitHSDva5c0YQ IgyMPmSy+b5nM5MDocfjDFZYAxijWzLyk/IoE1oz/a+6xF0ydw1jxoO0NUwPj5JIuRk4OCQF/ ifd3djKD2GwCyhI/O3vZQGwRAT2JpgPPGbsYuTiYBT4wSvzfvIS1i5GDQ1jAVGLj6iqQGhYBV Yknzx+D1fMKWEqsnjKJDWKmvMSutotg5ZxA8Z3PckHCQgIWEucWdbFB2AoSHdOPMUG0CkqcnP mEBcRmFpCQOPjiBfMERt5ZSFKzkKQWMDKtYtQoTi0qSy3SNTTRSyrKTM8oyU3MzNE1NDDWy00 tLk5MT81JTCrWS87P3cQIDB4GINjBuGK75yFGSQ4mJVHez8ITIoT4kvJTKjMSizPii0pzUosP McpwcChJ8E4qAMoJFqWmp1akZeYAwxgmLcHBoyTCWw+S5i0uSMwtzkyHSJ1i1OU4deP0SyYhl rz8vFQpcV6OQqAiAZCijNI8uBGwmLrEKCslzMsIdJQQT0FqUW5mCar8K0ZxDkYlYd4/IKt4Mv NK4Da9AjqCCegI91d9IEeUJCKkpBoYi5q2uYpPZPt9yH6G4Gr1tGShz1P71bx7faZNOX4xaPW X0/0yx9eH7JJcwmHOrz9r74X05YGTNoi0X5xlu/Yg90xL5bkp0W03XynG7X5rbvZ/12WvqOkP A7ff3LUgd+vH6tZNC+tvVZXeORajvm5Jws3TvrNVltQJ7XiiPOeTSdLMjkP+pkZar5VYijMSD bWYi4oTAfZ1thukAgAA X-Env-Sender: prvs=1976b8d93=wei.liu2@citrix.com X-Msg-Ref: server-10.tower-31.messagelabs.com!1485861402!82530687!1 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 42207 invoked from network); 31 Jan 2017 11:16:44 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-10.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 31 Jan 2017 11:16:44 -0000 X-IronPort-AV: E=Sophos;i="5.33,314,1477958400"; d="scan'208";a="411964010" From: Wei Liu To: Xen-devel Date: Tue, 31 Jan 2017 11:08:07 +0000 Message-ID: <20170131110809.30001-11-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170131110809.30001-1-wei.liu2@citrix.com> References: <20170131110809.30001-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: Wei Liu , George Dunlap , Andrew Cooper , Ian Jackson , George Dunlap , Jan Beulich Subject: [Xen-devel] [PATCH v2 10/12] fuzz/x86emul: update fuzzer 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 Provide the fuzzer with more ops, and more sophisticated input structure. Based on a patch originally written by Andrew and George. Signed-off-by: Andrew Cooper Signed-off-by: George Dunlap Signed-off-by: Wei Liu --- Cc: Ian Jackson Cc: Jan Beulich Cc: Andrew Cooper Cc: George Dunlap v2: 1. Address comments from Jan. 2. Provide architecturally correct behaviour for rep stub. --- .../x86-insn-emulator-fuzzer.c | 660 +++++++++++++++++++-- 1 file changed, 598 insertions(+), 62 deletions(-) diff --git a/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c index 7d7f731677..ef223e856d 100644 --- a/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c +++ b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -16,26 +17,79 @@ #include "x86_emulate.h" -static unsigned char data[4096]; +#include "../../../xen/include/asm-x86/msr-index.h" + +#define MSR_INDEX_MAX 16 + +#define SEG_NUM x86_seg_none + +struct input_struct { + unsigned long cr[5]; + uint64_t msr[MSR_INDEX_MAX]; + struct cpu_user_regs regs; + struct segment_register segments[SEG_NUM]; + unsigned long options; + unsigned char data[4096]; +} input; +#define DATA_OFFSET offsetof(struct input_struct, data) static unsigned int data_index; -static unsigned int data_max; +static unsigned int data_num; + +/* Randomly return success or failure when processing data. If + * `exception` is false, this function turns _EXCEPTION to _OKAY. + */ +int maybe_fail(const char *why, bool exception) +{ + int rc; + + if ( data_index + 1 > data_num ) + rc = X86EMUL_EXCEPTION; + else + { + /* Randomly returns value: + * 50% okay + * 25% unhandlable + * 25% exception + */ + if ( input.data[data_index] > 0xc0 ) + rc = X86EMUL_EXCEPTION; + else if ( input.data[data_index] > 0x80 ) + rc = X86EMUL_UNHANDLEABLE; + else + rc = X86EMUL_OKAY; + data_index++; + } + + if ( rc == X86EMUL_EXCEPTION && !exception ) + rc = X86EMUL_OKAY; + + printf("maybe_fail %s: %d\n", why, rc); + + return rc; +} static int data_read(const char *why, void *dst, unsigned int bytes) { unsigned int i; + int rc; - if ( data_index + bytes > data_max ) - return X86EMUL_EXCEPTION; + if ( data_index + bytes > data_num ) + rc = X86EMUL_EXCEPTION; + else + rc = maybe_fail(why, true); - memcpy(dst, data + data_index, bytes); - data_index += bytes; + if ( rc == X86EMUL_OKAY ) + { + memcpy(dst, input.data + data_index, bytes); + data_index += bytes; - printf("%s: ", why); - for ( i = 0; i < bytes; i++ ) - printf(" %02x", *(unsigned char *)(dst + i)); - printf("\n"); + printf("%s: ", why); + for ( i = 0; i < bytes; i++ ) + printf(" %02x", *(unsigned char *)(dst + i)); + printf("\n"); + } - return X86EMUL_OKAY; + return rc; } static int fuzz_read( @@ -48,14 +102,96 @@ static int fuzz_read( return data_read("read", p_data, bytes); } -static int fuzz_fetch( +static int fuzz_read_io( + unsigned int port, + unsigned int bytes, + unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + return data_read("read_io", val, bytes); +} + +static int fuzz_insn_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); + return data_read("insn_fetch", p_data, bytes); +} + +static int _fuzz_rep_read(const char *why, unsigned long *reps) +{ + int rc; + unsigned long bytes_read = 0; + + rc = data_read(why, &bytes_read, sizeof(bytes_read)); + + if ( bytes_read < *reps ) + *reps -= bytes_read; + + /* Indicate we haven't done any work if emulation has failed */ + if ( rc != X86EMUL_OKAY ) + *reps = 0; + + return rc; +} + +static int _fuzz_rep_write(const char *why, unsigned long *reps) +{ + int rc = maybe_fail(why, true); + + /* Indicate we haven't done any work if emulation has failed */ + if ( rc != X86EMUL_OKAY ) + *reps = 0; + + return rc; +} + +static int fuzz_rep_ins( + uint16_t src_port, + enum x86_segment dst_seg, + unsigned long dst_offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return _fuzz_rep_read("rep_in", reps); +} + +static int fuzz_rep_movs( + enum x86_segment src_seg, + unsigned long src_offset, + enum x86_segment dst_seg, + unsigned long dst_offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return _fuzz_rep_read("rep_movs", reps); +} + +static int fuzz_rep_outs( + enum x86_segment src_seg, + unsigned long src_offset, + uint16_t dst_port, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return _fuzz_rep_write("rep_outs", reps); +} + +static int fuzz_rep_stos( + void *p_data, + enum x86_segment seg, + unsigned long offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return _fuzz_rep_write("rep_stos", reps); } static int fuzz_write( @@ -65,7 +201,7 @@ static int fuzz_write( unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - return X86EMUL_OKAY; + return maybe_fail("write", true); } static int fuzz_cmpxchg( @@ -76,18 +212,294 @@ static int fuzz_cmpxchg( unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - return X86EMUL_OKAY; + return maybe_fail("cmpxchg", true); +} + +static int fuzz_invlpg( + enum x86_segment seg, + unsigned long offset, + struct x86_emulate_ctxt *ctxt) +{ + return maybe_fail("invlpg", false); +} + +static int fuzz_wbinvd( + struct x86_emulate_ctxt *ctxt) +{ + return maybe_fail("wbinvd", true); +} + +static int fuzz_write_io( + unsigned int port, + unsigned int bytes, + unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + return maybe_fail("write_io", true); +} + +static int fuzz_cpuid( + uint32_t leaf, + uint32_t subleaf, + struct cpuid_leaf *res, + struct x86_emulate_ctxt *ctxt) +{ + return emul_test_cpuid(leaf, subleaf, res, ctxt); +} + +static int fuzz_read_segment( + enum x86_segment seg, + struct segment_register *reg, + struct x86_emulate_ctxt *ctxt) +{ + int rc; + + if ( seg > SEG_NUM ) + return X86EMUL_UNHANDLEABLE; + + rc = maybe_fail("read_segment", true); + + if ( rc == X86EMUL_OKAY ) + memcpy(reg, input.segments+seg, sizeof(struct segment_register)); + + return rc; +} + +static int fuzz_write_segment( + enum x86_segment seg, + const struct segment_register *reg, + struct x86_emulate_ctxt *ctxt) +{ + int rc; + + if ( seg > SEG_NUM ) + return X86EMUL_UNHANDLEABLE; + + rc = maybe_fail("write_segment", true); + + if ( rc == X86EMUL_OKAY ) + memcpy(input.segments+seg, reg, sizeof(struct segment_register)); + + return rc; +} + +static int fuzz_read_cr( + unsigned int reg, + unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + int rc; + + if ( reg > ARRAY_SIZE(input.cr) ) + return X86EMUL_UNHANDLEABLE; + + rc = maybe_fail("read_cr", true); + + if ( rc == X86EMUL_OKAY ) + *val = input.cr[reg]; + + return rc; +} + +static int fuzz_write_cr( + unsigned int reg, + unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + int rc; + + if ( reg > ARRAY_SIZE(input.cr) ) + return X86EMUL_UNHANDLEABLE; + + rc = maybe_fail("write_cr", true); + + if ( rc == X86EMUL_OKAY ) + input.cr[reg] = val; + + return rc; +} + +enum { + MSRI_IA32_SYSENTER_CS, + MSRI_IA32_SYSENTER_ESP, + MSRI_IA32_SYSENTER_EIP, + MSRI_EFER, + MSRI_STAR, + MSRI_LSTAR, + MSRI_CSTAR, + MSRI_SYSCALL_MASK +}; + +const static unsigned int msr_index[MSR_INDEX_MAX] = { + [MSRI_IA32_SYSENTER_CS] = MSR_IA32_SYSENTER_CS, + [MSRI_IA32_SYSENTER_ESP] = MSR_IA32_SYSENTER_ESP, + [MSRI_IA32_SYSENTER_EIP] = MSR_IA32_SYSENTER_EIP, + [MSRI_EFER] = MSR_EFER, + [MSRI_STAR] = MSR_STAR, + [MSRI_LSTAR] = MSR_LSTAR, + [MSRI_CSTAR] = MSR_CSTAR, + [MSRI_SYSCALL_MASK] = MSR_SYSCALL_MASK +}; + +static int _fuzz_read_msr( + unsigned int reg, + uint64_t *val, + struct x86_emulate_ctxt *ctxt) +{ + unsigned int idx; + + switch ( reg ) + { + case MSR_TSC_AUX: + case MSR_IA32_TSC: + return data_read("read_msr", val, sizeof(*val)); + case MSR_EFER: + *val = input.msr[MSRI_EFER]; + *val &= ~EFER_LMA; + if ( (*val & EFER_LME) && (input.cr[4] & X86_CR4_PAE) && + (input.cr[0] & X86_CR0_PG) ) + { + printf("Setting EFER_LMA\n"); + *val |= EFER_LMA; + } + return X86EMUL_OKAY; + } + + for ( idx = 0; idx < MSR_INDEX_MAX; idx++ ) + { + if ( msr_index[idx] == reg ) + { + *val = input.msr[idx]; + return X86EMUL_OKAY; + } + } + + return X86EMUL_EXCEPTION; +} + +static int fuzz_read_msr( + unsigned int reg, + uint64_t *val, + struct x86_emulate_ctxt *ctxt) { + int rc; + + rc = maybe_fail("read_msr", true); + if ( rc != X86EMUL_OKAY ) + return rc; + else + return _fuzz_read_msr(reg, val, ctxt); +} + +static int fuzz_write_msr( + unsigned int reg, + uint64_t val, + struct x86_emulate_ctxt *ctxt) +{ + unsigned int idx; + int rc; + + rc = maybe_fail("write_ms", true); + if ( rc != X86EMUL_OKAY ) + return rc; + + switch ( reg ) + { + case MSR_TSC_AUX: + case MSR_IA32_TSC: + return X86EMUL_OKAY; + } + + for ( idx = 0; idx < MSR_INDEX_MAX; idx++ ) + { + if ( msr_index[idx] == reg ) + { + input.msr[idx] = val; + return X86EMUL_OKAY; + } + } + + return X86EMUL_EXCEPTION; } +#define SET(h) .h = fuzz_##h static struct x86_emulate_ops fuzz_emulops = { - .read = fuzz_read, - .insn_fetch = fuzz_fetch, - .write = fuzz_write, - .cmpxchg = fuzz_cmpxchg, - .cpuid = emul_test_cpuid, - .read_cr = emul_test_read_cr, + SET(read), + SET(insn_fetch), + SET(write), + SET(cmpxchg), + SET(rep_ins), + SET(rep_outs), + SET(rep_movs), + SET(rep_stos), + SET(read_segment), + SET(write_segment), + SET(read_io), + SET(write_io), + SET(read_cr), + SET(write_cr), + SET(read_msr), + SET(write_msr), + SET(wbinvd), + SET(cpuid), + SET(invlpg), .get_fpu = emul_test_get_fpu, }; +#undef SET + +static void setup_fpu_exception_handler(void) +{ + /* FIXME - just disable exceptions for now */ + unsigned long a; + + asm volatile ( "fnclex"); + a=0x37f; /* FCW_DEFAULT in Xen */ + asm volatile ( "fldcw %0" :: "m" (a)); + a=0x1f80; /* MXCSR_DEFAULT in Xen */ + asm volatile ( "ldmxcsr %0" :: "m" (a) ); +} + +static void dump_state(struct x86_emulate_ctxt *ctxt) +{ + struct cpu_user_regs *regs = ctxt->regs; + uint64_t val; + + printf(" -- State -- \n"); + printf("addr / sp size: %d / %d\n", ctxt->addr_size, ctxt->sp_size); + printf(" cr0: %lx\n", input.cr[0]); + printf(" cr3: %lx\n", input.cr[3]); + printf(" cr4: %lx\n", input.cr[4]); + + printf(" rip: %"PRIx64"\n", regs->rip); + + _fuzz_read_msr(MSR_EFER, &val, ctxt); + printf("EFER: %"PRIx64"\n", val); +} + +static bool long_mode_active(struct x86_emulate_ctxt *ctxt) +{ + uint64_t val; + + if ( _fuzz_read_msr(MSR_EFER, &val, ctxt) != X86EMUL_OKAY ) + return false; + + return val & EFER_LMA; +} + +static bool in_longmode(struct x86_emulate_ctxt *ctxt) +{ + return long_mode_active(ctxt) && input.segments[x86_seg_cs].attr.fields.l; +} + +static void set_sizes(struct x86_emulate_ctxt *ctxt) +{ + if ( in_longmode(ctxt) ) + ctxt->addr_size = ctxt->sp_size = 64; + else + { + ctxt->addr_size = input.segments[x86_seg_cs].attr.fields.db ? 32 : 16; + ctxt->sp_size = input.segments[x86_seg_ss].attr.fields.db ? 32 : 16; + } +} #define CANONICALIZE(x) \ do { \ @@ -100,10 +512,150 @@ static struct x86_emulate_ops fuzz_emulops = { (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) +/* Expects bitmap and regs to be defined */ +#define CANONICALIZE_MAYBE(reg) \ + if ( !(bitmap & (1 << CANONICALIZE_##reg)) ) \ + CANONICALIZE(regs->reg); \ + +enum { + HOOK_read, + HOOK_insn_fetch, + HOOK_write, + HOOK_cmpxchg, + HOOK_rep_ins, + HOOK_rep_outs, + HOOK_rep_movs, + HOOK_rep_stos, + HOOK_read_segment, + HOOK_write_segment, + HOOK_read_io, + HOOK_write_io, + HOOK_read_cr, + HOOK_write_cr, + HOOK_read_dr, + HOOK_write_dr, + HOOK_read_msr, + HOOK_write_msr, + HOOK_wbinvd, + HOOK_cpuid, + HOOK_inject_hw_exception, + HOOK_inject_sw_interrupt, + HOOK_get_fpu, + HOOK_put_fpu, + HOOK_invlpg, + HOOK_vmfunc, + OPTION_swint_emulation, /* Two bits */ + CANONICALIZE_rip = OPTION_swint_emulation + 2, + CANONICALIZE_rsp, + CANONICALIZE_rbp +}; + +/* Expects bitmap to be defined */ +#define MAYBE_DISABLE_HOOK(h) \ + if ( bitmap & (1 << HOOK_##h) ) \ + { \ + fuzz_emulops.h = NULL; \ + printf("Disabling hook "#h"\n"); \ + } + +static void disable_hooks(void) +{ + unsigned long bitmap = input.options; + + /* See also sanitize_input, some hooks can't be disabled. */ + MAYBE_DISABLE_HOOK(read); + MAYBE_DISABLE_HOOK(insn_fetch); + MAYBE_DISABLE_HOOK(write); + MAYBE_DISABLE_HOOK(cmpxchg); + MAYBE_DISABLE_HOOK(rep_ins); + MAYBE_DISABLE_HOOK(rep_outs); + MAYBE_DISABLE_HOOK(rep_movs); + MAYBE_DISABLE_HOOK(rep_stos); + MAYBE_DISABLE_HOOK(read_segment); + MAYBE_DISABLE_HOOK(write_segment); + MAYBE_DISABLE_HOOK(read_io); + MAYBE_DISABLE_HOOK(write_io); + MAYBE_DISABLE_HOOK(read_cr); + MAYBE_DISABLE_HOOK(write_cr); + MAYBE_DISABLE_HOOK(read_msr); + MAYBE_DISABLE_HOOK(write_msr); + MAYBE_DISABLE_HOOK(wbinvd); + MAYBE_DISABLE_HOOK(cpuid); + MAYBE_DISABLE_HOOK(get_fpu); + MAYBE_DISABLE_HOOK(invlpg); +} + +static void set_swint_support(struct x86_emulate_ctxt *ctxt) +{ + unsigned int swint_opt = (input.options >> OPTION_swint_emulation) & 3; + + static const enum x86_swint_emulation map[4] = { + x86_swint_emulate_none, + x86_swint_emulate_none, + x86_swint_emulate_icebp, + x86_swint_emulate_all }; + + ctxt->swint_emulate = map[swint_opt]; +} + +/* + * Constrain input to architecturally-possible states where + * the emulator relies on these + * + * In general we want the emulator to be as absolutely robust as + * possible; which means that we want to minimize the number of things + * it assumes about the input state. Tesing this means minimizing and + * removing as much of the input constraints as possible. + * + * So we only add constraints that (in general) have been proven to + * cause crashes in the emulator. + * + * For future reference: other constraints which might be necessary at + * some point: + * + * - EFER.LMA => !EFLAGS.NT + * - In VM86 mode (and real mode?), force segment... + * - ...access rights to 0xf3 + * - ...limits to 0xffff + * - ...bases to below 1Mb, 16-byte aligned + * - ...selectors to (base >> 4) + */ +void sanitize_input(struct x86_emulate_ctxt *ctxt) { + struct cpu_user_regs *regs = &input.regs; + unsigned long bitmap = input.options; + + /* Some hooks can't be disabled. */ + input.options &= ~((1<error_code = 0; + regs->entry_vector = 0; + + CANONICALIZE_MAYBE(rip); + CANONICALIZE_MAYBE(rsp); + CANONICALIZE_MAYBE(rbp); + + /* + * CR0.PG can't be set if CR0.PE isn't set. Set is more interesting, so + * set PE if PG is set. + */ + if ( input.cr[0] & X86_CR0_PG ) + input.cr[0] |= X86_CR0_PE; + + /* + * EFLAGS.VM not available in long mode + */ + if ( long_mode_active(ctxt) ) + regs->rflags &= ~X86_EFLAGS_VM; + + /* + * EFLAGS.VM implies 16-bit mode + */ + if ( regs->rflags & X86_EFLAGS_VM ) { + input.segments[x86_seg_cs].attr.fields.db = 0; + input.segments[x86_seg_ss].attr.fields.db = 0; + } +} int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size) { @@ -114,10 +666,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size) .addr_size = 8 * sizeof(void *), .sp_size = 8 * sizeof(void *), }; - unsigned int nr = 0; int rc; - unsigned int x; - const uint8_t *p = data_p; stack_exec = emul_test_make_stack_executable(); if ( !stack_exec ) @@ -127,52 +676,39 @@ int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size) } /* Reset all global state variables */ - memset(data, 0, sizeof(data)); + memset(&input, 0, sizeof(input)); data_index = 0; - data_max = 0; - - nr = size < sizeof(regs) ? size : sizeof(regs); + data_num = 0; - memcpy(®s, p, nr); - p += sizeof(regs); + if ( size <= DATA_OFFSET ) + { + printf("Input too small\n"); + return 1; + } - if ( nr < size ) + if ( size > sizeof(input) ) { - memcpy(data, p, size - nr); - data_max = size - nr; + printf("Input too large\n"); + return 1; } - ctxt.force_writeback = false; + memcpy(&input, data_p, size); - /* Zero 'private' fields */ - regs.error_code = 0; - regs.entry_vector = 0; + data_num = size - DATA_OFFSET; - /* 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); + sanitize_input(&ctxt); - /* 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); + disable_hooks(); - /* Zero all segments for now */ - regs.cs = regs.ss = regs.es = regs.ds = regs.fs = regs.gs = 0; + set_swint_support(&ctxt); do { + /* FIXME: Until we actually implement SIGFPE handling properly */ + setup_fpu_exception_handler(); + + set_sizes(&ctxt); + dump_state(&ctxt); + rc = x86_emulate(&ctxt, &fuzz_emulops); printf("Emulation result: %d\n", rc); } while ( rc == X86EMUL_OKAY );