aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c36
1 files changed, 15 insertions, 21 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3e80aa32b8b0..a6a43103655e 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -410,7 +410,7 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task,
410 * altivec/spe instructions at some point. 410 * altivec/spe instructions at some point.
411 */ 411 */
412static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, 412static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
413 int sigret) 413 int sigret, int ctx_has_vsx_region)
414{ 414{
415 unsigned long msr = regs->msr; 415 unsigned long msr = regs->msr;
416 416
@@ -451,7 +451,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
451 * the saved MSR value to indicate that frame->mc_vregs 451 * the saved MSR value to indicate that frame->mc_vregs
452 * contains valid data 452 * contains valid data
453 */ 453 */
454 if (current->thread.used_vsr) { 454 if (current->thread.used_vsr && ctx_has_vsx_region) {
455 __giveup_vsx(current); 455 __giveup_vsx(current);
456 if (copy_vsx_to_user(&frame->mc_vsregs, current)) 456 if (copy_vsx_to_user(&frame->mc_vsregs, current))
457 return 1; 457 return 1;
@@ -858,11 +858,11 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
858 frame = &rt_sf->uc.uc_mcontext; 858 frame = &rt_sf->uc.uc_mcontext;
859 addr = frame; 859 addr = frame;
860 if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { 860 if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
861 if (save_user_regs(regs, frame, 0)) 861 if (save_user_regs(regs, frame, 0, 1))
862 goto badframe; 862 goto badframe;
863 regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; 863 regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
864 } else { 864 } else {
865 if (save_user_regs(regs, frame, __NR_rt_sigreturn)) 865 if (save_user_regs(regs, frame, __NR_rt_sigreturn, 1))
866 goto badframe; 866 goto badframe;
867 regs->link = (unsigned long) frame->tramp; 867 regs->link = (unsigned long) frame->tramp;
868 } 868 }
@@ -936,12 +936,13 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
936 int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) 936 int ctx_size, int r6, int r7, int r8, struct pt_regs *regs)
937{ 937{
938 unsigned char tmp; 938 unsigned char tmp;
939 int ctx_has_vsx_region = 0;
939 940
940#ifdef CONFIG_PPC64 941#ifdef CONFIG_PPC64
941 unsigned long new_msr = 0; 942 unsigned long new_msr = 0;
942 943
943 if (new_ctx && 944 if (new_ctx &&
944 __get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR])) 945 get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR]))
945 return -EFAULT; 946 return -EFAULT;
946 /* 947 /*
947 * Check that the context is not smaller than the original 948 * Check that the context is not smaller than the original
@@ -956,16 +957,9 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
956 if ((ctx_size < sizeof(struct ucontext)) && 957 if ((ctx_size < sizeof(struct ucontext)) &&
957 (new_msr & MSR_VSX)) 958 (new_msr & MSR_VSX))
958 return -EINVAL; 959 return -EINVAL;
959#ifdef CONFIG_VSX 960 /* Does the context have enough room to store VSX data? */
960 /* 961 if (ctx_size >= sizeof(struct ucontext))
961 * If userspace doesn't provide enough room for VSX data, 962 ctx_has_vsx_region = 1;
962 * but current thread has used VSX, we don't have anywhere
963 * to store the full context back into.
964 */
965 if ((ctx_size < sizeof(struct ucontext)) &&
966 (current->thread.used_vsr && old_ctx))
967 return -EINVAL;
968#endif
969#else 963#else
970 /* Context size is for future use. Right now, we only make sure 964 /* Context size is for future use. Right now, we only make sure
971 * we are passed something we understand 965 * we are passed something we understand
@@ -985,17 +979,17 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
985 */ 979 */
986 mctx = (struct mcontext __user *) 980 mctx = (struct mcontext __user *)
987 ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL); 981 ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
988 if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) 982 if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size)
989 || save_user_regs(regs, mctx, 0) 983 || save_user_regs(regs, mctx, 0, ctx_has_vsx_region)
990 || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked) 984 || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
991 || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs)) 985 || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
992 return -EFAULT; 986 return -EFAULT;
993 } 987 }
994 if (new_ctx == NULL) 988 if (new_ctx == NULL)
995 return 0; 989 return 0;
996 if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) 990 if (!access_ok(VERIFY_READ, new_ctx, ctx_size)
997 || __get_user(tmp, (u8 __user *) new_ctx) 991 || __get_user(tmp, (u8 __user *) new_ctx)
998 || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) 992 || __get_user(tmp, (u8 __user *) new_ctx + ctx_size - 1))
999 return -EFAULT; 993 return -EFAULT;
1000 994
1001 /* 995 /*
@@ -1196,11 +1190,11 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
1196 goto badframe; 1190 goto badframe;
1197 1191
1198 if (vdso32_sigtramp && current->mm->context.vdso_base) { 1192 if (vdso32_sigtramp && current->mm->context.vdso_base) {
1199 if (save_user_regs(regs, &frame->mctx, 0)) 1193 if (save_user_regs(regs, &frame->mctx, 0, 1))
1200 goto badframe; 1194 goto badframe;
1201 regs->link = current->mm->context.vdso_base + vdso32_sigtramp; 1195 regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
1202 } else { 1196 } else {
1203 if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) 1197 if (save_user_regs(regs, &frame->mctx, __NR_sigreturn, 1))
1204 goto badframe; 1198 goto badframe;
1205 regs->link = (unsigned long) frame->mctx.tramp; 1199 regs->link = (unsigned long) frame->mctx.tramp;
1206 } 1200 }