Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > d0a35cd31c1125e2132804d68547073d > files > 4504

kernel-2.6.18-194.26.1.el5.src.rpm

From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 12 Aug 2010 04:01:25 -0400
Subject: [xen] fix guest crash on non-EPT machine may crash host
Message-id: <1281585685-23028-1-git-send-email-pbonzini@redhat.com>
Patchwork-id: 4452
O-Subject: [kernel team] [EMBARGOED RHEL5.5.z/5.6 PATCH] xen: guest crashes on
	non-EPT machines may crash the host as well
Bugzilla: 621430
CVE: CVE-2010-2938
RH-Acked-by: Rik van Riel <riel@redhat.com>
RH-Acked-by: Don Dutile <ddutile@redhat.com>
RH-Acked-by: Andrew Jones <drjones@redhat.com>
RH-Acked-by: Chris Lalancette <clalance@redhat.com>
RH-Acked-by: Eugene Teo <eugene@redhat.com>

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=620490

Upstream status: http://xenbits.xensource.com/xen-unstable.hg?rev/15911

Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=2676393

In this bug the guest fails to launch for some reason (it never worked)
and this sends us down the failed vmentry path.  This is just a series
of print statements that rely on __vmread to dump the VMCS.  However,
__vmread will crash the host on purpose if it fails (vmreads _shouldn't_
fail, so this is done to catch HV bugs), and this happens if for instance
the host does not support EPT.  Instead, vmcs_dump_vcpu should use
__vmread_safe, whose main (only?) purpose is to allow printing VMCS data
safely when a problem has been detected, without peppering the dump
code with if statements.  In fact, before this patch __vmread_safe is
completely unused.

This patch backports an upstream commit that printed the information
in a more helpful format and, in the process, changed __vmread to
__vmread_safe so that there is no crash.

Tested by me.
---
 arch/x86/hvm/vmx/vmcs.c |  171 ++++++++++++++++++++++++++++++++++-------------
 1 files changed, 124 insertions(+), 47 deletions(-)

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/arch/x86/hvm/vmx/vmcs.c b/arch/x86/hvm/vmx/vmcs.c
index 015e2be..091f049 100644
--- a/arch/x86/hvm/vmx/vmcs.c
+++ b/arch/x86/hvm/vmx/vmcs.c
@@ -685,65 +685,142 @@ void vmx_do_resume(struct vcpu *v)
     reset_stack_and_jump(vmx_asm_do_vmentry);
 }
 
-/* Dump a section of VMCS */
-static void print_section(char *header, uint32_t start, 
-                          uint32_t end, int incr)
+static void vmx_dump_sel(char *name, enum x86_segment seg)
 {
-    uint32_t addr, j;
-    unsigned long val;
-    int code, rc;
-    char *fmt[4] = {"0x%04lx ", "0x%016lx ", "0x%08lx ", "0x%016lx "};
-    char *err[4] = {"------ ", "------------------ ", 
-                    "---------- ", "------------------ "};
-
-    /* Find width of the field (encoded in bits 14:13 of address) */
-    code = (start>>13)&3;
-
-    if (header)
-        printk("\t %s", header);
-
-    for (addr=start, j=0; addr<=end; addr+=incr, j++) {
-
-        if (!(j&3))
-            printk("\n\t\t0x%08x: ", addr);
-
-        val = __vmread_safe(addr, &rc);
-        if (rc == 0)
-            printk(fmt[code], val);
-        else
-            printk("%s", err[code]);
-    }
+    struct segment_register sreg;
+    hvm_get_segment_register(current, seg, &sreg);
+    printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n", 
+           name, sreg.sel, sreg.attr.bytes, sreg.limit,
+           (unsigned long long)sreg.base);
+}
 
-    printk("\n");
+static unsigned long vmr(unsigned long field)
+{
+    int rc;
+    unsigned long val;
+    val = __vmread_safe(field, &rc);
+    return rc ? 0 : val;
 }
 
