aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@linux.vnet.ibm.com>2009-03-25 02:23:59 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-03-27 01:58:24 -0400
commitefbda86098455da014be849713df6498cefc5a2a (patch)
treefb239d51dd521bb2976807eeedfacd17be9b6824 /arch
parent82631f5dd114e52239fb3d1e270a49d37c088b46 (diff)
powerpc: Sanitize stack pointer in signal handling code
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/processor.h19
-rw-r--r--arch/powerpc/kernel/signal.c4
-rw-r--r--arch/powerpc/kernel/signal.h2
-rw-r--r--arch/powerpc/kernel/signal_32.c4
-rw-r--r--arch/powerpc/kernel/signal_64.c2
5 files changed, 25 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index d3466490104a..9eed29eee604 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -313,6 +313,25 @@ static inline void prefetchw(const void *x)
313#define HAVE_ARCH_PICK_MMAP_LAYOUT 313#define HAVE_ARCH_PICK_MMAP_LAYOUT
314#endif 314#endif
315 315
316#ifdef CONFIG_PPC64
317static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
318{
319 unsigned long sp;
320
321 if (is_32)
322 sp = regs->gpr[1] & 0x0ffffffffUL;
323 else
324 sp = regs->gpr[1];
325
326 return sp;
327}
328#else
329static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
330{
331 return regs->gpr[1];
332}
333#endif
334
316#endif /* __KERNEL__ */ 335#endif /* __KERNEL__ */
317#endif /* __ASSEMBLY__ */ 336#endif /* __ASSEMBLY__ */
318#endif /* _ASM_POWERPC_PROCESSOR_H */ 337#endif /* _ASM_POWERPC_PROCESSOR_H */
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index a54405ebd7b0..00b5078da9a3 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -26,12 +26,12 @@ int show_unhandled_signals = 0;
26 * Allocate space for the signal frame 26 * Allocate space for the signal frame
27 */ 27 */
28void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 28void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
29 size_t frame_size) 29 size_t frame_size, int is_32)
30{ 30{
31 unsigned long oldsp, newsp; 31 unsigned long oldsp, newsp;
32 32
33 /* Default to using normal stack */ 33 /* Default to using normal stack */
34 oldsp = regs->gpr[1]; 34 oldsp = get_clean_sp(regs, is_32);
35 35
36 /* Check for alt stack */ 36 /* Check for alt stack */
37 if ((ka->sa.sa_flags & SA_ONSTACK) && 37 if ((ka->sa.sa_flags & SA_ONSTACK) &&
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index f1442d69d4ec..6c0ddfc0603e 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -15,7 +15,7 @@
15extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags); 15extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags);
16 16
17extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 17extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
18 size_t frame_size); 18 size_t frame_size, int is_32);
19extern void restore_sigmask(sigset_t *set); 19extern void restore_sigmask(sigset_t *set);
20 20
21extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, 21extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index b13abf305996..d670429a1608 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -836,7 +836,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
836 836
837 /* Set up Signal Frame */ 837 /* Set up Signal Frame */
838 /* Put a Real Time Context onto stack */ 838 /* Put a Real Time Context onto stack */
839 rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); 839 rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf), 1);
840 addr = rt_sf; 840 addr = rt_sf;
841 if (unlikely(rt_sf == NULL)) 841 if (unlikely(rt_sf == NULL))
842 goto badframe; 842 goto badframe;
@@ -1182,7 +1182,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
1182 unsigned long newsp = 0; 1182 unsigned long newsp = 0;
1183 1183
1184 /* Set up Signal Frame */ 1184 /* Set up Signal Frame */
1185 frame = get_sigframe(ka, regs, sizeof(*frame)); 1185 frame = get_sigframe(ka, regs, sizeof(*frame), 1);
1186 if (unlikely(frame == NULL)) 1186 if (unlikely(frame == NULL))
1187 goto badframe; 1187 goto badframe;
1188 sc = (struct sigcontext __user *) &frame->sctx; 1188 sc = (struct sigcontext __user *) &frame->sctx;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index e132891d3cea..2fe6fc64b614 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -402,7 +402,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
402 unsigned long newsp = 0; 402 unsigned long newsp = 0;
403 long err = 0; 403 long err = 0;
404 404
405 frame = get_sigframe(ka, regs, sizeof(*frame)); 405 frame = get_sigframe(ka, regs, sizeof(*frame), 0);
406 if (unlikely(frame == NULL)) 406 if (unlikely(frame == NULL))
407 goto badframe; 407 goto badframe;
408 408