[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] x86emul/fuzz: add a state sanity checking function



commit 8a184632a17f5a6a513d5b08f3ebeae5fe1e1f27
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Mon Jun 3 17:15:06 2019 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Jun 3 17:15:06 2019 +0200

    x86emul/fuzz: add a state sanity checking function
    
    This is to accompany sanitize_input(). Just like for initial state we
    want to have state between two emulated insns sane, at least as far as
    assumptions in the main emulator go. Do minimal checking after segment
    register, CR, and MSR writes, and roll back to the old value in case of
    failure (raising #GP(0) at the same time).
    
    In the particular case observed, a CR0 write clearing CR0.PE was
    followed by a VEX-encoded insn, which the decoder accepts based on
    guest address size, restricting things just outside of the 64-bit case
    (real and virtual modes don't allow VEX-encoded insns). Subsequently
    _get_fpu() would then assert that CR0.PE must be set (and EFLAGS.VM
    clear) when trying to invoke YMM, ZMM, or OPMASK state.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: George Dunlap <george.dunlap@xxxxxxxxxx>
---
 tools/fuzz/x86_instruction_emulator/fuzz-emul.c | 57 ++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c 
b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
index 4bcb6c2bf6..34b844d91a 100644
--- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
+++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
@@ -76,6 +76,8 @@ static inline bool input_read(struct fuzz_state *s, void 
*dst, size_t size)
     return true;
 }
 
+static bool check_state(struct x86_emulate_ctxt *ctxt);
+
 static const char* const x86emul_return_string[] = {
     [X86EMUL_OKAY] = "X86EMUL_OKAY",
     [X86EMUL_UNHANDLEABLE] = "X86EMUL_UNHANDLEABLE",
@@ -424,8 +426,19 @@ static int fuzz_write_segment(
     rc = maybe_fail(ctxt, "write_segment", true);
 
     if ( rc == X86EMUL_OKAY )
+    {
+        struct segment_register old = c->segments[seg];
+
         c->segments[seg] = *reg;
 
+        if ( !check_state(ctxt) )
+        {
+            c->segments[seg] = old;
+            x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
+            rc = X86EMUL_EXCEPTION;
+        }
+    }
+
     return rc;
 }
 
@@ -452,6 +465,7 @@ static int fuzz_write_cr(
 {
     struct fuzz_state *s = ctxt->data;
     struct fuzz_corpus *c = s->corpus;
+    unsigned long old;
     int rc;
 
     if ( reg >= ARRAY_SIZE(c->cr) )
@@ -461,9 +475,17 @@ static int fuzz_write_cr(
     if ( rc != X86EMUL_OKAY )
         return rc;
 
+    old = c->cr[reg];
     c->cr[reg] = val;
 
-    return X86EMUL_OKAY;
+    if ( !check_state(ctxt) )
+    {
+        c->cr[reg] = old;
+        x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
+        rc = X86EMUL_EXCEPTION;
+    }
+
+    return rc;
 }
 
 #define fuzz_read_xcr emul_test_read_xcr
@@ -561,7 +583,16 @@ static int fuzz_write_msr(
     {
         if ( msr_index[idx] == reg )
         {
+            uint64_t old = c->msr[idx];
+
             c->msr[idx] = val;
+
+            if ( !check_state(ctxt) )
+            {
+                c->msr[idx] = old;
+                break;
+            }
+
             return X86EMUL_OKAY;
         }
     }
@@ -811,6 +842,30 @@ static void sanitize_input(struct x86_emulate_ctxt *ctxt)
     }
 }
 
+/*
+ * Call this function from hooks potentially altering machine state into
+ * something that's not architecturally valid, yet which - as per above -
+ * the emulator relies on.
+ */
+static bool check_state(struct x86_emulate_ctxt *ctxt)
+{
+    const struct fuzz_state *s = ctxt->data;
+    const struct fuzz_corpus *c = s->corpus;
+    const struct cpu_user_regs *regs = &c->regs;
+
+    if ( long_mode_active(ctxt) && !(c->cr[0] & X86_CR0_PG) )
+        return false;
+
+    if ( (c->cr[0] & X86_CR0_PG) && !(c->cr[0] & X86_CR0_PE) )
+        return false;
+
+    if ( (regs->rflags & X86_EFLAGS_VM) &&
+         (c->segments[x86_seg_cs].db || c->segments[x86_seg_ss].db) )
+        return false;
+
+    return true;
+}
+
 int LLVMFuzzerInitialize(int *argc, char ***argv)
 {
     if ( !emul_test_init() )
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.