diff options
author | Andi Kleen <ak@suse.de> | 2005-01-11 01:51:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-11 01:51:31 -0800 |
commit | a3e64936b929189eaebc10466fa6549e532da97c (patch) | |
tree | 5558fa00b4168b4a1aa8ce1381a46582d24135e8 /arch | |
parent | 7fb0f979367c4a4beda64b10b9ef378054ec4442 (diff) | |
download | history-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.c | 6 | ||||
-rw-r--r-- | arch/x86_64/ia32/ia32_signal.c | 6 | ||||
-rw-r--r-- | arch/x86_64/kernel/signal.c | 6 |
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; + } } } |