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 <george.dun...@citrix.com> --- v2: Rebase on top of previous changes CC: Ian Jackson <ian.jack...@citrix.com> CC: Wei Liu <wei.l...@citrix.com> CC: Andrew Cooper <andrew.coop...@citrix.com> CC: Jan Beulich <jbeul...@suse.com> --- tools/fuzz/x86_instruction_emulator/fuzz-emul.c | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c index 21d00b7416..48cad0307a 100644 --- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c +++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c @@ -38,6 +38,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. */ const struct fuzz_corpus *corpus; @@ -597,6 +599,47 @@ static const struct x86_emulate_ops all_fuzzer_ops = { }; #undef SET +static void _set_fpu_state(char *fxsave, bool store) +{ + if ( cpu_has_fxsr ) + { + static union __attribute__((__aligned__(16))) { + char x[464]; + struct { + uint32_t other[6]; + uint32_t mxcsr; + uint32_t mxcsr_mask; + /* ... */ + }; + } *fxs; + + fxs = (typeof(fxs)) fxsave; + + if ( store ) { + char null[512] __attribute__((aligned(16))) = { 0 }; + asm volatile(" fxrstor %0; "::"m"(*null)); + asm volatile(" fxrstor %0; "::"m"(*fxsave)); + } + + asm volatile( "fxsave %0" : "=m" (*fxs) ); + + if ( fxs->mxcsr_mask ) + mxcsr_mask = fxs->mxcsr_mask; + else + mxcsr_mask = 0x000ffbf; + } +} + +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 */ @@ -737,6 +780,17 @@ 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 ) + { + 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" */ @@ -883,6 +937,9 @@ static void sanitize_state(struct x86_emulate_ctxt *ctxt) s->segments[x86_seg_cs].db = 0; s->segments[x86_seg_ss].db = 0; } + + /* Setting this value seems to cause crashes in fxrstor */ + *((unsigned int *)(s->fxsave) + 6) = 0; } int LLVMFuzzerInitialize(int *argc, char ***argv) @@ -920,6 +977,8 @@ 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(); @@ -931,6 +990,8 @@ int runtest(struct fuzz_state *state) { printf("Emulation result: %d\n", rc); } while ( rc == X86EMUL_OKAY ); + save_fpu_state(state->fxsave); + return 0; } @@ -1007,6 +1068,16 @@ 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"); -- 2.14.1 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel