aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-01-11 01:51:31 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-11 01:51:31 -0800
commita3e64936b929189eaebc10466fa6549e532da97c (patch)
tree5558fa00b4168b4a1aa8ce1381a46582d24135e8 /arch
parent7fb0f979367c4a4beda64b10b9ef378054ec4442 (diff)
downloadhistory-a3e64936b929189eaebc10466fa6549e532da97c.tar.gz
[PATCH] x86_64: Fix signal FPU leak on i386 and x86-64
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> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/signal.c6
-rw-r--r--arch/x86_64/ia32/ia32_signal.c6
-rw-r--r--arch/x86_64/kernel/signal.c6
3 files changed, 18 insertions, 0 deletions
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 51c4bfc53c938e..f98146004f5e1d 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -190,6 +190,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax
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 --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 16854c4faa64c7..7b78206dd90bc8 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -261,6 +261,12 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc,
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 --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index df01c50b717770..ad3b240cdd9c77 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -125,6 +125,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned
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;
+ }
}
}