diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 39 |
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 | ||