diff options
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 36 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 33 |
2 files changed, 30 insertions, 39 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 | } |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index c6a8f2326b6f..e132891d3cea 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -74,7 +74,8 @@ static const char fmt64[] = KERN_INFO \ | |||
74 | */ | 74 | */ |
75 | 75 | ||
76 | static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 76 | static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
77 | int signr, sigset_t *set, unsigned long handler) | 77 | int signr, sigset_t *set, unsigned long handler, |
78 | int ctx_has_vsx_region) | ||
78 | { | 79 | { |
79 | /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the | 80 | /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the |
80 | * process never used altivec yet (MSR_VEC is zero in pt_regs of | 81 | * process never used altivec yet (MSR_VEC is zero in pt_regs of |
@@ -121,7 +122,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
121 | * then out to userspace. Update v_regs to point after the | 122 | * then out to userspace. Update v_regs to point after the |
122 | * VMX data. | 123 | * VMX data. |
123 | */ | 124 | */ |
124 | if (current->thread.used_vsr) { | 125 | if (current->thread.used_vsr && ctx_has_vsx_region) { |
125 | __giveup_vsx(current); | 126 | __giveup_vsx(current); |
126 | v_regs += ELF_NVRREG; | 127 | v_regs += ELF_NVRREG; |
127 | err |= copy_vsx_to_user(v_regs, current); | 128 | err |= copy_vsx_to_user(v_regs, current); |
@@ -282,9 +283,10 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
282 | unsigned char tmp; | 283 | unsigned char tmp; |
283 | sigset_t set; | 284 | sigset_t set; |
284 | unsigned long new_msr = 0; | 285 | unsigned long new_msr = 0; |
286 | int ctx_has_vsx_region = 0; | ||
285 | 287 | ||
286 | if (new_ctx && | 288 | if (new_ctx && |
287 | __get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) | 289 | get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) |
288 | return -EFAULT; | 290 | return -EFAULT; |
289 | /* | 291 | /* |
290 | * Check that the context is not smaller than the original | 292 | * Check that the context is not smaller than the original |
@@ -299,28 +301,23 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
299 | if ((ctx_size < sizeof(struct ucontext)) && | 301 | if ((ctx_size < sizeof(struct ucontext)) && |
300 | (new_msr & MSR_VSX)) | 302 | (new_msr & MSR_VSX)) |
301 | return -EINVAL; | 303 | return -EINVAL; |
302 | #ifdef CONFIG_VSX | 304 | /* Does the context have enough room to store VSX data? */ |
303 | /* | 305 | if (ctx_size >= sizeof(struct ucontext)) |
304 | * If userspace doesn't provide enough room for VSX data, | 306 | ctx_has_vsx_region = 1; |
305 | * but current thread has used VSX, we don't have anywhere | 307 | |
306 | * to store the full context back into. | ||
307 | */ | ||
308 | if ((ctx_size < sizeof(struct ucontext)) && | ||
309 | (current->thread.used_vsr && old_ctx)) | ||
310 | return -EINVAL; | ||
311 | #endif | ||
312 | if (old_ctx != NULL) { | 308 | if (old_ctx != NULL) { |
313 | if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) | 309 | if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) |
314 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) | 310 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0, |
311 | ctx_has_vsx_region) | ||
315 | || __copy_to_user(&old_ctx->uc_sigmask, | 312 | || __copy_to_user(&old_ctx->uc_sigmask, |
316 | ¤t->blocked, sizeof(sigset_t))) | 313 | ¤t->blocked, sizeof(sigset_t))) |
317 | return -EFAULT; | 314 | return -EFAULT; |
318 | } | 315 | } |
319 | if (new_ctx == NULL) | 316 | if (new_ctx == NULL) |
320 | return 0; | 317 | return 0; |
321 | if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) | 318 | if (!access_ok(VERIFY_READ, new_ctx, ctx_size) |
322 | || __get_user(tmp, (u8 __user *) new_ctx) | 319 | || __get_user(tmp, (u8 __user *) new_ctx) |
323 | || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) | 320 | || __get_user(tmp, (u8 __user *) new_ctx + ctx_size - 1)) |
324 | return -EFAULT; | 321 | return -EFAULT; |
325 | 322 | ||
326 | /* | 323 | /* |
@@ -423,7 +420,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
423 | &frame->uc.uc_stack.ss_flags); | 420 | &frame->uc.uc_stack.ss_flags); |
424 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 421 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
425 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL, | 422 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL, |
426 | (unsigned long)ka->sa.sa_handler); | 423 | (unsigned long)ka->sa.sa_handler, 1); |
427 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 424 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
428 | if (err) | 425 | if (err) |
429 | goto badframe; | 426 | goto badframe; |