Commit a3e64936 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[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: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7fb0f979
...@@ -190,6 +190,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax ...@@ -190,6 +190,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax
if (verify_area(VERIFY_READ, buf, sizeof(*buf))) if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe; goto badframe;
err |= restore_i387(buf); err |= restore_i387(buf);
} else {
struct task_struct *me = current;
if (me->used_math) {
clear_fpu(me);
me->used_math = 0;
}
} }
} }
......
...@@ -261,6 +261,12 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc, ...@@ -261,6 +261,12 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc,
if (verify_area(VERIFY_READ, buf, sizeof(*buf))) if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe; goto badframe;
err |= restore_i387_ia32(current, buf, 0); err |= restore_i387_ia32(current, buf, 0);
} else {
struct task_struct *me = current;
if (me->used_math) {
clear_fpu(me);
me->used_math = 0;
}
} }
} }
......
...@@ -125,6 +125,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned ...@@ -125,6 +125,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned
if (verify_area(VERIFY_READ, buf, sizeof(*buf))) if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe; goto badframe;
err |= restore_i387(buf); err |= restore_i387(buf);
} else {
struct task_struct *me = current;
if (me->used_math) {
clear_fpu(me);
me->used_math = 0;
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment