aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/signal_64.c')
-rw-r--r--arch/powerpc/kernel/signal_64.c36
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 */
273int sys_swapcontext(struct ucontext __user *old_ctx, 280int 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)