From patchwork Tue Oct 10 16:20:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: George Dunlap X-Patchwork-Id: 9997939 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 3C20B601AE for ; Tue, 10 Oct 2017 21:35:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2EC1F28705 for ; Tue, 10 Oct 2017 21:35:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2383B287BE; Tue, 10 Oct 2017 21:35:51 +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=-2.6 required=2.0 tests=BAYES_00, DATE_IN_PAST_03_06, 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 A647228705 for ; Tue, 10 Oct 2017 21:35:50 +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 1e229S-0000xB-K0; Tue, 10 Oct 2017 21:33:22 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e229R-0000x2-OW for xen-devel@lists.xenproject.org; Tue, 10 Oct 2017 21:33:21 +0000 Received: from [193.109.254.147] by server-5.bemta-6.messagelabs.com id 1C/6D-29911-1AC3DD95; Tue, 10 Oct 2017 21:33:21 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprGIsWRWlGSWpSXmKPExsXitHSDve4Cm7u RBgv+qlh83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBm37mxmK7ilXdHxzbuB8ZhCFyMnh4SAv8Tf b40sIDabgJ7EvONfgWwODhEBFYnbew26GLk4mAX2M0r0fv3BBlIjLOAuce38L7B6FgFVie+/7 4PZvAK2EkcvTmCCmCkv8X7BfUYQmxMovvtcLzuILSRgI7GtfTIThK0qsfjBUXaIXkGJkzOfgM 1hFpCQOPjiBfMERt5ZSFKzkKQWMDKtYtQoTi0qSy3SNTTVSyrKTM8oyU3MzNE1NDDTy00tLk5 MT81JTCrWS87P3cQIDB0GINjB+G1ZwCFGSQ4mJVHe1+p3I4X4kvJTKjMSizPii0pzUosPMcpw cChJ8D6zBsoJFqWmp1akZeYAgxgmLcHBoyTCOwskzVtckJhbnJkOkTrFaMxxbNPlP0wcHTfv/ mESYsnLz0uVEuetBSkVACnNKM2DGwSLrkuMslLCvIxApwnxFKQW5WaWoMq/YhTnYFQS5p0HMo UnM68Ebt8roFOYgE4RTbsDckpJIkJKqoGxt+zD9SBhRkv25dsyNu+vFJHX1Q5Yuthwyyb24vi aon/XW6ZY3j0vlJO69dqjGez6QU4HLuslzegp/N99qVTX7LPydbYVlvsPLco+OT+4cxWXGNuv +FmHsyrn31VnnJyi9eHQgtO3t05ZfNHNdPoBCQG9asPSlzKGKTO+2q+v+r5GxGJizgwhJZbij ERDLeai4kQAGfP3SKkCAAA= X-Env-Sender: prvs=4495d6a26=George.Dunlap@citrix.com X-Msg-Ref: server-4.tower-27.messagelabs.com!1507671198!110258899!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.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 8178 invoked from network); 10 Oct 2017 21:33:20 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-4.tower-27.messagelabs.com with RC4-SHA encrypted SMTP; 10 Oct 2017 21:33:20 -0000 X-IronPort-AV: E=Sophos;i="5.43,359,1503360000"; d="scan'208";a="452872735" From: George Dunlap To: Date: Tue, 10 Oct 2017 17:20:10 +0100 Message-ID: <20171010162011.9629-11-george.dunlap@citrix.com> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20171010162011.9629-1-george.dunlap@citrix.com> References: <20171010162011.9629-1-george.dunlap@citrix.com> MIME-Version: 1.0 Cc: Ian Jackson , Wei Liu , George Dunlap , Jan Beulich , Andrew Cooper Subject: [Xen-devel] [PATCH v3 11/12] fuzz/x86_emulate: Set and fuzz more CPU state 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 x86_emulate() operates not only on state passed to it in cpu_user_regs, but also on state currently found on the cpu: namely, the FPU and XMM registers. At the moment, we re-zero (and/or re-initialize) cpu_user_regs on every invocation, but leave the cpu-stored state alone. In "persistent mode", this causes test cases to behave differently -- sometimes significantly so -- depending on which test cases have been run beforehand. Zero out the state before each test run, and then fuzz it based on the corpus input. Signed-off-by: George Dunlap --- v3: - Make type 512 bytes rather than 464 - Style changes - Change argument from 'store' to 'write' - Add a comment explaining why we always 'save' even for a write - Sanitize mxcsr with mxcrs_mask when writing instead of zeroing it in sanitize_state - Get rid of redundant mxcsr_mask setting - Add comments explaining why we're arbitrarily writing 32 bits v2: Rebase on top of previous changes CC: Ian Jackson CC: Wei Liu CC: Andrew Cooper CC: Jan Beulich --- tools/fuzz/x86_instruction_emulator/fuzz-emul.c | 82 ++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c index 7685e976b8..79dd36ec30 100644 --- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c +++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c @@ -40,6 +40,8 @@ struct fuzz_state uint64_t msr[MSR_INDEX_MAX]; struct segment_register segments[SEG_NUM]; struct cpu_user_regs regs; + char fxsave[512] __attribute__((aligned(16))); + /* Fuzzer's input data. */ #define DATA_SIZE_FULL offsetof(struct fuzz_state, corpus) @@ -596,6 +598,54 @@ static const struct x86_emulate_ops all_fuzzer_ops = { }; #undef SET +/* + * This funciton will read or write fxsave to the fpu. When writing, + * it 'sanitizes' the state: It will mask off the appropriate bits in + * the mxcsr, 'restore' the state to the fpu, then 'save' it again so + * that the data in fxsave reflects what's actually in the FPU. + * + * TODO: Extend state beyond just FPU (ymm registers, &c) + */ +static void _set_fpu_state(char *fxsave, bool write) +{ + if ( cpu_has_fxsr ) + { + static union __attribute__((__aligned__(16))) { + char x[512]; + struct { + uint32_t other[6]; + uint32_t mxcsr; + uint32_t mxcsr_mask; + /* ... */ + }; + } *fxs; + + fxs = (typeof(fxs)) fxsave; + + if ( write ) + { + char null[512] __attribute__((aligned(16))) = { }; + + fxs->mxcsr &= mxcsr_mask; + + asm volatile( "fxrstor %0" :: "m" (*null) ); + asm volatile( "fxrstor %0" :: "m" (*fxs) ); + } + + asm volatile( "fxsave %0" : "=m" (*fxs) ); + } +} + +static void set_fpu_state(char *fxsave) +{ + _set_fpu_state(fxsave, true); +} + +static void save_fpu_state(char *fxsave) +{ + _set_fpu_state(fxsave, false); +} + static void setup_fpu_exception_handler(void) { /* FIXME - just disable exceptions for now */ @@ -674,7 +724,11 @@ static void setup_state(struct x86_emulate_ctxt *ctxt) return; } - /* Modify only select bits of state */ + /* + * Modify only select bits of state. In general, try not to fuzz less + * than 32 bits at a time; otherwise we're reading 2 bytes in order to fuzz only + * one byte. + */ /* Always read 'options' */ if ( !input_read(s, s, DATA_SIZE_COMPACT) ) @@ -737,6 +791,18 @@ static void setup_state(struct x86_emulate_ctxt *ctxt) printf("Setting cpu_user_regs offset %x\n", offset); continue; } + offset -= sizeof(struct cpu_user_regs); + + /* Fuzz fxsave state */ + if ( offset < 128 ) + { + /* 32-bit size is arbitrary; see comment above */ + if ( !input_read(s, s->fxsave + (offset * 4), 4) ) + return; + printf("Setting fxsave offset %x\n", offset * 4); + continue; + } + offset -= 128; /* None of the above -- take that as "start emulating" */ @@ -919,6 +985,8 @@ static int runtest(struct fuzz_state *state) { disable_hooks(state); + set_fpu_state(state->fxsave); + do { /* FIXME: Until we actually implement SIGFPE handling properly */ setup_fpu_exception_handler(); @@ -930,6 +998,8 @@ static int runtest(struct fuzz_state *state) { printf("Emulation result: %d\n", rc); } while ( rc == X86EMUL_OKAY ); + save_fpu_state(state->fxsave); + return 0; } @@ -1013,6 +1083,16 @@ static void compare_states(struct fuzz_state state[2]) if ( memcmp(&state[0].ops, &state[1].ops, sizeof(state[0].ops)) ) printf("ops differ!\n"); + if ( memcmp(&state[0].fxsave, &state[1].fxsave, sizeof(state[0].fxsave)) ) + { + printf("fxsave differs!\n"); + for ( i = 0; i < sizeof(state[0].fxsave)/sizeof(unsigned); i++ ) + { + printf("[%04lu] %08x %08x\n", + i * sizeof(unsigned), ((unsigned *)&state[0].fxsave)[i], ((unsigned *)&state[1].fxsave)[i]); + } + } + if ( memcmp(&state[0].ctxt, &state[1].ctxt, sizeof(state[0].ctxt)) ) { printf("ctxt differs!\n");