VMX: flush cache when vmentry back to UC guest
authorLiu Jinsong <jinsong.liu@intel.com>
Wed, 6 Nov 2013 09:13:20 +0000 (10:13 +0100)
committerJan Beulich <jbeulich@suse.com>
Wed, 6 Nov 2013 09:13:20 +0000 (10:13 +0100)
This patch flush cache when vmentry back to UC guest, to prevent
cache polluted by hypervisor access guest memory during UC mode.

The elegant way to do this is, simply add wbinvd just before vmentry.
However, currently wbinvd before vmentry will mysteriously trigger
lapic timer interrupt storm, hung booting stage for 10s ~ 60s. We still
didn't dig out the root cause of interrupt storm, so currently this
patch add flag indicating hypervisor access UC guest memory to prevent
interrupt storm -- though it still leaves aspects un-addressed, i.e.
speculative reads, and multi-vCPU issues, etc.

Whenever the interrupt storm got root caused and fixed, the protection
flag can be removed -- that would be final clean and elegant approach
dealing with cache flushing before vmentry.

This is CVE-2013-2212 / XSA-60.

Suggested-by: Jan Beulich <jbeulich@suse.com>
Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Liu Jinsong <jinsong.liu@intel.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Jun Nakajima <jun.nakajima@intel.com>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/vcpu.h

index 73d1cf0291a465ccdbdc09bbb82adaa7302359f5..36699b861e4ef1b599ca265627716954c82d34c1 100644 (file)
@@ -2477,6 +2477,9 @@ static enum hvm_copy_result __hvm_copy(
         return HVMCOPY_unhandleable;
 #endif
 
+    if ( unlikely(curr->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) )
+        curr->arch.hvm_vcpu.hypervisor_access_uc_hvm_memory = 1;
+
     while ( todo > 0 )
     {
         count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo);
@@ -2588,6 +2591,9 @@ static enum hvm_copy_result __hvm_clear(paddr_t addr, int size)
         return HVMCOPY_unhandleable;
 #endif
 
+    if ( unlikely(curr->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) )
+        curr->arch.hvm_vcpu.hypervisor_access_uc_hvm_memory = 1;
+
     while ( todo > 0 )
     {
         count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo);
index 75be62eec079e76555df96c20c73da5d4d172253..a0ad37ac3dae078eaf27901dbb649aa2957804cc 100644 (file)
@@ -2974,6 +2974,13 @@ void vmx_vmenter_helper(const struct cpu_user_regs *regs)
     struct hvm_vcpu_asid *p_asid;
     bool_t need_flush;
 
+    /* In case hypervisor access hvm memory when guest uc mode */
+    if ( unlikely(curr->arch.hvm_vcpu.hypervisor_access_uc_hvm_memory) )
+    {
+        curr->arch.hvm_vcpu.hypervisor_access_uc_hvm_memory = 0;
+        wbinvd();
+    }
+
     if ( !cpu_has_vmx_vpid )
         goto out;
     if ( nestedhvm_vcpu_in_guestmode(curr) )
index 8fa5452ab18348f7e1be93e749a25944959df5c3..a309389187f2133bb4e90e9086d05b5c50f0032f 100644 (file)
@@ -167,6 +167,7 @@ struct hvm_vcpu {
 
     /* Which cache mode is this VCPU in (CR0:CD/NW)? */
     u8                  cache_mode;
+    bool_t              hypervisor_access_uc_hvm_memory;
 
     struct hvm_vcpu_io  hvm_io;