diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 16 |
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, ¤t->blocked) | 851 | || put_sigset_t(&old_ctx->uc_sigmask, ¤t->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) |