WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] Clean up SVM instruction-fetch code some more

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH] Clean up SVM instruction-fetch code some more
From: Tim Deegan <Tim.Deegan@xxxxxxxxxx>
Date: Fri, 2 May 2008 16:32:28 +0100
Delivery-date: Fri, 02 May 2008 08:32:57 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.17 (2007-11-01)
SVM: clean up __get_instruction_length_from_list()

Remove unused arguments, fix its behaviour near page boundaries,
inject appropriate pagefaults, and kill the guest only if the
instruction is not decodable or %eip is not pointing to valid RAM.

Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxx>

diff -r 483d006cc607 -r c20b8931b598 xen/arch/x86/hvm/svm/emulate.c
--- a/xen/arch/x86/hvm/svm/emulate.c    Fri Apr 25 13:46:27 2008 +0100
+++ b/xen/arch/x86/hvm/svm/emulate.c    Fri May 02 16:28:05 2008 +0100
@@ -28,18 +28,6 @@
 #include <asm/hvm/svm/emulate.h>
 
 #define MAX_INST_LEN 15
-
-static int inst_copy_from_guest(
-    unsigned char *buf, unsigned long guest_eip, int inst_len)
-{
-    struct vmcb_struct *vmcb = current->arch.hvm_svm.vmcb;
-    uint32_t pfec = (vmcb->cpl == 3) ? PFEC_user_mode : 0;
-    if ( (inst_len > MAX_INST_LEN) || (inst_len <= 0) )
-        return 0;
-    if ( hvm_fetch_from_guest_virt_nofault(buf, guest_eip, inst_len, pfec) )
-        return 0;
-    return inst_len;
-}
 
 static unsigned int is_prefix(u8 opc)
 {
@@ -101,29 +89,47 @@ static const u8 *opc_bytes[INSTR_MAX_COU
     [INSTR_INT3]   = OPCODE_INT3
 };
 
+static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
+{
+    uint32_t pfec = (v->arch.hvm_svm.vmcb->cpl == 3) ? PFEC_user_mode : 0;
+
+    switch ( hvm_fetch_from_guest_virt(buf, addr, len, pfec) )
+    {
+    case HVMCOPY_okay:
+        return 1;
+    case HVMCOPY_bad_gva_to_gfn:
+        /* OK just to give up; we'll have injected #PF already */
+        return 0;
+    case HVMCOPY_bad_gfn_to_mfn:
+    default:
+        /* Not OK: fetches from non-RAM pages are not supportable. */
+        gdprintk(XENLOG_ERR, "Bad instruction fetch at %#lx (%#lx)\n",
+                 (unsigned long) guest_cpu_user_regs()->eip, addr);
+        domain_crash(v->domain);
+        return 0;
+    }
+}
+
 int __get_instruction_length_from_list(struct vcpu *v,
-        enum instruction_index *list, unsigned int list_count, 
-        u8 *guest_eip_buf, enum instruction_index *match)
+        enum instruction_index *list, unsigned int list_count)
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     unsigned int i, j, inst_len = 0;
     int found = 0;
     enum instruction_index instr = 0;
-    u8 buffer[MAX_INST_LEN];
-    u8 *buf;
+    u8 buf[MAX_INST_LEN];
     const u8 *opcode = NULL;
