File 59f32b46-x86-dont-latch-wrong-GS-base-addresses.patch of Package xen.8005

References: bsc#1057493

# Commit a711f6f24a7157ae70d1cc32e61b98f23dc0c584
# Date 2017-10-27 13:49:10 +0100
# Author Jan Beulich <JBeulich@suse.com>
# Committer Andrew Cooper <andrew.cooper3@citrix.com>
x86: don't latch wrong (stale) GS base addresses

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>

--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1611,7 +1611,7 @@ static int guest_io_okay(
 {
     /* If in user mode, switch to kernel mode just to read I/O bitmap. */
     int user_mode = !(v->arch.flags & TF_kernel_mode);
-#define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)
+#define TOGGLE_MODE() if ( user_mode ) toggle_guest_pt(v)
 
     if ( !vm86_mode(regs) &&
          (v->arch.pv_vcpu.iopl >= (guest_kernel_mode(v, regs) ? 1 : 3)) )
--- a/xen/arch/x86/x86_64/traps.c
+++ b/xen/arch/x86/x86_64/traps.c
@@ -278,8 +278,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);
 #ifdef USER_MAPPINGS_ARE_GLOBAL
     /* Don't flush user global mappings from the TLB. Don't tick TLB clock. */
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -75,6 +75,8 @@ void mapcache_override_current(struct vc
 
 /* 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
--- a/xen/include/asm-x86/paging.h
+++ b/xen/include/asm-x86/paging.h
@@ -411,7 +411,7 @@ static inline void
 guest_get_eff_kern_l1e(struct vcpu *v, unsigned long addr, void *eff_l1e)
 {
     int user_mode = !(v->arch.flags & TF_kernel_mode);
-#define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)
+#define TOGGLE_MODE() if ( user_mode ) toggle_guest_pt(v)
 
     TOGGLE_MODE();
     guest_get_eff_l1e(v, addr, eff_l1e);
openSUSE Build Service is sponsored by