aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-12-19 21:57:06 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-20 00:37:49 -0500
commit1c9bb1a01ac1bc92a0d98cf3e40a7922ee684dc0 (patch)
tree4072b12f9507045ed75595727998a00f17cdacc8 /arch/powerpc/kernel/signal_32.c
parentbb63ab13515951f4d09b16c9e8bd6e50b0f20d1e (diff)
[POWERPC] Fix register save area alignment for swapcontext syscall
For 32-bit processes, the getcontext side of the swapcontext system call (i.e. the saving of the context when the first argument is non-NULL) has to set the ctx->uc_mcontext.uc_regs pointer to the place where it saves the registers. Which it does, but it doesn't ensure that the pointer is 16-byte aligned. 16-byte alignment is needed because the Altivec/VMX registers are saved in there, and they need to be on a 16-byte boundary. This fixes it by ensuring the appropriate alignment of the pointer. This issue was pointed out by Jakub Jelinek. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index e4ebe1a6228e..6b405a3f43f9 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -835,11 +835,21 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
835 return -EINVAL; 835 return -EINVAL;
836 836
837 if (old_ctx != NULL) { 837 if (old_ctx != NULL) {
838 struct mcontext __user *mctx;
839
840 /*
841 * old_ctx might not be 16-byte aligned, in which
842 * case old_ctx->uc_mcontext won't be either.
843 * Because we have the old_ctx->uc_pad2 field
844 * before old_ctx->uc_mcontext, we need to round down
845 * from &old_ctx->uc_mcontext to a 16-byte boundary.
846 */
847 mctx = (struct mcontext __user *)
848 ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
838 if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) 849 if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
839 || save_user_regs(regs, &old_ctx->uc_mcontext, 0) 850 || save_user_regs(regs, mctx, 0)
840 || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked) 851 || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
841 || __put_user(to_user_ptr(&old_ctx->uc_mcontext), 852 || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
842 &old_ctx->uc_regs))
843 return -EFAULT; 853 return -EFAULT;
844 } 854 }
845 if (new_ctx == NULL) 855 if (new_ctx == NULL)