-
-    if ( guest_eip_buf )
-    {
-        buf = guest_eip_buf;
-    }
-    else
-    {
-        if ( inst_copy_from_guest(buffer, svm_rip2pointer(v), MAX_INST_LEN)
-             != MAX_INST_LEN )
-            return 0;
-        buf = buffer;
-    }
+    unsigned long fetch_addr;
+    int fetch_len;
+
+    /* Fetch up to the next page break; we'll fetch from the next page
+     * later if we have to. */
+    fetch_addr = svm_rip2pointer(v);
+    fetch_len = PAGE_SIZE - (fetch_addr & ~PAGE_MASK) ;
+    if ( fetch_len > MAX_INST_LEN ) 
+        fetch_len = MAX_INST_LEN;
+    if ( !fetch(v, buf, fetch_addr, fetch_len) )
+        return 0;
 
     for ( j = 0; j < list_count; j++ )
     {
@@ -134,17 +140,36 @@ int __get_instruction_length_from_list(s
         while ( (inst_len < MAX_INST_LEN) && 
                 is_prefix(buf[inst_len]) && 
                 !is_prefix(opcode[1]) )
+        {
             inst_len++;
+            if ( inst_len >= fetch_len ) 
+            { 
+                if ( !fetch(v, buf + fetch_len,
+                            fetch_addr + fetch_len,
+                            MAX_INST_LEN - fetch_len) )
+                    return 0;
+                fetch_len = MAX_INST_LEN;
+            }
+        }
 
         ASSERT(opcode[0] <= 15);    /* Make sure the table is correct. */
         found = 1;
 
-        for ( i = 0; i < opcode[0]; i++ )
+        for ( i = 0; i < opcode[0] && inst_len + i < MAX_INST_LEN; i++ )
         {
             /* If the last byte is zero, we just accept it without checking */
             if ( (i == (opcode[0]-1)) && (opcode[i+1] == 0) )
                 break;
 
+            if ( inst_len + i >= fetch_len ) 
+            { 
+                if ( !fetch(v, buf + fetch_len, 
+                            fetch_addr + fetch_len, 
+                            MAX_INST_LEN - fetch_len) ) 
+                    return 0;
+                fetch_len = MAX_INST_LEN;
+            }
+
             if ( buf[inst_len+i] != opcode[i+1] )
             {
                 found = 0;
@@ -158,13 +183,12 @@ int __get_instruction_length_from_list(s
 
     printk("%s: Mismatch between expected and actual instruction bytes: "
             "eip = %lx\n",  __func__, (unsigned long)vmcb->rip);
+    domain_crash(v->domain);
     return 0;
 
  done:
     inst_len += opcode[0];
     ASSERT(inst_len <= MAX_INST_LEN);
-    if ( match )
-        *match = instr;
     return inst_len;
 }
 
diff -r 483d006cc607 -r c20b8931b598 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Fri Apr 25 13:46:27 2008 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Fri May 02 16:28:05 2008 +0100
@@ -84,7 +84,10 @@ static void inline __update_guest_eip(
 {
     struct vcpu *curr = current;
 
-    if ( unlikely((inst_len == 0) || (inst_len > 15)) )
+    if ( unlikely(inst_len == 0) )
+        return;
+
+    if ( unlikely(inst_len > 15) )
     {
         gdprintk(XENLOG_ERR, "Bad instruction length %u\n", inst_len);
         domain_crash(curr->domain);
@@ -907,7 +910,7 @@ static void svm_vmexit_do_cpuid(struct c
 {
     unsigned int eax, ebx, ecx, edx, inst_len;
 
-    inst_len = __get_instruction_length(current, INSTR_CPUID, NULL);
+    inst_len = __get_instruction_length(current, INSTR_CPUID);
     if ( inst_len == 0 ) 
         return;
 
@@ -1084,12 +1087,12 @@ static void svm_do_msr_access(struct cpu
     if ( vmcb->exitinfo1 == 0 )
     {
         rc = hvm_msr_read_intercept(regs);
-        inst_len = __get_instruction_length(v, INSTR_RDMSR, NULL);
+        inst_len = __get_instruction_length(v, INSTR_RDMSR);
     }
     else
     {
         rc = hvm_msr_write_intercept(regs);
-        inst_len = __get_instruction_length(v, INSTR_WRMSR, NULL);
+        inst_len = __get_instruction_length(v, INSTR_WRMSR);
     }
 
     if ( rc == X86EMUL_OKAY )
@@ -1103,7 +1106,7 @@ static void svm_vmexit_do_hlt(struct vmc
     struct hvm_intack intack = hvm_vcpu_has_pending_irq(curr);
     unsigned int inst_len;
 
-    inst_len = __get_instruction_length(curr, INSTR_HLT, NULL);
+    inst_len = __get_instruction_length(curr, INSTR_HLT);
     if ( inst_len == 0 )
         return;
     __update_guest_eip(regs, inst_len);
@@ -1140,7 +1143,7 @@ static void svm_vmexit_do_invalidate_cac
     svm_wbinvd_intercept();
 
     inst_len = __get_instruction_length_from_list(
-        current, list, ARRAY_SIZE(list), NULL, NULL);
+        current, list, ARRAY_SIZE(list));
     __update_guest_eip(regs, inst_len);
 }
 
@@ -1216,7 +1219,7 @@ asmlinkage void svm_vmexit_handler(struc
         if ( !v->domain->debugger_attached )
             goto exit_and_crash;
         /* AMD Vol2, 15.11: INT3, INTO, BOUND intercepts do not update RIP. */
-        inst_len = __get_instruction_length(v, INSTR_INT3, NULL);
+        inst_len = __get_instruction_length(v, INSTR_INT3);
         __update_guest_eip(regs, inst_len);
         domain_pause_for_debugger();
         break;
@@ -1293,7 +1296,7 @@ asmlinkage void svm_vmexit_handler(struc
         break;
 
     case VMEXIT_VMMCALL:
-        inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL);
+        inst_len = __get_instruction_length(v, INSTR_VMCALL);
         if ( inst_len == 0 )
             break;
         HVMTRACE_1D(VMMCALL, v, regs->eax);
diff -r 483d006cc607 -r c20b8931b598 xen/include/asm-x86/hvm/svm/emulate.h
--- a/xen/include/asm-x86/hvm/svm/emulate.h     Fri Apr 25 13:46:27 2008 +0100
+++ b/xen/include/asm-x86/hvm/svm/emulate.h     Fri May 02 16:28:05 2008 +0100
@@ -34,15 +34,12 @@ enum instruction_index {
 };
 
 int __get_instruction_length_from_list(
-    struct vcpu *v,
-    enum instruction_index *list, unsigned int list_count, 
-    u8 *guest_eip_buf, enum instruction_index *match);
+    struct vcpu *v, enum instruction_index *list, unsigned int list_count);
 
 static inline int __get_instruction_length(struct vcpu *v, 
-        enum instruction_index instr, u8 *guest_eip_buf)
+                                           enum instruction_index instr)
 {
-    return __get_instruction_length_from_list(
-        v, &instr, 1, guest_eip_buf, NULL);
+    return __get_instruction_length_from_list(v, &instr, 1);
 }
 
 #endif /* __ASM_X86_HVM_SVM_EMULATE_H__ */

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH] Clean up SVM instruction-fetch code some more, Tim Deegan <=