]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
2.6.16.9 release v2.6.16.9
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 19 Apr 2006 14:59:18 +0000 (07:59 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 19 Apr 2006 14:59:18 +0000 (07:59 -0700)
2.6.16.9/i386-x86-64-fix-x87-information-leak-between-processes.patch [new file with mode: 0644]
2.6.16.9/series [new file with mode: 0644]

diff --git a/2.6.16.9/i386-x86-64-fix-x87-information-leak-between-processes.patch b/2.6.16.9/i386-x86-64-fix-x87-information-leak-between-processes.patch
new file mode 100644 (file)
index 0000000..f307589
--- /dev/null
@@ -0,0 +1,217 @@
+From ak@suse.de Tue Apr 18 22:18:03 2006
+From: Andi Kleen <ak@suse.de>
+To: Greg KH <greg@kroah.com>
+Subject: i386/x86-64: Fix x87 information leak between processes (CVE-2006-1056)
+Date: Wed, 19 Apr 2006 07:17:31 +0200
+Cc: vendor-sec@lst.de, security@kernel.org, richard.brunner@amd.com, jbeulich@novell.com
+Content-Disposition: inline
+Message-Id: <200604190717.31631.ak@suse.de>
+
+
+AMD K7/K8 CPUs only save/restore the FOP/FIP/FDP x87 registers in FXSAVE
+when an exception is pending.  This means the value leak through context
+switches and allow processes to observe some x87 instruction state of
+other processes.
+
+This was actually documented by AMD, but nobody recognized it as being
+different from Intel before.
+
+The fix first adds an optimization: instead of unconditionally calling
+FNCLEX after each FXSAVE test if ES is pending and skip it when not
+needed. Then do a x87 load from a kernel variable to clear FOP/FIP/FDP.
+
+This means other processes always will only see a constant value defined
+by the kernel in their FP state.
+
+I took some pain to make sure to chose a variable that's already in L1
+during context switch to make the overhead of this low.
+
+Also alternative() is used to patch away the new code on CPUs who don't
+need it.
+
+Patch for both i386/x86-64.
+
+The problem was discovered originally by Jan Beulich. Richard Brunner
+provided the basic code for the workarounds, with contribution from Jan.
+
+This is CVE-2006-1056
+
+Cc: richard.brunner@amd.com
+Cc: jbeulich@novell.com
+Signed-off-by: Andi Kleen <ak@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/i386/kernel/cpu/amd.c      |    2 ++
+ arch/x86_64/kernel/process.c    |    8 ++++++--
+ arch/x86_64/kernel/setup.c      |    4 ++++
+ include/asm-i386/cpufeature.h   |    1 +
+ include/asm-i386/i387.h         |   30 ++++++++++++++++++++++++++----
+ include/asm-x86_64/cpufeature.h |    1 +
+ include/asm-x86_64/i387.h       |   20 +++++++++++++++++++-
+ 7 files changed, 59 insertions(+), 7 deletions(-)
+
+--- linux-2.6.16.8.orig/arch/i386/kernel/cpu/amd.c
++++ linux-2.6.16.8/arch/i386/kernel/cpu/amd.c
+@@ -207,6 +207,8 @@ static void __init init_amd(struct cpuin
+               set_bit(X86_FEATURE_K7, c->x86_capability); 
+               break;
+       }
++      if (c->x86 >= 6)
++              set_bit(X86_FEATURE_FXSAVE_LEAK, c->x86_capability);
+       display_cacheinfo(c);
+--- linux-2.6.16.8.orig/arch/x86_64/kernel/process.c
++++ linux-2.6.16.8/arch/x86_64/kernel/process.c
+@@ -527,8 +527,6 @@ __switch_to(struct task_struct *prev_p, 
+       int cpu = smp_processor_id();  
+       struct tss_struct *tss = &per_cpu(init_tss, cpu);
+-      unlazy_fpu(prev_p);
+-
+       /*
+        * Reload esp0, LDT and the page table pointer:
+        */
+@@ -591,6 +589,12 @@ __switch_to(struct task_struct *prev_p, 
+       prev->userrsp = read_pda(oldrsp); 
+       write_pda(oldrsp, next->userrsp); 
+       write_pda(pcurrent, next_p); 
++
++      /* This must be here to ensure both math_state_restore() and
++         kernel_fpu_begin() work consistently.
++         And the AMD workaround requires it to be after DS reload. */
++      unlazy_fpu(prev_p);
++
+       write_pda(kernelstack,
+                 task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
+--- linux-2.6.16.8.orig/arch/x86_64/kernel/setup.c
++++ linux-2.6.16.8/arch/x86_64/kernel/setup.c
+@@ -909,6 +909,10 @@ static int __init init_amd(struct cpuinf
+       if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
+               set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
++      /* Enable workaround for FXSAVE leak */
++      if (c->x86 >= 6)
++              set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
++
+       r = get_model_name(c);
+       if (!r) { 
+               switch (c->x86) { 
+--- linux-2.6.16.8.orig/include/asm-i386/cpufeature.h
++++ linux-2.6.16.8/include/asm-i386/cpufeature.h
+@@ -70,6 +70,7 @@
+ #define X86_FEATURE_P3                (3*32+ 6) /* P3 */
+ #define X86_FEATURE_P4                (3*32+ 7) /* P4 */
+ #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
++#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
+ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+ #define X86_FEATURE_XMM3      (4*32+ 0) /* Streaming SIMD Extensions-3 */
+--- linux-2.6.16.8.orig/include/asm-i386/i387.h
++++ linux-2.6.16.8/include/asm-i386/i387.h
+@@ -13,6 +13,7 @@
+ #include <linux/sched.h>
+ #include <linux/init.h>
++#include <linux/kernel_stat.h>
+ #include <asm/processor.h>
+ #include <asm/sigcontext.h>
+ #include <asm/user.h>
+@@ -38,17 +39,38 @@ extern void init_fpu(struct task_struct 
+ extern void kernel_fpu_begin(void);
+ #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0)
++/* We need a safe address that is cheap to find and that is already
++   in L1 during context switch. The best choices are unfortunately
++   different for UP and SMP */
++#ifdef CONFIG_SMP
++#define safe_address (__per_cpu_offset[0])
++#else
++#define safe_address (kstat_cpu(0).cpustat.user)
++#endif
++
+ /*
+  * These must be called with preempt disabled
+  */
+ static inline void __save_init_fpu( struct task_struct *tsk )
+ {
++      /* Use more nops than strictly needed in case the compiler
++         varies code */
+       alternative_input(
+-              "fnsave %1 ; fwait ;" GENERIC_NOP2,
+-              "fxsave %1 ; fnclex",
++              "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
++              "fxsave %[fx]\n"
++              "bt $7,%[fsw] ; jc 1f ; fnclex\n1:",
+               X86_FEATURE_FXSR,
+-              "m" (tsk->thread.i387.fxsave)
+-              :"memory");
++              [fx] "m" (tsk->thread.i387.fxsave),
++              [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory");
++      /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
++         is pending.  Clear the x87 state here by setting it to fixed
++         values. __per_cpu_offset[0] is a random variable that should be in L1 */
++      alternative_input(
++              GENERIC_NOP8 GENERIC_NOP2,
++              "emms\n\t"              /* clear stack tags */
++              "fildl %[addr]",        /* set F?P to defined value */
++              X86_FEATURE_FXSAVE_LEAK,
++              [addr] "m" (safe_address));
+       task_thread_info(tsk)->status &= ~TS_USEDFPU;
+ }
+--- linux-2.6.16.8.orig/include/asm-x86_64/cpufeature.h
++++ linux-2.6.16.8/include/asm-x86_64/cpufeature.h
+@@ -64,6 +64,7 @@
+ #define X86_FEATURE_REP_GOOD  (3*32+ 4) /* rep microcode works well on this CPU */
+ #define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */
+ #define X86_FEATURE_SYNC_RDTSC  (3*32+6)  /* RDTSC syncs CPU core */
++#define X86_FEATURE_FXSAVE_LEAK (3*32+7)  /* FIP/FOP/FDP leaks through FXSAVE */
+ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+ #define X86_FEATURE_XMM3      (4*32+ 0) /* Streaming SIMD Extensions-3 */
+--- linux-2.6.16.8.orig/include/asm-x86_64/i387.h
++++ linux-2.6.16.8/include/asm-x86_64/i387.h
+@@ -72,6 +72,23 @@ extern int set_fpregs(struct task_struct
+ #define set_fpu_swd(t,val) ((t)->thread.i387.fxsave.swd = (val))
+ #define set_fpu_fxsr_twd(t,val) ((t)->thread.i387.fxsave.twd = (val))
++#define X87_FSW_ES (1 << 7)   /* Exception Summary */
++
++/* 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 kernel data segment can be sometimes 0 and sometimes
++   new user value. Both should be ok.
++   Use the PDA as safe address because it should be already in L1. */
++static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
++{
++      if (unlikely(fx->swd & X87_FSW_ES))
++               asm volatile("fnclex");
++      alternative_input(ASM_NOP8 ASM_NOP2,
++                   "    emms\n"               /* clear stack tags */
++                   "    fildl %%gs:0",        /* load to clear state */
++                   X86_FEATURE_FXSAVE_LEAK);
++}
++
+ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) 
+ { 
+       int err;
+@@ -119,6 +136,7 @@ static inline int save_i387_checking(str
+ #endif
+       if (unlikely(err))
+               __clear_user(fx, sizeof(struct i387_fxsave_struct));
++      /* No need to clear here because the caller clears USED_MATH */
+       return err;
+ } 
+@@ -149,7 +167,7 @@ static inline void __fxsave_clear(struct
+                               "i" (offsetof(__typeof__(*tsk),
+                                             thread.i387.fxsave)));
+ #endif
+-      __asm__ __volatile__("fnclex");
++      clear_fpu_state(&tsk->thread.i387.fxsave);
+ }
+ static inline void kernel_fpu_begin(void)
diff --git a/2.6.16.9/series b/2.6.16.9/series
new file mode 100644 (file)
index 0000000..52c4d41
--- /dev/null
@@ -0,0 +1 @@
+i386-x86-64-fix-x87-information-leak-between-processes.patch