diff options
author | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2009-03-25 02:23:59 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-27 01:58:24 -0400 |
commit | efbda86098455da014be849713df6498cefc5a2a (patch) | |
tree | fb239d51dd521bb2976807eeedfacd17be9b6824 /arch/powerpc/kernel | |
parent | 82631f5dd114e52239fb3d1e270a49d37c088b46 (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/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/signal.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 2 |
4 files changed, 6 insertions, 6 deletions
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 | */ |
28 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 28 | void __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 @@ | |||
15 | extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags); | 15 | extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags); |
16 | 16 | ||
17 | extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 17 | extern 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); |
19 | extern void restore_sigmask(sigset_t *set); | 19 | extern void restore_sigmask(sigset_t *set); |
20 | 20 | ||
21 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, | 21 | extern 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 | ||