summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/align.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-08-20 12:30:07 +0200
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-08-27 06:44:26 +0200
commit5c2e08231b68a3c8082716a7ed4e972dde406e4a (patch)
tree865d5e0683f580921bec3515649767471bad098e /arch/powerpc/kernel/align.c
parentpseries: Move plpar_wrapper.h to powerpc common include/asm location. (diff)
downloadlinux-5c2e08231b68a3c8082716a7ed4e972dde406e4a.tar.xz
linux-5c2e08231b68a3c8082716a7ed4e972dde406e4a.zip
powerpc: Never handle VSX alignment exceptions from kernel
The VSX alignment handler needs to write out the existing VSX state to memory before operating on it (flush_vsx_to_thread()). If we take a VSX alignment exception in the kernel bad things will happen. It looks like we could write the kernel state out to the user process, or we could handle the kernel exception using data from the user process (depending if MSR_VSX is set or not). Worse still, if the code to read or write the VSX state causes an alignment exception, we will recurse forever. I ended up with hundreds of megabytes of kernel stack to look through as a result. Floating point and SPE code have similar issues but already include a user check. Add the same check to emulate_vsx(). With this patch any unaligned VSX loads and stores in the kernel will show up as a clear oops rather than silent corruption of kernel or userspace VSX state, or worse, corruption of a potentially unlimited amount of kernel memory. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/align.c')
-rw-r--r--arch/powerpc/kernel/align.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 52e5758ea368..a27ccd5dc6b9 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -651,6 +651,10 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
int sw = 0;
int i, j;
+ /* userland only */
+ if (unlikely(!user_mode(regs)))
+ return 0;
+
flush_vsx_to_thread(current);
if (reg < 32)