diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_64.c')
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 33 |
1 files changed, 15 insertions, 18 deletions
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; |