]> xenbits.xensource.com Git - xen.git/commitdiff
x86: avoid leaking PKRU and BND* between vCPU-s
authorJan Beulich <jbeulich@suse.com>
Tue, 20 Jun 2017 14:10:04 +0000 (16:10 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 20 Jun 2017 14:10:04 +0000 (16:10 +0200)
PKRU is explicitly "XSAVE-managed but not XSAVE-enabled", so guests
might access the register (via {RD,WR}PKRU) without setting XCR0.PKRU.
Force context switching as well as migrating the register as soon as
CR4.PKE is being set the first time.

For MPX (BND<n>, BNDCFGU, and BNDSTATUS) the situation is less clear,
and the SDM has not entirely consistent information for that case.
While experimentally the instructions don't change register state as
long as the two XCR0 bits aren't both 1, be on the safe side and enable
both if BNDCFGS.EN is being set the first time.

This is XSA-220.

Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: de20bb6c4f65c4161e0931402613f9ffac86302d
master date: 2017-06-20 14:36:51 +0200

xen/arch/x86/hvm/hvm.c

index 6c30bec652c26baacf8388f57dca8b35d4281078..53b99c36e614c6079aaf68a4e4f3c7658d34aac1 100644 (file)
@@ -311,10 +311,39 @@ int hvm_set_guest_pat(struct vcpu *v, u64 guest_pat)
 
 bool hvm_set_guest_bndcfgs(struct vcpu *v, u64 val)
 {
-    return hvm_funcs.set_guest_bndcfgs &&
-           is_canonical_address(val) &&
-           !(val & IA32_BNDCFGS_RESERVED) &&
-           hvm_funcs.set_guest_bndcfgs(v, val);
+    if ( !hvm_funcs.set_guest_bndcfgs ||
+         !is_canonical_address(val) ||
+         (val & IA32_BNDCFGS_RESERVED) )
+        return false;
+
+    /*
+     * While MPX instructions are supposed to be gated on XCR0.BND*, let's
+     * nevertheless force the relevant XCR0 bits on when the feature is being
+     * enabled in BNDCFGS.
+     */
+    if ( (val & IA32_BNDCFGS_ENABLE) &&
+         !(v->arch.xcr0_accum & (XSTATE_BNDREGS | XSTATE_BNDCSR)) )
+    {
+        uint64_t xcr0 = get_xcr0();
+        int rc;
+
+        if ( v != current )
+            return false;
+
+        rc = handle_xsetbv(XCR_XFEATURE_ENABLED_MASK,
+                           xcr0 | XSTATE_BNDREGS | XSTATE_BNDCSR);
+
+        if ( rc )
+        {
+            HVM_DBG_LOG(DBG_LEVEL_1, "Failed to force XCR0.BND*: %d", rc);
+            return false;
+        }
+
+        if ( handle_xsetbv(XCR_XFEATURE_ENABLED_MASK, xcr0) )
+            /* nothing, best effort only */;
+    }
+
+    return hvm_funcs.set_guest_bndcfgs(v, val);
 }
 
 /*
@@ -2477,6 +2506,27 @@ int hvm_set_cr4(unsigned long value, bool_t may_defer)
             paging_update_paging_modes(v);
     }
 
+    /*
+     * {RD,WR}PKRU are not gated on XCR0.PKRU and hence an oddly behaving
+     * guest may enable the feature in CR4 without enabling it in XCR0. We
+     * need to context switch / migrate PKRU nevertheless.
+     */
+    if ( (value & X86_CR4_PKE) && !(v->arch.xcr0_accum & XSTATE_PKRU) )
+    {
+        int rc = handle_xsetbv(XCR_XFEATURE_ENABLED_MASK,
+                               get_xcr0() | XSTATE_PKRU);
+
+        if ( rc )
+        {
+            HVM_DBG_LOG(DBG_LEVEL_1, "Failed to force XCR0.PKRU: %d", rc);
+            goto gpf;
+        }
+
+        if ( handle_xsetbv(XCR_XFEATURE_ENABLED_MASK,
+                           get_xcr0() & ~XSTATE_PKRU) )
+            /* nothing, best effort only */;
+    }
+
     return X86EMUL_OKAY;
 
  gpf: