]> xenbits.xensource.com Git - people/iwj/xen.git/commitdiff
x86: don't latch wrong (stale) GS base addresses
authorJan Beulich <JBeulich@suse.com>
Thu, 26 Oct 2017 07:57:04 +0000 (01:57 -0600)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 27 Oct 2017 12:49:10 +0000 (13:49 +0100)
load_segments() writes selector registers before doing any of the base
address updates. Any of these selector loads can cause a page fault in
case it references the LDT, and the LDT page accessed was only recently
installed. Therefore the call tree map_ldt_shadow_page() ->
guest_get_eff_kern_l1e() -> toggle_guest_mode() would in such a case
wrongly latch the outgoing vCPU's GS.base into the incoming vCPU's
recorded state.

Split page table toggling from GS handling - neither
guest_get_eff_kern_l1e() nor guest_io_okay() need more than the page
tables being the kernel ones for the memory access they want to do.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-acked-by: Julien Grall <julien.grall@linaro.org>
xen/arch/x86/pv/domain.c
xen/arch/x86/pv/emul-priv-op.c
xen/arch/x86/pv/mm.c
xen/include/asm-x86/domain.h

index 2fb19960ba6e046fd839dca12c468c22d61790b7..2234128bb33ea4f2ddb3d5a93aabb4a9baa9c22f 100644 (file)
@@ -233,8 +233,17 @@ void toggle_guest_mode(struct vcpu *v)
         else
             v->arch.pv_vcpu.gs_base_user = __rdgsbase();
     }
-    v->arch.flags ^= TF_kernel_mode;
     asm volatile ( "swapgs" );
+
+    toggle_guest_pt(v);
+}
+
+void toggle_guest_pt(struct vcpu *v)
+{
+    if ( is_pv_32bit_vcpu(v) )
+        return;
+
+    v->arch.flags ^= TF_kernel_mode;
     update_cr3(v);
     /* Don't flush user global mappings from the TLB. Don't tick TLB clock. */
     asm volatile ( "mov %0, %%cr3" : : "r" (v->arch.cr3) : "memory" );
index dd90713acfd93f02d333006e7d42d292a807d894..2f9264548ab82be6f837dd12fba9c89ef603ff01 100644 (file)
@@ -137,7 +137,7 @@ static bool guest_io_okay(unsigned int port, unsigned int bytes,
          * read as 0xff (no access allowed).
          */
         if ( user_mode )
-            toggle_guest_mode(v);
+            toggle_guest_pt(v);
 
         switch ( __copy_from_guest_offset(x.bytes, v->arch.pv_vcpu.iobmp,
                                           port>>3, 2) )
@@ -150,7 +150,7 @@ static bool guest_io_okay(unsigned int port, unsigned int bytes,
         }
 
         if ( user_mode )
-            toggle_guest_mode(v);
+            toggle_guest_pt(v);
 
         if ( (x.mask & (((1 << bytes) - 1) << (port & 7))) == 0 )
             return true;
index 6890e80efd4275a4d638f72bb456fe35aafdee3c..8d7a4fd85f8f024c31d1ef9c0ee55485297e9814 100644 (file)
@@ -72,12 +72,12 @@ static l1_pgentry_t guest_get_eff_kern_l1e(unsigned long linear)
     l1_pgentry_t l1e;
 
     if ( user_mode )
-        toggle_guest_mode(curr);
+        toggle_guest_pt(curr);
 
     l1e = guest_get_eff_l1e(linear);
 
     if ( user_mode )
-        toggle_guest_mode(curr);
+        toggle_guest_pt(curr);
 
     return l1e;
 }
index 4d0b77dc28f1368a7a0594f4ee330f9269e82ce1..f69911918eec38c558e60442189c281550d1e53c 100644 (file)
@@ -76,6 +76,8 @@ void mapcache_override_current(struct vcpu *);
 
 /* x86/64: toggle guest between kernel and user modes. */
 void toggle_guest_mode(struct vcpu *);
+/* x86/64: toggle guest page tables between kernel and user modes. */
+void toggle_guest_pt(struct vcpu *);
 
 /*
  * Initialise a hypercall-transfer page. The given pointer must be mapped