>>>>> On Fri, 07 Oct 2005 23:51:52 +0900 (JST), Atsushi Nemoto
>>>>> <anemo@mba.ocn.ne.jp> said:
anemo> The setup_sigcontect/restore_sigcontext might sleep on
anemo> put_user/get_user with preemption disabled (i.e. atomic
anemo> context). Sleeping in atomic context is not allowed. This
anemo> patch fixes this problem using temporary variable (struct
anemo> sigcontext tmpsc).
anemo> Another possible fix might be rewriting
anemo> restore_fp_context/save_fp_context to copy to/from current
anemo> thread_struct and use them with restore_fp/save_fp.
Updated. And I'll post the "another possible fix" in next mail. If
the another one was accepted, please ignore this patch.
The setup_sigcontect()/restore_sigcontext() might sleep on
put_user()/get_user() with preemption disabled (i.e. atomic context).
Sleeping in atomic context is not allowed. This patch fixes this
problem using temporary variable (struct sigcontext tmpsc).
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index 0fbc492..0c7726a 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -14,6 +14,7 @@ static inline int
setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
{
int err = 0;
+ struct sigcontext tmpsc;
err |= __put_user(regs->cp0_epc, &sc->sc_pc);
@@ -73,10 +74,15 @@ setup_sigcontext(struct pt_regs *regs, s
own_fpu();
restore_fp(current);
}
- err |= save_fp_context(sc);
+ /* make sure save_fp_context not sleep */
+ err |= save_fp_context(&tmpsc);
preempt_enable();
+ 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);
+
out:
return err;
}
@@ -138,14 +144,18 @@ restore_sigcontext(struct pt_regs *regs,
err |= __get_user(used_math, &sc->sc_used_math);
conditional_used_math(used_math);
- preempt_disable();
-
if (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);
+ preempt_disable();
/* 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. */
+ preempt_disable();
lose_fpu();
}
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 136260c..4741d91 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -377,14 +377,18 @@ static int restore_sigcontext32(struct p
err |= __get_user(used_math, &sc->sc_used_math);
conditional_used_math(used_math);
- preempt_disable();
-
if (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);
+ preempt_disable();
/* 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. */
+ preempt_disable();
lose_fpu();
}
@@ -568,6 +572,7 @@ static inline int setup_sigcontext32(str
struct sigcontext32 __user *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);
@@ -613,10 +618,15 @@ 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);
preempt_enable();
+ 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);
+
out:
return err;
}
|