Re: fpu_emulator can lose fpu on get_user/put_user

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>>>>> On Wed, 06 Oct 2004 10:19:20 +0900 (JST), Atsushi Nemoto <anemo@xxxxxxxxxxxxx> 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


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux