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

[Xen-changelog] [xen-unstable] [HVM][VMX] Clean up and audit VMX uses of instruction-length



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID a753630a6456541bc90c32a17e4b452bcece825d
# Parent  140dff9d90dca30cb8f8e258e8976ce2dafb73e2
[HVM][VMX] Clean up and audit VMX uses of instruction-length
info field. Todo: use by mmio decoder needs to be removed.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/svm/svm.c            |    4 
 xen/arch/x86/hvm/vmx/io.c             |    8 +
 xen/arch/x86/hvm/vmx/vmx.c            |  138 ++++++++++++++++++++++------------
 xen/include/asm-x86/hvm/svm/emulate.h |   32 +------
 xen/include/asm-x86/hvm/vmx/vmx.h     |   38 ---------
 5 files changed, 109 insertions(+), 111 deletions(-)

diff -r 140dff9d90dc -r a753630a6456 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Fri Sep 22 09:12:00 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Fri Sep 22 11:33:03 2006 +0100
@@ -1847,12 +1847,12 @@ static int svm_cr_access(struct vcpu *v,
        where the prefix lives later on */
     index = skip_prefix_bytes(buffer, sizeof(buffer));
     
-    if (type == TYPE_MOV_TO_CR) 
+    if ( type == TYPE_MOV_TO_CR )
     {
         inst_len = __get_instruction_length_from_list(
             vmcb, list_a, ARR_SIZE(list_a), &buffer[index], &match);
     }
-    else
+    else /* type == TYPE_MOV_FROM_CR */
     {
         inst_len = __get_instruction_length_from_list(
             vmcb, list_b, ARR_SIZE(list_b), &buffer[index], &match);
diff -r 140dff9d90dc -r a753630a6456 xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Fri Sep 22 09:12:00 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/io.c Fri Sep 22 11:33:03 2006 +0100
@@ -108,11 +108,17 @@ asmlinkage void vmx_intr_assist(void)
         return;
     }
 
+    /* This could be moved earlier in the VMX resume sequence. */
     __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
     if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
         __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
 
-        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+        /*
+         * Safe: the length will only be interpreted for software exceptions
+         * and interrupts. If we get here then delivery of some event caused a
+         * fault, and this always results in defined VM_EXIT_INSTRUCTION_LEN.
+         */
+        __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len); /* Safe */
         __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
 
         if (unlikely(idtv_info_field & 0x800)) { /* valid error code */
diff -r 140dff9d90dc -r a753630a6456 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Fri Sep 22 09:12:00 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Fri Sep 22 11:33:03 2006 +0100
@@ -597,7 +597,7 @@ static int vmx_instruction_length(struct
 {
     unsigned long inst_len;
 
-    if (__vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len))
+    if ( __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len) ) /* XXX Unsafe XXX */
         return 0;
     return inst_len;
 }
@@ -836,11 +836,16 @@ int start_vmx(void)
 
 /*
  * Not all cases receive valid value in the VM-exit instruction length field.
+ * Callers must know what they're doing!
  */
