]>
Commit | Line | Data |
---|---|---|
e46fb18b GKH |
1 | From 2a855dd01bc1539111adb7233f587c5c468732ac Mon Sep 17 00:00:00 2001 |
2 | From: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> | |
3 | Date: Sun, 25 Oct 2009 15:37:58 +0100 | |
4 | Subject: signal: Fix alternate signal stack check | |
5 | ||
6 | From: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> | |
7 | ||
8 | commit 2a855dd01bc1539111adb7233f587c5c468732ac upstream. | |
9 | ||
10 | All architectures in the kernel increment/decrement the stack pointer | |
11 | before storing values on the stack. | |
12 | ||
13 | On architectures which have the stack grow down sas_ss_sp == sp is not | |
14 | on the alternate signal stack while sas_ss_sp + sas_ss_size == sp is | |
15 | on the alternate signal stack. | |
16 | ||
17 | On architectures which have the stack grow up sas_ss_sp == sp is on | |
18 | the alternate signal stack while sas_ss_sp + sas_ss_size == sp is not | |
19 | on the alternate signal stack. | |
20 | ||
21 | The current implementation fails for architectures which have the | |
22 | stack grow down on the corner case where sas_ss_sp == sp.This was | |
23 | reported as Debian bug #544905 on AMD64. | |
24 | Simplified test case: http://download.breakpoint.cc/tc-sig-stack.c | |
25 | ||
26 | The test case creates the following stack scenario: | |
27 | 0xn0300 stack top | |
28 | 0xn0200 alt stack pointer top (when switching to alt stack) | |
29 | 0xn01ff alt stack end | |
30 | 0xn0100 alt stack start == stack pointer | |
31 | ||
32 | If the signal is sent the stack pointer is pointing to the base | |
33 | address of the alt stack and the kernel erroneously decides that it | |
34 | has already switched to the alternate stack because of the current | |
35 | check for "sp - sas_ss_sp < sas_ss_size" | |
36 | ||
37 | On parisc (stack grows up) the scenario would be: | |
38 | 0xn0200 stack pointer | |
39 | 0xn01ff alt stack end | |
40 | 0xn0100 alt stack start = alt stack pointer base | |
41 | (when switching to alt stack) | |
42 | 0xn0000 stack base | |
43 | ||
44 | This is handled correctly by the current implementation. | |
45 | ||
46 | [ tglx: Modified for archs which have the stack grow up (parisc) which | |
47 | would fail with the correct implementation for stack grows | |
48 | down. Added a check for sp >= current->sas_ss_sp which is | |
49 | strictly not necessary but makes the code symetric for both | |
50 | variants ] | |
51 | ||
52 | Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> | |
53 | Cc: Oleg Nesterov <oleg@redhat.com> | |
54 | Cc: Roland McGrath <roland@redhat.com> | |
55 | Cc: Kyle McMartin <kyle@mcmartin.ca> | |
56 | LKML-Reference: <20091025143758.GA6653@Chamillionaire.breakpoint.cc> | |
57 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
58 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
59 | ||
60 | --- | |
61 | include/linux/sched.h | 13 ++++++++++--- | |
62 | 1 file changed, 10 insertions(+), 3 deletions(-) | |
63 | ||
64 | --- a/include/linux/sched.h | |
65 | +++ b/include/linux/sched.h | |
66 | @@ -2086,11 +2086,18 @@ static inline int is_si_special(const st | |
67 | return info <= SEND_SIG_FORCED; | |
68 | } | |
69 | ||
70 | -/* True if we are on the alternate signal stack. */ | |
71 | - | |
72 | +/* | |
73 | + * True if we are on the alternate signal stack. | |
74 | + */ | |
75 | static inline int on_sig_stack(unsigned long sp) | |
76 | { | |
77 | - return (sp - current->sas_ss_sp < current->sas_ss_size); | |
78 | +#ifdef CONFIG_STACK_GROWSUP | |
79 | + return sp >= current->sas_ss_sp && | |
80 | + sp - current->sas_ss_sp < current->sas_ss_size; | |
81 | +#else | |
82 | + return sp > current->sas_ss_sp && | |
83 | + sp - current->sas_ss_sp <= current->sas_ss_size; | |
84 | +#endif | |
85 | } | |
86 | ||
87 | static inline int sas_ss_flags(unsigned long sp) |