From: Paul Mackerras Date: Tue, 26 Jun 2007 10:10:12 +0000 (+1000) Subject: [PATCH] POWERPC: Fix subtle FP state corruption bug in signal return on SMP X-Git-Tag: v2.6.20.16~6 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=0c53130a7d5da7597548f885e7b3238af18945d3;p=karo-tx-linux.git [PATCH] POWERPC: Fix subtle FP state corruption bug in signal return on SMP This fixes a bug which can cause corruption of the floating-point state on return from a signal handler. If we have a signal handler that has used the floating-point registers, and it happens to context-switch to another task while copying the interrupted floating-point state from the user stack into the thread struct (e.g. because of a page fault, or because it gets preempted), the context switch code will think that the FP registers contain valid FP state that needs to be copied into the thread_struct, and will thus overwrite the values that the signal return code has put into the thread_struct. This can occur because we clear the MSR bits that indicate the presence of valid FP state after copying the state into the thread_struct. To fix this we just move the clearing of the MSR bits to before the copy. A similar potential problem also occurs with the Altivec state, and this fixes that in the same way. Signed-off-by: Paul Mackerras Signed-off-by: Chris Wright Signed-off-by: Greg Kroah-Hartman --- diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index f72e8e823d78..a84304eabcaa 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -177,6 +177,13 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, */ discard_lazy_cpu_state(); + /* + * Force reload of FP/VEC. + * This has to be done before copying stuff into current->thread.fpr/vr + * for the reasons explained in the previous comment. + */ + regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); + err |= __copy_from_user(¤t->thread.fpr, &sc->fp_regs, FP_REGS_SIZE); #ifdef CONFIG_ALTIVEC @@ -198,9 +205,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, current->thread.vrsave = 0; #endif /* CONFIG_ALTIVEC */ - /* Force reload of FP/VEC */ - regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); - return err; }