
From: "Andi Kleen" <ak@suse.de>

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 <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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;
+			}
 		}
 	}
 
_
