From: David Vrabel <david.vrabel@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
David Vrabel <david.vrabel@citrix.com>,
Jan Beulich <jbeulich@suse.com>
Subject: [PATCHv3 1/3] x86/fpu: improve check for XSAVE* not writing FIP/FDP fields
Date: Thu, 25 Feb 2016 10:58:02 +0000 [thread overview]
Message-ID: <1456397884-661-2-git-send-email-david.vrabel@citrix.com> (raw)
In-Reply-To: <1456397884-661-1-git-send-email-david.vrabel@citrix.com>
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@citrix.com>
---
v3:
- Use a random (and still non-canonical) value to poison FIP.
---
xen/arch/x86/xstate.c | 47 +++++++++++++++++------------------------------
1 file changed, 17 insertions(+), 30 deletions(-)
diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index 4f2fb8e..6a917f8 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -263,41 +263,28 @@ void xsave(struct vcpu *v, uint64_t mask)
if ( word_size <= 0 || !is_pv_32bit_vcpu(v) )
{
- typeof(ptr->fpu_sse.fip.sel) fcs = ptr->fpu_sse.fip.sel;
- typeof(ptr->fpu_sse.fdp.sel) fds = ptr->fpu_sse.fdp.sel;
+ uint64_t orig_fip;
+ static const uint64_t bad_fip = 0x6a3f5c4b13a533f6;
- if ( cpu_has_xsaveopt || cpu_has_xsaves )
- {
- /*
- * XSAVEOPT/XSAVES 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 ( word_size > 0 &&
- (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;
- }
- }
+ /*
+ * 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 both a) non-canonical; and b) random
+ * with a vanishingly small probability to match a value the
+ * hardware may write (1e-19).
+ */
+ orig_fip = ptr->fpu_sse.fip.addr;
+ ptr->fpu_sse.fip.addr = bad_fip;
XSAVE("0x48,");
- 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 || cpu_has_xsaves) && word_size > 0 )
- {
- ptr->fpu_sse.fip.sel = fcs;
- ptr->fpu_sse.fdp.sel = fds;
- }
+ ptr->fpu_sse.fip.addr = orig_fip;
return;
}
--
2.1.4
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2016-02-25 10:58 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-25 10:58 [PATCHv3 0/3] x86: workaround inability to fully restore FPU state David Vrabel
2016-02-25 10:58 ` David Vrabel [this message]
2016-02-25 11:32 ` [PATCHv3 1/3] x86/fpu: improve check for XSAVE* not writing FIP/FDP fields Jan Beulich
2016-02-25 12:18 ` David Vrabel
2016-02-25 12:27 ` Jan Beulich
2016-02-25 12:49 ` David Vrabel
2016-02-25 13:16 ` Andrew Cooper
2016-02-25 14:27 ` Jan Beulich
2016-02-25 15:07 ` Andrew Cooper
2016-02-25 15:09 ` David Vrabel
2016-03-01 6:27 ` Tian, Kevin
2016-03-01 9:31 ` Jan Beulich
2016-02-25 10:58 ` [PATCHv3 2/3] x86/fpu: Add a per-domain field to set the width of FIP/FDP David Vrabel
2016-02-25 11:24 ` Jan Beulich
2016-02-25 11:38 ` David Vrabel
2016-02-25 11:55 ` Jan Beulich
2016-02-25 10:58 ` [PATCHv3 3/3] x86/hvm: add HVM_PARAM_X87_FIP_WIDTH David Vrabel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1456397884-661-2-git-send-email-david.vrabel@citrix.com \
--to=david.vrabel@citrix.com \
--cc=andrew.cooper3@citrix.com \
--cc=jbeulich@suse.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).