-/* Dump current VMCS */
 void vmcs_dump_vcpu(void)
 {
-    print_section("16-bit Guest-State Fields", 0x800, 0x80e, 2);
-    print_section("16-bit Host-State Fields", 0xc00, 0xc0c, 2);
-    print_section("64-bit Control Fields", 0x2000, 0x2013, 1);
-    print_section("64-bit Guest-State Fields", 0x2800, 0x2803, 1);
-    print_section("32-bit Control Fields", 0x4000, 0x401c, 2);
-    print_section("32-bit RO Data Fields", 0x4400, 0x440e, 2);
-    print_section("32-bit Guest-State Fields", 0x4800, 0x482a, 2);
-    print_section("32-bit Host-State Fields", 0x4c00, 0x4c00, 2);
-    print_section("Natural 64-bit Control Fields", 0x6000, 0x600e, 2);
-    print_section("64-bit RO Data Fields", 0x6400, 0x640A, 2);
-    print_section("Natural 64-bit Guest-State Fields", 0x6800, 0x6826, 2);
-    print_section("Natural 64-bit Host-State Fields", 0x6c00, 0x6c16, 2);
+    unsigned long long x;
+
+    printk("*** Guest State ***\n");
+    printk("CR0: actual=0x%016llx, shadow=0x%016llx, gh_mask=%016llx\n",
+           (unsigned long long)vmr(GUEST_CR0),
+           (unsigned long long)vmr(CR0_READ_SHADOW), 
+           (unsigned long long)vmr(CR0_GUEST_HOST_MASK));
+    printk("CR4: actual=0x%016llx, shadow=0x%016llx, gh_mask=%016llx\n",
+           (unsigned long long)vmr(GUEST_CR4),
+           (unsigned long long)vmr(CR4_READ_SHADOW), 
+           (unsigned long long)vmr(CR4_GUEST_HOST_MASK));
+    printk("CR3: actual=0x%016llx, target_count=%d\n",
+           (unsigned long long)vmr(GUEST_CR3),
+           (int)vmr(CR3_TARGET_COUNT));
+    printk("     target0=%016llx, target1=%016llx\n",
+           (unsigned long long)vmr(CR3_TARGET_VALUE0),
+           (unsigned long long)vmr(CR3_TARGET_VALUE1));
+    printk("     target2=%016llx, target3=%016llx\n",
+           (unsigned long long)vmr(CR3_TARGET_VALUE2),
+           (unsigned long long)vmr(CR3_TARGET_VALUE3));
+    printk("RSP = 0x%016llx  RIP = 0x%016llx\n", 
+           (unsigned long long)vmr(GUEST_RSP),
+           (unsigned long long)vmr(GUEST_RIP));
+    printk("RFLAGS=0x%016llx  DR7 = 0x%016llx\n", 
+           (unsigned long long)vmr(GUEST_DR7),
+           (unsigned long long)vmr(GUEST_RFLAGS));
+    printk("Sysenter RSP=%016llx CS:RIP=%04x:%016llx\n",
+           (unsigned long long)vmr(GUEST_SYSENTER_ESP),
+           (int)vmr(GUEST_SYSENTER_CS),
+           (unsigned long long)vmr(GUEST_SYSENTER_EIP));
+    vmx_dump_sel("CS", x86_seg_cs);
+    vmx_dump_sel("DS", x86_seg_ds);
+    vmx_dump_sel("SS", x86_seg_ss);
+    vmx_dump_sel("ES", x86_seg_es);
+    vmx_dump_sel("FS", x86_seg_fs);
+    vmx_dump_sel("GS", x86_seg_gs);
+    vmx_dump_sel("GDTR", x86_seg_gdtr);
+    vmx_dump_sel("LDTR", x86_seg_ldtr);
+    vmx_dump_sel("IDTR", x86_seg_idtr);
+    vmx_dump_sel("TR", x86_seg_tr);
+    x  = (unsigned long long)vmr(TSC_OFFSET_HIGH) << 32;
+    x |= (uint32_t)vmr(TSC_OFFSET);
+    printk("TSC Offset = %016llx\n", x);
+    x  = (unsigned long long)vmr(GUEST_IA32_DEBUGCTL) << 32;
+    x |= (uint32_t)vmr(GUEST_IA32_DEBUGCTL);
+    printk("DebugCtl=%016llx DebugExceptions=%016llx\n", x,
+           (unsigned long long)vmr(GUEST_PENDING_DBG_EXCEPTIONS));
+    printk("Interruptibility=%04x ActivityState=%04x\n",
+           (int)vmr(GUEST_INTERRUPTIBILITY_INFO),
+           (int)vmr(GUEST_ACTIVITY_STATE));
+
+    printk("*** Host State ***\n");
+    printk("RSP = 0x%016llx  RIP = 0x%016llx\n", 
+           (unsigned long long)vmr(HOST_RSP),
+           (unsigned long long)vmr(HOST_RIP));
+    printk("CS=%04x DS=%04x ES=%04x FS=%04x GS=%04x SS=%04x TR=%04x\n",
+           (uint16_t)vmr(HOST_CS_SELECTOR),
+           (uint16_t)vmr(HOST_DS_SELECTOR),
+           (uint16_t)vmr(HOST_ES_SELECTOR),
+           (uint16_t)vmr(HOST_FS_SELECTOR),
+           (uint16_t)vmr(HOST_GS_SELECTOR),
+           (uint16_t)vmr(HOST_SS_SELECTOR),
+           (uint16_t)vmr(HOST_TR_SELECTOR));
+    printk("FSBase=%016llx GSBase=%016llx TRBase=%016llx\n",
+           (unsigned long long)vmr(HOST_FS_BASE),
+           (unsigned long long)vmr(HOST_GS_BASE),
+           (unsigned long long)vmr(HOST_TR_BASE));
+    printk("GDTBase=%016llx IDTBase=%016llx\n",
+           (unsigned long long)vmr(HOST_GDTR_BASE),
+           (unsigned long long)vmr(HOST_IDTR_BASE));
+    printk("CR0=%016llx CR3=%016llx CR4=%016llx\n",
+           (unsigned long long)vmr(HOST_CR0),
+           (unsigned long long)vmr(HOST_CR3),
+           (unsigned long long)vmr(HOST_CR4));
+    printk("Sysenter RSP=%016llx CS:RIP=%04x:%016llx\n",
+           (unsigned long long)vmr(HOST_IA32_SYSENTER_ESP),
+           (int)vmr(HOST_IA32_SYSENTER_CS),
+           (unsigned long long)vmr(HOST_IA32_SYSENTER_EIP));
+
+    printk("*** Control State ***\n");
+    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
+           (uint32_t)vmr(PIN_BASED_VM_EXEC_CONTROL),
+           (uint32_t)vmr(CPU_BASED_VM_EXEC_CONTROL),
+           (uint32_t)vmr(SECONDARY_VM_EXEC_CONTROL));
+    printk("EntryControls=%08x ExitControls=%08x\n",
+           (uint32_t)vmr(VM_ENTRY_CONTROLS),
+           (uint32_t)vmr(VM_EXIT_CONTROLS));
+    printk("ExceptionBitmap=%08x\n",
+           (uint32_t)vmr(EXCEPTION_BITMAP));
+    printk("VMEntry: intr_info=%08x errcode=%08x ilen=%08x\n",
+           (uint32_t)vmr(VM_ENTRY_INTR_INFO_FIELD),
+           (uint32_t)vmr(VM_ENTRY_EXCEPTION_ERROR_CODE),
+           (uint32_t)vmr(VM_ENTRY_INSTRUCTION_LEN));
+    printk("VMExit: intr_info=%08x errcode=%08x ilen=%08x\n",
+           (uint32_t)vmr(VM_EXIT_INTR_INFO),
+           (uint32_t)vmr(VM_EXIT_INTR_ERROR_CODE),
+           (uint32_t)vmr(VM_ENTRY_INSTRUCTION_LEN));
+    printk("        reason=%08x qualification=%08x\n",
+           (uint32_t)vmr(VM_EXIT_REASON),
+           (uint32_t)vmr(EXIT_QUALIFICATION));
+    printk("IDTVectoring: info=%08x errcode=%08x\n",
+           (uint32_t)vmr(IDT_VECTORING_INFO_FIELD),
+           (uint32_t)vmr(IDT_VECTORING_ERROR_CODE));
+    printk("TPR Threshold = 0x%02x\n",
+           (uint32_t)vmr(TPR_THRESHOLD));
     printk("secondary exec control = 0x%08x\n",
-      (uint32_t)__vmread(SECONDARY_VM_EXEC_CONTROL));
+      (uint32_t)vmr(SECONDARY_VM_EXEC_CONTROL));
     printk("Guest PAT = 0x%08x%08x\n",
-           (uint32_t)__vmread(GUEST_PAT_HIGH), (uint32_t)__vmread(GUEST_PAT));
+           (uint32_t)vmr(GUEST_PAT_HIGH), (uint32_t)vmr(GUEST_PAT));
     printk("Host PAT = 0x%08x%08x\n",
-           (uint32_t)__vmread(HOST_PAT_HIGH), (uint32_t)__vmread(HOST_PAT));
+           (uint32_t)vmr(HOST_PAT_HIGH), (uint32_t)vmr(HOST_PAT));
     printk("EPT pointer = 0x%08x%08x\n",
-      (uint32_t)__vmread(EPT_POINTER_HIGH), (uint32_t)__vmread(EPT_POINTER));
+      (uint32_t)vmr(EPT_POINTER_HIGH), (uint32_t)vmr(EPT_POINTER));
     printk("virtual processor ID = 0x%04x\n",
-      (uint32_t)__vmread(VIRTUAL_PROCESSOR_ID));
-}
+      (uint32_t)vmr(VIRTUAL_PROCESSOR_ID));
 
+}
 
 static void vmcs_dump(unsigned char ch)
 {