aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.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_32.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_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 9991e2a58bf4..6f6810db0a74 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -68,6 +68,13 @@
68#define ucontext ucontext32 68#define ucontext ucontext32
69 69
70/* 70/*
71 * Userspace code may pass a ucontext which doesn't include VSX added
72 * at the end. We need to check for this case.
73 */
74#define UCONTEXTSIZEWITHOUTVSX \
75 (sizeof(struct ucontext) - sizeof(elf_vsrreghalf_t32))
76
77/*
71 * Returning 0 means we return to userspace via 78 * Returning 0 means we return to userspace via
72 * ret_from_except and thus restore all user 79 * ret_from_except and thus restore all user
73 * registers from *regs. This is what we need 80 * registers from *regs. This is what we need
@@ -930,12 +937,42 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
930{ 937{
931 unsigned char tmp; 938 unsigned char tmp;
932 939
940#ifdef CONFIG_PPC64
941 unsigned long new_msr = 0;
942
943 if (new_ctx &&
944 __get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR]))
945 return -EFAULT;
946 /*
947 * Check that the context is not smaller than the original
948 * size (with VMX but without VSX)
949 */
950 if (ctx_size < UCONTEXTSIZEWITHOUTVSX)
951 return -EINVAL;
952 /*
953 * If the new context state sets the MSR VSX bits but
954 * it doesn't provide VSX state.
955 */
956 if ((ctx_size < sizeof(struct ucontext)) &&
957 (new_msr & MSR_VSX))
958 return -EINVAL;
959#ifdef CONFIG_VSX
960 /*
961 * If userspace doesn't provide enough room for VSX data,
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
933 /* Context size is for future use. Right now, we only make sure 970 /* Context size is for future use. Right now, we only make sure
934 * we are passed something we understand 971 * we are passed something we understand
935 */ 972 */
936 if (ctx_size < sizeof(struct ucontext)) 973 if (ctx_size < sizeof(struct ucontext))
937 return -EINVAL; 974 return -EINVAL;
938 975#endif
939 if (old_ctx != NULL) { 976 if (old_ctx != NULL) {
940 struct mcontext __user *mctx; 977 struct mcontext __user *mctx;
941 978