diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 39 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 36 |
2 files changed, 70 insertions, 5 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 | ||
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) |