diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_64.c')
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 93ebfb6944b6..5f9d2ef2e24b 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -268,6 +268,13 @@ static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | |||
268 | } | 268 | } |
269 | 269 | ||
270 | /* | 270 | /* |
271 | * Userspace code may pass a ucontext which doesn't include VSX added | ||
272 | * at the end. We need to check for this case. | ||
273 | */ | ||
274 | #define UCONTEXTSIZEWITHOUTVSX \ | ||
275 | (sizeof(struct ucontext) - 32*sizeof(long)) | ||
276 | |||
277 | /* | ||
271 | * Handle {get,set,swap}_context operations | 278 | * Handle {get,set,swap}_context operations |
272 | */ | 279 | */ |
273 | int sys_swapcontext(struct ucontext __user *old_ctx, | 280 | int sys_swapcontext(struct ucontext __user *old_ctx, |
@@ -276,13 +283,34 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
276 | { | 283 | { |
277 | unsigned char tmp; | 284 | unsigned char tmp; |
278 | sigset_t set; | 285 | sigset_t set; |
286 | unsigned long new_msr = 0; | ||
279 | 287 | ||
280 | /* Context size is for future use. Right now, we only make sure | 288 | if (new_ctx && |
281 | * we are passed something we understand | 289 | __get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) |
290 | return -EFAULT; | ||
291 | /* | ||
292 | * Check that the context is not smaller than the original | ||
293 | * size (with VMX but without VSX) | ||
282 | */ | 294 | */ |
283 | if (ctx_size < sizeof(struct ucontext)) | 295 | if (ctx_size < UCONTEXTSIZEWITHOUTVSX) |
284 | return -EINVAL; | 296 | return -EINVAL; |
285 | 297 | /* | |
298 | * If the new context state sets the MSR VSX bits but | ||
299 | * it doesn't provide VSX state. | ||
300 | */ | ||
301 | if ((ctx_size < sizeof(struct ucontext)) && | ||
302 | (new_msr & MSR_VSX)) | ||
303 | return -EINVAL; | ||
304 | #ifdef CONFIG_VSX | ||
305 | /* | ||
306 | * If userspace doesn't provide enough room for VSX data, | ||
307 | * but current thread has used VSX, we don't have anywhere | ||
308 | * to store the full context back into. | ||
309 | */ | ||
310 | if ((ctx_size < sizeof(struct ucontext)) && | ||
311 | (current->thread.used_vsr && old_ctx)) | ||
312 | return -EINVAL; | ||
313 | #endif | ||
286 | if (old_ctx != NULL) { | 314 | if (old_ctx != NULL) { |
287 | if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) | 315 | if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) |
288 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) | 316 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) |