>>>>> On Wed, 06 Oct 2004 10:19:20 +0900 (JST), Atsushi Nemoto
>>>>> <anemo@mba.ocn.ne.jp> said:
anemo> I found a potential problem in math emulation. The math-emu
anemo> uses put_user/get_user to fetch the instruction or to emulate
anemo> load/store fp-regs. The put_user/get_user can sleep then we
anemo> can lose fpu ownership on it. It it happened, subsequent
anemo> restore_fp will cause CpU exception which not allowed in
anemo> kernel.
And there are similar potential problem in setup/restore sigcontext.
save_fp_context/restore_fp_context might sleep on put_user/get_user.
This is a quick fix for 2.6 kernel. Another possible fix is rewriting
restore_fp_context/save_fp_context to copy to/from current
thread_struct and use them with restore_fp/save_fp. Is this better?
Any comment are welcome.
diff -up linux-mips/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- linux-mips/arch/mips/kernel/signal.c Wed Sep 22 13:27:59 2004
+++ linux/arch/mips/kernel/signal.c Thu Oct 7 14:47:23 2004
@@ -182,9 +182,14 @@ asmlinkage int restore_sigcontext(struct
err |= __get_user(current->used_math, &sc->sc_used_math);
if (current->used_math) {
+ /* make sure restore_fp_context not sleep */
+ struct sigcontext tmpsc;
+ err |= __copy_from_user(&tmpsc.sc_fpregs, &sc->sc_fpregs,
sizeof(tmpsc.sc_fpregs));
+ err |= __get_user(tmpsc.sc_fpc_csr, &sc->sc_fpc_csr);
+ err |= __get_user(tmpsc.sc_fpc_eir, &sc->sc_fpc_eir);
/* restore fpu context if we have used it before */
own_fpu();
- err |= restore_fp_context(sc);
+ err |= restore_fp_context(&tmpsc);
} else {
/* signal handler may have used FPU. Give it up. */
lose_fpu();
@@ -291,6 +296,7 @@ badframe:
inline int setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
int err = 0;
+ struct sigcontext tmpsc;
err |= __put_user(regs->cp0_epc, &sc->sc_pc);
err |= __put_user(regs->cp0_status, &sc->sc_status);
@@ -327,7 +333,12 @@ inline int setup_sigcontext(struct pt_re
own_fpu();
restore_fp(current);
}
- err |= save_fp_context(sc);
+ /* make sure save_fp_context not sleep */
+ err |= save_fp_context(&tmpsc);
+ err |= __copy_to_user(&sc->sc_fpregs, &tmpsc.sc_fpregs,
+ sizeof(tmpsc.sc_fpregs));
+ err |= __put_user(tmpsc.sc_fpc_csr, &sc->sc_fpc_csr);
+ err |= __put_user(tmpsc.sc_fpc_eir, &sc->sc_fpc_eir);
out:
return err;
diff -up linux-mips/arch/mips/kernel/signal32.c
linux/arch/mips/kernel/signal32.c
--- linux-mips/arch/mips/kernel/signal32.c Wed Sep 22 13:27:59 2004
+++ linux/arch/mips/kernel/signal32.c Thu Oct 7 14:47:39 2004
@@ -365,9 +365,14 @@ static asmlinkage int restore_sigcontext
err |= __get_user(current->used_math, &sc->sc_used_math);
if (current->used_math) {
+ struct sigcontext32 tmpsc;
+ /* make sure restore_fp_context32 not sleep */
+ err |= __copy_from_user(&tmpsc.sc_fpregs, &sc->sc_fpregs,
sizeof(tmpsc.sc_fpregs));
+ err |= __get_user(tmpsc.sc_fpc_csr, &sc->sc_fpc_csr);
+ err |= __get_user(tmpsc.sc_fpc_eir, &sc->sc_fpc_eir);
/* restore fpu context if we have used it before */
own_fpu();
- err |= restore_fp_context32(sc);
+ err |= restore_fp_context32(&tmpsc);
} else {
/* signal handler may have used FPU. Give it up. */
lose_fpu();
@@ -526,6 +531,7 @@ static inline int setup_sigcontext32(str
struct sigcontext32 *sc)
{
int err = 0;
+ struct sigcontext32 tmpsc;
err |= __put_user(regs->cp0_epc, &sc->sc_pc);
err |= __put_user(regs->cp0_status, &sc->sc_status);
@@ -562,7 +568,12 @@ static inline int setup_sigcontext32(str
own_fpu();
restore_fp(current);
}
- err |= save_fp_context32(sc);
+ /* make sure save_fp_context32 not sleep */
+ err |= save_fp_context32(&tmpsc);
+ err |= __copy_to_user(&sc->sc_fpregs, &tmpsc.sc_fpregs,
+ sizeof(tmpsc.sc_fpregs));
+ err |= __put_user(tmpsc.sc_fpc_csr, &sc->sc_fpc_csr);
+ err |= __put_user(tmpsc.sc_fpc_eir, &sc->sc_fpc_eir);
out:
return err;
---
Atsushi Nemoto
|