aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_64.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2008-07-08 04:43:41 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-09 02:30:47 -0400
commitc1cb299ead405f0ac065c4430729549b187e5b32 (patch)
treef61b78d06c8bc49e5b671bd065464613758dcefb /arch/powerpc/kernel/signal_64.c
parent1b17adf19b4d66858f366acd82b4e81cba5edc93 (diff)
powerpc: fix swapcontext backwards compat. with VSX ucontext changes
When the ucontext changed to add the VSX context, this broke backwards compatibly on swapcontext. swapcontext only compares the ucontext size passed in from the user to the new kernel ucontext size. This adds a check against the old ucontext size (with VMX but without VSX). It also adds some sanity check for ucontexts without VSX, but where VSX is used according the MSR. Fixes for both 32 and 64bit processes on 64bit kernels Kudos to Paulus for noticing. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
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)