aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/i387.c
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2006-04-26 20:01:37 +0100
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2006-04-26 20:01:37 +0100
commit60395c1ca994f0c1ce83ff7fe19362f76c3ff3d8 (patch)
tree674783cd773be5ce7bdb76555af61827cedb506f /xen/arch/x86/i387.c
parentb450304086140f01d838368dfedc7fe2eddb67ef (diff)
downloadxen-60395c1ca994f0c1ce83ff7fe19362f76c3ff3d8.tar.gz
xen-60395c1ca994f0c1ce83ff7fe19362f76c3ff3d8.tar.bz2
xen-60395c1ca994f0c1ce83ff7fe19362f76c3ff3d8.zip
This patch addresses CVE-2006-1056 (information leak from
fxsave/fxrstor on AMD CPUs) and also adjusts 64-bit handling so that full 64-bit RIP/RDP values get saved/restored. More fine-grained handling may be needed if 32-bit processes are expected to properly see their selectors (native Linux doesn't currently do that either, but there is a patch to adjust it there). Original patch: Jan Beulich (based on Linux original by Andi Kleen) Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/arch/x86/i387.c')
-rw-r--r--xen/arch/x86/i387.c60
1 files changed, 55 insertions, 5 deletions
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
index c8abc8aba7..d97ca4713c 100644
--- a/xen/arch/x86/i387.c
+++ b/xen/arch/x86/i387.c
@@ -26,19 +26,54 @@ void init_fpu(void)
void save_init_fpu(struct vcpu *v)
{
unsigned long cr0 = read_cr0();
+ char *fpu_ctxt = v->arch.guest_context.fpu_ctxt.x;
/* This can happen, if a paravirtualised guest OS has set its CR0.TS. */
if ( cr0 & X86_CR0_TS )
clts();
if ( cpu_has_fxsr )
+ {
+#ifdef __i386__
__asm__ __volatile__ (
- "fxsave %0 ; fnclex"
- : "=m" (v->arch.guest_context.fpu_ctxt) );
+ "fxsave %0"
+ : "=m" (*fpu_ctxt) );
+#else /* __x86_64__ */
+ /*
+ * The only way to force fxsaveq on a wide range of gas versions. On
+ * older versions the rex64 prefix works only if we force an addressing
+ * mode that doesn't require extended registers.
+ */
+ __asm__ __volatile__ (
+ "rex64/fxsave (%1)"
+ : "=m" (*fpu_ctxt) : "cdaSDb" (fpu_ctxt) );
+#endif
+
+ /* Clear exception flags if FSW.ES is set. */
+ if ( unlikely(fpu_ctxt[2] & 0x80) )
+ __asm__ __volatile__ ("fnclex");
+
+ /*
+ * AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
+ * is pending. Clear the x87 state here by setting it to fixed
+ * values. The hypervisor data segment can be sometimes 0 and
+ * sometimes new user value. Both should be ok. Use the FPU saved
+ * data block as a safe address because it should be in L1.
+ */
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
+ {
+ __asm__ __volatile__ (
+ "emms\n\t" /* clear stack tags */
+ "fildl %0" /* load to clear state */
+ : : "m" (*fpu_ctxt) );
+ }
+ }
else
+ {
__asm__ __volatile__ (
"fnsave %0 ; fwait"
- : "=m" (v->arch.guest_context.fpu_ctxt) );
+ : "=m" (*fpu_ctxt) );
+ }
clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
write_cr0(cr0|X86_CR0_TS);
@@ -46,14 +81,22 @@ void save_init_fpu(struct vcpu *v)
void restore_fpu(struct vcpu *v)
{
+ char *fpu_ctxt = v->arch.guest_context.fpu_ctxt.x;
+
/*
* FXRSTOR can fault if passed a corrupted data block. We handle this
* possibility, which may occur if the block was passed to us by control
* tools, by silently clearing the block.
*/
if ( cpu_has_fxsr )
+ {
__asm__ __volatile__ (
+#ifdef __i386__
"1: fxrstor %0 \n"
+#else /* __x86_64__ */
+ /* See above for why the operands/constraints are this way. */
+ "1: rex64/fxrstor (%2) \n"
+#endif
".section .fixup,\"ax\" \n"
"2: push %%"__OP"ax \n"
" push %%"__OP"cx \n"
@@ -72,12 +115,19 @@ void restore_fpu(struct vcpu *v)
" "__FIXUP_WORD" 1b,2b \n"
".previous \n"
:
- : "m" (v->arch.guest_context.fpu_ctxt),
- "i" (sizeof(v->arch.guest_context.fpu_ctxt)/4) );
+ : "m" (*fpu_ctxt),
+ "i" (sizeof(v->arch.guest_context.fpu_ctxt)/4)
+#ifdef __x86_64__
+ ,"cdaSDb" (fpu_ctxt)
+#endif
+ );
+ }
else
+ {
__asm__ __volatile__ (
"frstor %0"
: : "m" (v->arch.guest_context.fpu_ctxt) );
+ }
}
/*