[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.6] x86/fpu: improve check for XSAVE* not writing FIP/FDP fields



commit 16ca37fadf4fe13a3987dfec247083bde44a8444
Author:     David Vrabel <david.vrabel@xxxxxxxxxx>
AuthorDate: Tue Mar 29 15:15:32 2016 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Mar 29 15:15:32 2016 +0200

    x86/fpu: improve check for XSAVE* not writing FIP/FDP fields
    
    The hardware may not write the FIP/FDP fields with a XSAVE*
    instruction.  e.g., with XSAVEOPT/XSAVES if the state hasn't changed
    or on AMD CPUs when a floating point exception is not pending.  We
    need to identify this case so we can correctly apply the check for
    whether to save/restore FCS/FDS.
    
    By poisoning FIP in the saved state we can check if the hardware
    writes to this field.  The poison value is both: a) non-canonical; and
    b) random with a vanishingly small probability of matching a value
    written by the hardware (1 / (2^63) = 10^-19).
    
    The poison value is fixed and thus knowable by a guest (or guest
    userspace).  This could allow the guest to cause Xen to incorrectly
    detect that the field has not been written.  But: a) this requires the
    FIP register to be a full 64 bits internally which is not the case for
    all current AMD and Intel CPUs; and b) this only allows the guest (or
    a guest userspace process) to corrupt its own state (i.e., it cannot
    affect the state of another guest or another user space process).
    
    This results in smaller code with fewer branches and is more
    understandable.
    
    Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
    
    Intel confirmed that 64-bit {F,}XRSTOR sign-extend FIP from bit 47.
    While leaving the description above intact, modify the code comment
    accordingly.
    
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: e869abd77aa32fb0a5212d34ae954e4dbcb8f7a5
    master date: 2016-03-18 09:49:01 +0100
---
 xen/arch/x86/xstate.c | 47 +++++++++++++++++++----------------------------
 1 file changed, 19 insertions(+), 28 deletions(-)

diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index a6ca814..59644c6 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -96,45 +96,36 @@ void xsave(struct vcpu *v, uint64_t mask)
     }
     else
     {
-        typeof(ptr->fpu_sse.fip.sel) fcs = ptr->fpu_sse.fip.sel;
-        typeof(ptr->fpu_sse.fdp.sel) fds = ptr->fpu_sse.fdp.sel;
+        /*
+         * FIP/FDP may not be written in some cases (e.g., if XSAVEOPT/XSAVES
+         * is used, or on AMD CPUs if an exception isn't pending).
+         *
+         * To tell if the hardware writes these fields, poison the FIP field.
+         * The poison is
+         * a) non-canonical
+         * b) non-zero for the reserved part of a 32-bit FCS:FIP
+         * c) random with a vanishingly small probability to match a value the
+         *    hardware may write (1e-19) even if it did not canonicalize the
+         *    64-bit FIP or zero-extend the 16-bit FCS.
+         */
+        uint64_t orig_fip = ptr->fpu_sse.fip.addr;
+        const uint64_t bad_fip = 0x6a3f5c4b13a533f6;
+
+        ptr->fpu_sse.fip.addr = bad_fip;
 
         if ( cpu_has_xsaveopt )
-        {
-            /*
-             * xsaveopt may not write the FPU portion even when the respective
-             * mask bit is set. For the check further down to work we hence
-             * need to put the save image back into the state that it was in
-             * right after the previous xsaveopt.
-             */
-            if ( ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 4 ||
-                 ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 2 )
-            {
-                ptr->fpu_sse.fip.sel = 0;
-                ptr->fpu_sse.fdp.sel = 0;
-            }
             asm volatile ( ".byte 0x48,0x0f,0xae,0x37"
                            : "=m" (*ptr)
                            : "a" (lmask), "d" (hmask), "D" (ptr) );
-        }
         else
             asm volatile ( ".byte 0x48,0x0f,0xae,0x27"
                            : "=m" (*ptr)
                            : "a" (lmask), "d" (hmask), "D" (ptr) );
 
-        if ( !(mask & ptr->xsave_hdr.xstate_bv & XSTATE_FP) ||
-             /*
-              * AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
-              * is pending.
-              */
-             (!(ptr->fpu_sse.fsw & 0x0080) &&
-              boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
+        /* FIP/FDP not updated? Restore the old FIP value. */
+        if ( ptr->fpu_sse.fip.addr == bad_fip )
         {
-            if ( cpu_has_xsaveopt )
-            {
-                ptr->fpu_sse.fip.sel = fcs;
-                ptr->fpu_sse.fdp.sel = fds;
-            }
+            ptr->fpu_sse.fip.addr = orig_fip;
             return;
         }
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.6

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.