]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
powerpc: Sanitize stack pointer in signal handling code
authorJosh Boyer <jwboyer@linux.vnet.ibm.com>
Tue, 28 Apr 2009 15:11:57 +0000 (11:11 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 2 May 2009 17:24:48 +0000 (10:24 -0700)
This has been backported to 2.6.27.x from commit efbda86098 in Linus' tree.

On powerpc64 machines running 32-bit userspace, we can get garbage bits in the
stack pointer passed into the kernel.  Most places handle this correctly, but
the signal handling code uses the passed value directly for allocating signal
stack frames.

This fixes the issue by introducing a get_clean_sp function that returns a
sanitized stack pointer.  For 32-bit tasks on a 64-bit kernel, the stack
pointer is masked correctly.  In all other cases, the stack pointer is simply
returned.

Additionally, we pass an 'is_32' parameter to get_sigframe now in order to
get the properly sanitized stack.  The callers are know to be 32 or 64-bit
statically.

Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/signal.c
arch/powerpc/kernel/signal.h
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c

index 101ed87f7d844d832a7d37a41d91739ed8f0aeb1..ae1c5b595ec03bf9b129fe2eb62899f700fd9a8d 100644 (file)
@@ -309,6 +309,25 @@ static inline void prefetchw(const void *x)
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 #endif
 
+#ifdef CONFIG_PPC64
+static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
+{
+       unsigned long sp;
+
+       if (is_32)
+               sp = regs->gpr[1] & 0x0ffffffffUL;
+       else
+               sp = regs->gpr[1];
+
+       return sp;
+}
+#else
+static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
+{
+       return regs->gpr[1];
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_PROCESSOR_H */
index a54405ebd7b0c35236cafedb3edee13bcfb67fb3..00b5078da9a3f10f2e34ba160c72db098f67c612 100644 (file)
@@ -26,12 +26,12 @@ int show_unhandled_signals = 0;
  * Allocate space for the signal frame
  */
 void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-                          size_t frame_size)
+                          size_t frame_size, int is_32)
 {
         unsigned long oldsp, newsp;
 
         /* Default to using normal stack */
-        oldsp = regs->gpr[1];
+        oldsp = get_clean_sp(regs, is_32);
 
        /* Check for alt stack */
        if ((ka->sa.sa_flags & SA_ONSTACK) &&
index 28f4b9f5fe5e970a505940acd4268ce355be48c3..f77d5023269688c48ee050bf1e912c721da21139 100644 (file)
@@ -13,7 +13,7 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-                                 size_t frame_size);
+                                 size_t frame_size, int is_32);
 extern void restore_sigmask(sigset_t *set);
 
 extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
index a6a43103655e8625865b021b5cf3d59e2cee0221..9084a2750d3340bdc0f9ea460d373237901b5f3f 100644 (file)
@@ -836,7 +836,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
 
        /* Set up Signal Frame */
        /* Put a Real Time Context onto stack */
-       rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+       rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf), 1);
        addr = rt_sf;
        if (unlikely(rt_sf == NULL))
                goto badframe;
@@ -1170,7 +1170,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
        unsigned long newsp = 0;
 
        /* Set up Signal Frame */
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), 1);
        if (unlikely(frame == NULL))
                goto badframe;
        sc = (struct sigcontext __user *) &frame->sctx;
index e4acdbd441084852ab83906916f645be0d6838c3..3de15b075d714b2a018f99186ea0723a6808fad5 100644 (file)
@@ -404,7 +404,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
        unsigned long newsp = 0;
        long err = 0;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(ka, regs, sizeof(*frame), 0);
        if (unlikely(frame == NULL))
                goto badframe;