diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 36 |
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 | */ |
412 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | 412 | static 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, ¤t->blocked) | 984 | || put_sigset_t(&old_ctx->uc_sigmask, ¤t->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 | } |