x86/hvm: don't discard the SW/HW event distinction from the emulator
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 29 Sep 2014 08:22:23 +0000 (10:22 +0200)
committerJan Beulich <jbeulich@suse.com>
Mon, 29 Sep 2014 08:22:23 +0000 (10:22 +0200)
Injecting emulator software events as hardware exceptions results in a bypass
of DPL checks.  As the emulator doesn't perform DPL checks itself, guest
userspace is capable of bypassing DPL checks and injecting arbitrary events.

Propagating software event information from the emulator allows VMX to now
properly inject software events, including DPL and presence checks, as well
correct fault/trap frames.

Reported-by: Andrei LUTAS <vlutas@bitdefender.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrei LUTAS <vlutas@bitdefender.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
xen/arch/x86/hvm/emulate.c
xen/arch/x86/hvm/io.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/realmode.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/emulate.h

index 5d5d765b8b5e1c56404f8a1c5446dc1db7442bdc..7ee146b0b81857580b1822d46cc5104057beeb91 100644 (file)
@@ -441,9 +441,10 @@ static int hvmemul_virtual_to_linear(
 
     /* This is a singleton operation: fail it with an exception. */
     hvmemul_ctxt->exn_pending = 1;
-    hvmemul_ctxt->exn_vector = TRAP_gp_fault;
-    hvmemul_ctxt->exn_error_code = 0;
-    hvmemul_ctxt->exn_insn_len = 0;
+    hvmemul_ctxt->trap.vector = TRAP_gp_fault;
+    hvmemul_ctxt->trap.type = X86_EVENTTYPE_HW_EXCEPTION;
+    hvmemul_ctxt->trap.error_code = 0;
+    hvmemul_ctxt->trap.insn_len = 0;
     return X86EMUL_EXCEPTION;
 }
 
@@ -1111,9 +1112,10 @@ static int hvmemul_inject_hw_exception(
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
 
     hvmemul_ctxt->exn_pending = 1;
-    hvmemul_ctxt->exn_vector = vector;
-    hvmemul_ctxt->exn_error_code = error_code;
-    hvmemul_ctxt->exn_insn_len = 0;
+    hvmemul_ctxt->trap.vector = vector;
+    hvmemul_ctxt->trap.type = X86_EVENTTYPE_HW_EXCEPTION;
+    hvmemul_ctxt->trap.error_code = error_code;
+    hvmemul_ctxt->trap.insn_len = 0;
 
     return X86EMUL_OKAY;
 }
@@ -1127,10 +1129,29 @@ static int hvmemul_inject_sw_interrupt(
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
 
+    switch ( type )
+    {
+    case x86_swint_icebp:
+        hvmemul_ctxt->trap.type = X86_EVENTTYPE_PRI_SW_EXCEPTION;
+        break;
+
+    case x86_swint_int3:
+    case x86_swint_into:
+        hvmemul_ctxt->trap.type = X86_EVENTTYPE_SW_EXCEPTION;
+        break;
+
+    case x86_swint_int:
+        hvmemul_ctxt->trap.type = X86_EVENTTYPE_SW_INTERRUPT;
+        break;
+
+    default:
+        return X86EMUL_UNHANDLEABLE;
+    }
+
     hvmemul_ctxt->exn_pending = 1;
-    hvmemul_ctxt->exn_vector = vector;
-    hvmemul_ctxt->exn_error_code = -1;
-    hvmemul_ctxt->exn_insn_len = insn_len;
+    hvmemul_ctxt->trap.vector = vector;
+    hvmemul_ctxt->trap.error_code = HVM_DELIVER_NO_ERROR_CODE;
+    hvmemul_ctxt->trap.insn_len = insn_len;
 
     return X86EMUL_OKAY;
 }
@@ -1404,7 +1425,7 @@ void hvm_mem_event_emulate_one(bool_t nowrite, unsigned int trapnr,
         break;
     case X86EMUL_EXCEPTION:
         if ( ctx.exn_pending )
-            hvm_inject_hw_exception(ctx.exn_vector, ctx.exn_error_code);
+            hvm_inject_trap(&ctx.trap);
         break;
     }
 
