From: "Andi Kleen" Found by Bodo Stroesser. Description from Bodo: >> On i386, if a signal handler is started, the kernel saves the fpu-state of the interrupted routine in the sigcontext on the stack. Calling unlazy_fpu() and setting current->used_math=0, the kernel supplies the signal-handler with a cleared virtual fpu. On sigreturn(), the old fpu-state of the interrupted routine is restored. If a process never used the fpu, it virtually has a cleared fpu. If such a process is interrupted by a signal handler, no fpu-context is saved and sigcontext->fpstate is set to NULL. Assume, that the signal handler uses the fpu. Then, AFAICS, on sigreturn current->used_math will be 1. Since sigcontext->fpstate still is NULL, restore_sigcontext() doesn't call restore_i387(). Thus, no clear_fpu() is done, current->used_math is not reset. Now, the interrupted processes fpu no longer is cleared! << Fix by AK. Just clear the FPU again when this happens. patch for i386 and x86-64. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/signal.c | 6 ++++++ 25-akpm/arch/x86_64/ia32/ia32_signal.c | 6 ++++++ 25-akpm/arch/x86_64/kernel/signal.c | 6 ++++++ 3 files changed, 18 insertions(+) diff -puN arch/i386/kernel/signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 arch/i386/kernel/signal.c --- 25/arch/i386/kernel/signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 2005-01-09 23:01:41.233114720 -0800 +++ 25-akpm/arch/i386/kernel/signal.c 2005-01-09 23:01:41.239113808 -0800 @@ -190,6 +190,12 @@ restore_sigcontext(struct pt_regs *regs, if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); + } else { + struct task_struct *me = current; + if (me->used_math) { + clear_fpu(me); + me->used_math = 0; + } } } diff -puN arch/x86_64/ia32/ia32_signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 arch/x86_64/ia32/ia32_signal.c --- 25/arch/x86_64/ia32/ia32_signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 2005-01-09 23:01:41.234114568 -0800 +++ 25-akpm/arch/x86_64/ia32/ia32_signal.c 2005-01-09 23:01:41.240113656 -0800 @@ -261,6 +261,12 @@ ia32_restore_sigcontext(struct pt_regs * if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387_ia32(current, buf, 0); + } else { + struct task_struct *me = current; + if (me->used_math) { + clear_fpu(me); + me->used_math = 0; + } } } diff -puN arch/x86_64/kernel/signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 arch/x86_64/kernel/signal.c --- 25/arch/x86_64/kernel/signal.c~x86_64-fix-signal-fpu-leak-on-i386-and-x86-64 2005-01-09 23:01:41.236114264 -0800 +++ 25-akpm/arch/x86_64/kernel/signal.c 2005-01-09 23:01:41.240113656 -0800 @@ -125,6 +125,12 @@ restore_sigcontext(struct pt_regs *regs, if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); + } else { + struct task_struct *me = current; + if (me->used_math) { + clear_fpu(me); + me->used_math = 0; + } } } _