-#define __get_instruction_length(len) \
-    __vmread(VM_EXIT_INSTRUCTION_LEN, &(len)); \
-     if ((len) < 1 || (len) > 15) \
-        __hvm_bug(&regs);
+static int __get_instruction_length(void)
+{
+    int len;
+    __vmread(VM_EXIT_INSTRUCTION_LEN, &len); /* Safe: callers audited */
+    if ( (len < 1) || (len > 15) )
+        __hvm_bug(guest_cpu_user_regs());
+    return len;
+}
 
 static void inline __update_guest_eip(unsigned long inst_len)
 {
@@ -1051,15 +1056,18 @@ static int check_for_null_selector(unsig
     int i, inst_len;
     int inst_copy_from_guest(unsigned char *, unsigned long, int);
 
-    __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+    inst_len = __get_instruction_length(); /* Safe: INS/OUTS */
     memset(inst, 0, MAX_INST_LEN);
-    if (inst_copy_from_guest(inst, eip, inst_len) != inst_len) {
+    if ( inst_copy_from_guest(inst, eip, inst_len) != inst_len )
+    {
         printf("check_for_null_selector: get guest instruction failed\n");
         domain_crash_synchronous();
     }
 
-    for (i = 0; i < inst_len; i++) {
-        switch (inst[i]) {
+    for ( i = 0; i < inst_len; i++ )
+    {
+        switch ( inst[i] )
+        {
         case 0xf3: /* REPZ */
         case 0xf2: /* REPNZ */
         case 0xf0: /* LOCK */
@@ -1184,15 +1192,14 @@ static void vmx_io_instruction(unsigned 
     }
 }
 
-int
-vmx_world_save(struct vcpu *v, struct vmx_assist_context *c)
-{
-    unsigned long inst_len;
+static int vmx_world_save(struct vcpu *v, struct vmx_assist_context *c)
+{
     int error = 0;
 
-    error |= __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+    /* NB. Skip transition instruction. */
     error |= __vmread(GUEST_RIP, &c->eip);
-    c->eip += inst_len; /* skip transition instruction */
+    c->eip += __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */
+
     error |= __vmread(GUEST_RSP, &c->esp);
     error |= __vmread(GUEST_RFLAGS, &c->eflags);
 
@@ -1249,8 +1256,7 @@ vmx_world_save(struct vcpu *v, struct vm
     return !error;
 }
 
-int
-vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c)
+static int vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c)
 {
     unsigned long mfn, old_cr4, old_base_mfn;
     int error = 0;
@@ -1364,8 +1370,7 @@ vmx_world_restore(struct vcpu *v, struct
 
 enum { VMX_ASSIST_INVOKE = 0, VMX_ASSIST_RESTORE };
 
-int
-vmx_assist(struct vcpu *v, int mode)
+static int vmx_assist(struct vcpu *v, int mode)
 {
     struct vmx_assist_context c;
     u32 magic;
@@ -1408,8 +1413,8 @@ vmx_assist(struct vcpu *v, int mode)
         break;
 
         /*
-         * Restore the VMXASSIST_OLD_CONTEXT that was saved by 
VMX_ASSIST_INVOKE
-         * above.
+         * Restore the VMXASSIST_OLD_CONTEXT that was saved by
+         * VMX_ASSIST_INVOKE above.
          */
     case VMX_ASSIST_RESTORE:
         /* save the old context */
@@ -1552,7 +1557,8 @@ static int vmx_set_cr0(unsigned long val
             }
         }
 
-        if ( vmx_assist(v, VMX_ASSIST_INVOKE) ) {
+        if ( vmx_assist(v, VMX_ASSIST_INVOKE) )
+        {
             set_bit(VMX_CPU_STATE_ASSIST_ENABLED, &v->arch.hvm_vmx.cpu_state);
             __vmread(GUEST_RIP, &eip);
             HVM_DBG_LOG(DBG_LEVEL_1,
@@ -1815,7 +1821,8 @@ static void mov_from_cr(int cr, int gp, 
     HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR%d, value = %lx", cr, value);
 }
 
-static int vmx_cr_access(unsigned long exit_qualification, struct 
cpu_user_regs *regs)
+static int vmx_cr_access(unsigned long exit_qualification,
+                         struct cpu_user_regs *regs)
 {
     unsigned int gp, cr;
     unsigned long value;
@@ -2069,6 +2076,47 @@ void restore_cpu_user_regs(struct cpu_us
 }
 #endif
 
+static void vmx_reflect_exception(struct vcpu *v)
+{
+    int error_code, intr_info, vector;
+
+    __vmread(VM_EXIT_INTR_INFO, &intr_info);
+    vector = intr_info & 0xff;
+    if ( intr_info & INTR_INFO_DELIVER_CODE_MASK )
+        __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
+    else
+        error_code = VMX_DELIVER_NO_ERROR_CODE;
+
+#ifndef NDEBUG
+    {
+        unsigned long rip;
+
+        __vmread(GUEST_RIP, &rip);
+        HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, error_code = %x",
+                    rip, error_code);
+    }
+#endif /* NDEBUG */
+
+    /*
+     * According to Intel Virtualization Technology Specification for
+     * the IA-32 Intel Architecture (C97063-002 April 2005), section
+     * 2.8.3, SW_EXCEPTION should be used for #BP and #OV, and
+     * HW_EXCEPTION used for everything else.  The main difference
+     * appears to be that for SW_EXCEPTION, the EIP/RIP is incremented
+     * by VM_ENTER_INSTRUCTION_LEN bytes, whereas for HW_EXCEPTION,
+     * it is not.
+     */
+    if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_SW_EXCEPTION )
+    {
+        int ilen = __get_instruction_length(); /* Safe: software exception */
+        vmx_inject_sw_exception(v, vector, ilen);
+    }
+    else
+    {
+        vmx_inject_hw_exception(v, vector, error_code);
+    }
+}
+
 asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
 {
     unsigned int exit_reason;
@@ -2116,7 +2164,8 @@ asmlinkage void vmx_vmexit_handler(struc
 
     TRACE_VMEXIT(0,exit_reason);
 
-    switch ( exit_reason ) {
+    switch ( exit_reason )
+    {
     case EXIT_REASON_EXCEPTION_NMI:
     {
         /*
@@ -2242,43 +2291,38 @@ asmlinkage void vmx_vmexit_handler(struc
         domain_crash_synchronous();
         break;
     case EXIT_REASON_CPUID:
+        inst_len = __get_instruction_length(); /* Safe: CPUID */
+        __update_guest_eip(inst_len);
         vmx_vmexit_do_cpuid(&regs);
-        __get_instruction_length(inst_len);
-        __update_guest_eip(inst_len);
         break;
     case EXIT_REASON_HLT:
-        __get_instruction_length(inst_len);
+        inst_len = __get_instruction_length(); /* Safe: HLT */
         __update_guest_eip(inst_len);
         vmx_vmexit_do_hlt();
         break;
     case EXIT_REASON_INVLPG:
     {
-        unsigned long   va;
-
+        unsigned long va;
+        inst_len = __get_instruction_length(); /* Safe: INVLPG */
+        __update_guest_eip(inst_len);
         __vmread(EXIT_QUALIFICATION, &va);
         vmx_vmexit_do_invlpg(va);
-        __get_instruction_length(inst_len);
+        break;
+    }
+    case EXIT_REASON_VMCALL:
+    {
+        inst_len = __get_instruction_length(); /* Safe: VMCALL */
         __update_guest_eip(inst_len);
-        break;
-    }
-    case EXIT_REASON_VMCALL:
-    {
-        __get_instruction_length(inst_len);
         __vmread(GUEST_RIP, &rip);
         __vmread(EXIT_QUALIFICATION, &exit_qualification);
-
         hvm_do_hypercall(&regs);
-        __update_guest_eip(inst_len);
         break;
     }
     case EXIT_REASON_CR_ACCESS:
     {
         __vmread(GUEST_RIP, &rip);
-        __get_instruction_length(inst_len);
         __vmread(EXIT_QUALIFICATION, &exit_qualification);
-
-        HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, inst_len =%lx, exit_qualification 
= %lx",
-                    rip, inst_len, exit_qualification);
+        inst_len = __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */
         if ( vmx_cr_access(exit_qualification, &regs) )
             __update_guest_eip(inst_len);
         TRACE_VMEXIT(3,regs.error_code);
@@ -2291,19 +2335,19 @@ asmlinkage void vmx_vmexit_handler(struc
         break;
     case EXIT_REASON_IO_INSTRUCTION:
         __vmread(EXIT_QUALIFICATION, &exit_qualification);
-        __get_instruction_length(inst_len);
+        inst_len = __get_instruction_length(); /* Safe: IN, INS, OUT, OUTS */
         vmx_io_instruction(exit_qualification, inst_len);
         TRACE_VMEXIT(4,exit_qualification);
         break;
     case EXIT_REASON_MSR_READ:
-        __get_instruction_length(inst_len);
+        inst_len = __get_instruction_length(); /* Safe: RDMSR */
+        __update_guest_eip(inst_len);
         vmx_do_msr_read(&regs);
+        break;
+    case EXIT_REASON_MSR_WRITE:
+        inst_len = __get_instruction_length(); /* Safe: WRMSR */
         __update_guest_eip(inst_len);
-        break;
-    case EXIT_REASON_MSR_WRITE:
         vmx_do_msr_write(&regs);
-        __get_instruction_length(inst_len);
-        __update_guest_eip(inst_len);
         break;
     case EXIT_REASON_MWAIT_INSTRUCTION:
     case EXIT_REASON_MONITOR_INSTRUCTION:
diff -r 140dff9d90dc -r a753630a6456 xen/include/asm-x86/hvm/svm/emulate.h
--- a/xen/include/asm-x86/hvm/svm/emulate.h     Fri Sep 22 09:12:00 2006 +0100
+++ b/xen/include/asm-x86/hvm/svm/emulate.h     Fri Sep 22 11:33:03 2006 +0100
@@ -94,15 +94,14 @@ static inline int __get_instruction_leng
 static inline int __get_instruction_length(struct vmcb_struct *vmcb, 
         enum instruction_index instr, u8 *guest_eip_buf)
 {
-    return __get_instruction_length_from_list(vmcb, &instr, 1, guest_eip_buf, 
-            NULL);
+    return __get_instruction_length_from_list(
+        vmcb, &instr, 1, guest_eip_buf, NULL);
 }
 
 
 static inline unsigned int is_prefix(u8 opc)
 {
-    switch(opc)
-    {
+    switch ( opc ) {
     case 0x66:
     case 0x67:
     case 0x2E:
@@ -115,22 +114,7 @@ static inline unsigned int is_prefix(u8 
     case 0xF3:
     case 0xF2:
 #if __x86_64__
-    case 0x40:
-    case 0x41:
-    case 0x42:
-    case 0x43:
-    case 0x44:
-    case 0x45:
-    case 0x46:
-    case 0x47:
-    case 0x48:
-    case 0x49:
-    case 0x4a:
-    case 0x4b:
-    case 0x4c:
-    case 0x4d:
-    case 0x4e:
-    case 0x4f:
+    case 0x40 ... 0x4f:
 #endif /* __x86_64__ */
         return 1;
     }
@@ -141,15 +125,15 @@ static inline int skip_prefix_bytes(u8 *
 static inline int skip_prefix_bytes(u8 *buf, size_t size)
 {
     int index;
-    for (index = 0; index < size && is_prefix(buf[index]); index ++)  
-        /* do nothing */ ;
+    for ( index = 0; index < size && is_prefix(buf[index]); index++ )
+        continue;
     return index;
 }
 
 
 
-static void inline __update_guest_eip(struct vmcb_struct *vmcb, 
-        int inst_len) 
+static void inline __update_guest_eip(
+    struct vmcb_struct *vmcb, int inst_len) 
 {
     ASSERT(inst_len > 0);
     vmcb->rip += inst_len;
diff -r 140dff9d90dc -r a753630a6456 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Fri Sep 22 09:12:00 2006 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Fri Sep 22 11:33:03 2006 +0100
@@ -469,7 +469,7 @@ static inline void __vmx_inject_exceptio
     if ( error_code != VMX_DELIVER_NO_ERROR_CODE ) {
         __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
         intr_fields |= INTR_INFO_DELIVER_CODE_MASK;
-     }
+    }
 
     if ( ilen )
       __vmwrite(VM_ENTRY_INSTRUCTION_LEN, ilen);
@@ -499,40 +499,4 @@ static inline void vmx_inject_extint(str
     __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
 }
 
-static inline void vmx_reflect_exception(struct vcpu *v)
-{
-    int error_code, intr_info, vector;
-
-    __vmread(VM_EXIT_INTR_INFO, &intr_info);
-    vector = intr_info & 0xff;
-    if ( intr_info & INTR_INFO_DELIVER_CODE_MASK )
-        __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
-    else
-        error_code = VMX_DELIVER_NO_ERROR_CODE;
-
-#ifndef NDEBUG
-    {
-        unsigned long rip;
-
-        __vmread(GUEST_RIP, &rip);
-        HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, error_code = %x",
-                    rip, error_code);
-    }
-#endif /* NDEBUG */
-
-    /* According to Intel Virtualization Technology Specification for
-       the IA-32 Intel Architecture (C97063-002 April 2005), section
-       2.8.3, SW_EXCEPTION should be used for #BP and #OV, and
-       HW_EXCPEPTION used for everything else.  The main difference
-       appears to be that for SW_EXCEPTION, the EIP/RIP is incremented
-       by VM_ENTER_INSTRUCTION_LEN bytes, whereas for HW_EXCEPTION,
-       it is not.  */
-    if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_SW_EXCEPTION ) {
-        int ilen;
-        __vmread(VM_EXIT_INSTRUCTION_LEN, &ilen);
-        vmx_inject_sw_exception(v, vector, ilen);
-    } else
-        vmx_inject_hw_exception(v, vector, error_code);
-}
-
 #endif /* __ASM_X86_HVM_VMX_VMX_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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