index 9f565d612b9ffacfe2d0110cef53e415e1e7f992..e5d5e796ff242179aaa4d083881298c0ebd0377f 100644 (file)
@@ -113,7 +113,7 @@ int handle_mmio(void)
         return 0;
     case X86EMUL_EXCEPTION:
         if ( ctxt.exn_pending )
-            hvm_inject_hw_exception(ctxt.exn_vector, ctxt.exn_error_code);
+            hvm_inject_trap(&ctxt.trap);
         break;
     default:
         break;
index 30af10d8e220328f8daad794ef72bf5299250b77..fadbe9378c0853c5b44931b6c90299d334d4108e 100644 (file)
@@ -2093,7 +2093,7 @@ static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs)
         break;
     case X86EMUL_EXCEPTION:
         if ( ctxt.exn_pending )
-            hvm_inject_hw_exception(ctxt.exn_vector, ctxt.exn_error_code);
+            hvm_inject_trap(&ctxt.trap);
         /* fall through */
     default:
         hvm_emulate_writeback(&ctxt);
index 45066b270bced8e05c6fc733a02a604d62c6e82e..9a6de6c4416e822c8bd1a99d1bc45da15a43ad8a 100644 (file)
@@ -129,27 +129,27 @@ static void realmode_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt)
                 gdprintk(XENLOG_ERR, "Exception pending but no info.\n");
                 goto fail;
             }
-            hvmemul_ctxt->exn_vector = (uint8_t)intr_info;
-            hvmemul_ctxt->exn_insn_len = 0;
+            hvmemul_ctxt->trap.vector = (uint8_t)intr_info;
+            hvmemul_ctxt->trap.insn_len = 0;
         }
 
         if ( unlikely(curr->domain->debugger_attached) &&
-             ((hvmemul_ctxt->exn_vector == TRAP_debug) ||
-              (hvmemul_ctxt->exn_vector == TRAP_int3)) )
+             ((hvmemul_ctxt->trap.vector == TRAP_debug) ||
+              (hvmemul_ctxt->trap.vector == TRAP_int3)) )
         {
             domain_pause_for_debugger();
         }
         else if ( curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE )
         {
             gdprintk(XENLOG_ERR, "Exception %02x in protected mode.\n",
-                     hvmemul_ctxt->exn_vector);
+                     hvmemul_ctxt->trap.vector);
             goto fail;
         }
         else
         {
             realmode_deliver_exception(
-                hvmemul_ctxt->exn_vector,
-                hvmemul_ctxt->exn_insn_len,
+                hvmemul_ctxt->trap.vector,
+                hvmemul_ctxt->trap.insn_len,
                 hvmemul_ctxt);
         }
     }
index fd0ad59c047e7e01fffd9fba6825878a9fcf0fb3..304aeea22d38f3e9445148181ff33658f8a1c85e 100644 (file)
@@ -2523,7 +2523,7 @@ static void vmx_vmexit_ud_intercept(struct cpu_user_regs *regs)
         break;
     case X86EMUL_EXCEPTION:
         if ( ctxt.exn_pending )
-            hvm_inject_hw_exception(ctxt.exn_vector, ctxt.exn_error_code);
+            hvm_inject_trap(&ctxt.trap);
         /* fall through */
     default:
         hvm_emulate_writeback(&ctxt);
index efff97eaa1d5ccca2715c770881da9460c2577eb..6cdc57b9240ee6e171c7de46f13d6a3ca88a30ef 100644 (file)
@@ -13,6 +13,7 @@
 #define __ASM_X86_HVM_EMULATE_H__
 
 #include <xen/config.h>
+#include <asm/hvm/hvm.h>
 #include <asm/x86_emulate.h>
 
 struct hvm_emulate_ctxt {
@@ -28,9 +29,7 @@ struct hvm_emulate_ctxt {
     unsigned long seg_reg_dirty;
 
     bool_t exn_pending;
-    uint8_t exn_vector;
-    uint8_t exn_insn_len;
-    int32_t exn_error_code;
+    struct hvm_trap trap;
 
     uint32_t intr_shadow;
 };