From: Greg Kroah-Hartman Date: Wed, 19 Apr 2006 14:59:18 +0000 (-0700) Subject: 2.6.16.9 release X-Git-Tag: v2.6.16.9^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b6974538e4576509a592db99ad5135fe0be1db93;p=thirdparty%2Fkernel%2Fstable-queue.git 2.6.16.9 release --- 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 index 00000000000..f3075895b51 --- /dev/null +++ b/2.6.16.9/i386-x86-64-fix-x87-information-leak-between-processes.patch @@ -0,0 +1,217 @@ +From ak@suse.de Tue Apr 18 22:18:03 2006 +From: Andi Kleen +To: Greg KH +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include ++#include + #include + #include + #include +@@ -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 index 00000000000..52c4d41ff18 --- /dev/null +++ b/2.6.16.9/series @@ -0,0 +1 @@ +i386-x86-64-fix-x87-information-leak-between-processes.patch