]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From 45b01b77bd3529e761bca6de0f0ed79549377479 Mon Sep 17 00:00:00 2001 |
2 | From: Andy Lutomirski <luto@kernel.org> | |
3 | Date: Mon, 4 Dec 2017 15:07:13 +0100 | |
633c5ed1 | 4 | Subject: [PATCH 143/242] x86/dumpstack: Add get_stack_info() support for the |
321d628a FG |
5 | SYSENTER stack |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5754 | |
11 | ||
12 | get_stack_info() doesn't currently know about the SYSENTER stack, so | |
13 | unwinding will fail if we entered the kernel on the SYSENTER stack | |
14 | and haven't fully switched off. Teach get_stack_info() about the | |
15 | SYSENTER stack. | |
16 | ||
17 | With future patches applied that run part of the entry code on the | |
18 | SYSENTER stack and introduce an intentional BUG(), I would get: | |
19 | ||
20 | PANIC: double fault, error_code: 0x0 | |
21 | ... | |
22 | RIP: 0010:do_error_trap+0x33/0x1c0 | |
23 | ... | |
24 | Call Trace: | |
25 | Code: ... | |
26 | ||
27 | With this patch, I get: | |
28 | ||
29 | PANIC: double fault, error_code: 0x0 | |
30 | ... | |
31 | Call Trace: | |
32 | <SYSENTER> | |
33 | ? async_page_fault+0x36/0x60 | |
34 | ? invalid_op+0x22/0x40 | |
35 | ? async_page_fault+0x36/0x60 | |
36 | ? sync_regs+0x3c/0x40 | |
37 | ? sync_regs+0x2e/0x40 | |
38 | ? error_entry+0x6c/0xd0 | |
39 | ? async_page_fault+0x36/0x60 | |
40 | </SYSENTER> | |
41 | Code: ... | |
42 | ||
43 | which is a lot more informative. | |
44 | ||
45 | Signed-off-by: Andy Lutomirski <luto@kernel.org> | |
46 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
47 | Reviewed-by: Borislav Petkov <bp@suse.de> | |
48 | Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
49 | Cc: Borislav Petkov <bp@alien8.de> | |
50 | Cc: Borislav Petkov <bpetkov@suse.de> | |
51 | Cc: Brian Gerst <brgerst@gmail.com> | |
52 | Cc: Dave Hansen <dave.hansen@intel.com> | |
53 | Cc: Dave Hansen <dave.hansen@linux.intel.com> | |
54 | Cc: David Laight <David.Laight@aculab.com> | |
55 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
56 | Cc: Eduardo Valentin <eduval@amazon.com> | |
57 | Cc: Greg KH <gregkh@linuxfoundation.org> | |
58 | Cc: H. Peter Anvin <hpa@zytor.com> | |
59 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
60 | Cc: Juergen Gross <jgross@suse.com> | |
61 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
62 | Cc: Peter Zijlstra <peterz@infradead.org> | |
63 | Cc: Rik van Riel <riel@redhat.com> | |
64 | Cc: Will Deacon <will.deacon@arm.com> | |
65 | Cc: aliguori@amazon.com | |
66 | Cc: daniel.gruss@iaik.tugraz.at | |
67 | Cc: hughd@google.com | |
68 | Cc: keescook@google.com | |
69 | Link: https://lkml.kernel.org/r/20171204150605.392711508@linutronix.de | |
70 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
71 | (cherry picked from commit 33a2f1a6c4d7c0a02d1c006fb0379cc5ca3b96bb) | |
72 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
73 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
74 | (cherry picked from commit 72e90cc5463cf882c5f9508817029d85b317f2b5) | |
75 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
76 | --- | |
77 | arch/x86/include/asm/stacktrace.h | 3 +++ | |
78 | arch/x86/kernel/dumpstack.c | 19 +++++++++++++++++++ | |
79 | arch/x86/kernel/dumpstack_32.c | 6 ++++++ | |
80 | arch/x86/kernel/dumpstack_64.c | 6 ++++++ | |
81 | 4 files changed, 34 insertions(+) | |
82 | ||
83 | diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h | |
84 | index 2e41c50ddf47..95f999576131 100644 | |
85 | --- a/arch/x86/include/asm/stacktrace.h | |
86 | +++ b/arch/x86/include/asm/stacktrace.h | |
87 | @@ -15,6 +15,7 @@ enum stack_type { | |
88 | STACK_TYPE_TASK, | |
89 | STACK_TYPE_IRQ, | |
90 | STACK_TYPE_SOFTIRQ, | |
91 | + STACK_TYPE_SYSENTER, | |
92 | STACK_TYPE_EXCEPTION, | |
93 | STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1, | |
94 | }; | |
95 | @@ -27,6 +28,8 @@ struct stack_info { | |
96 | bool in_task_stack(unsigned long *stack, struct task_struct *task, | |
97 | struct stack_info *info); | |
98 | ||
99 | +bool in_sysenter_stack(unsigned long *stack, struct stack_info *info); | |
100 | + | |
101 | int get_stack_info(unsigned long *stack, struct task_struct *task, | |
102 | struct stack_info *info, unsigned long *visit_mask); | |
103 | ||
104 | diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c | |
105 | index 695cdce5dfc8..c211cbdff709 100644 | |
106 | --- a/arch/x86/kernel/dumpstack.c | |
107 | +++ b/arch/x86/kernel/dumpstack.c | |
108 | @@ -43,6 +43,25 @@ bool in_task_stack(unsigned long *stack, struct task_struct *task, | |
109 | return true; | |
110 | } | |
111 | ||
112 | +bool in_sysenter_stack(unsigned long *stack, struct stack_info *info) | |
113 | +{ | |
114 | + struct tss_struct *tss = this_cpu_ptr(&cpu_tss); | |
115 | + | |
116 | + /* Treat the canary as part of the stack for unwinding purposes. */ | |
117 | + void *begin = &tss->SYSENTER_stack_canary; | |
118 | + void *end = (void *)&tss->SYSENTER_stack + sizeof(tss->SYSENTER_stack); | |
119 | + | |
120 | + if ((void *)stack < begin || (void *)stack >= end) | |
121 | + return false; | |
122 | + | |
123 | + info->type = STACK_TYPE_SYSENTER; | |
124 | + info->begin = begin; | |
125 | + info->end = end; | |
126 | + info->next_sp = NULL; | |
127 | + | |
128 | + return true; | |
129 | +} | |
130 | + | |
131 | static void printk_stack_address(unsigned long address, int reliable, | |
132 | char *log_lvl) | |
133 | { | |
134 | diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c | |
135 | index e5f0b40e66d2..3160bf2d100e 100644 | |
136 | --- a/arch/x86/kernel/dumpstack_32.c | |
137 | +++ b/arch/x86/kernel/dumpstack_32.c | |
138 | @@ -25,6 +25,9 @@ const char *stack_type_name(enum stack_type type) | |
139 | if (type == STACK_TYPE_SOFTIRQ) | |
140 | return "SOFTIRQ"; | |
141 | ||
142 | + if (type == STACK_TYPE_SYSENTER) | |
143 | + return "SYSENTER"; | |
144 | + | |
145 | return NULL; | |
146 | } | |
147 | ||
148 | @@ -92,6 +95,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, | |
149 | if (task != current) | |
150 | goto unknown; | |
151 | ||
152 | + if (in_sysenter_stack(stack, info)) | |
153 | + goto recursion_check; | |
154 | + | |
155 | if (in_hardirq_stack(stack, info)) | |
156 | goto recursion_check; | |
157 | ||
158 | diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c | |
159 | index 3e1471d57487..f5107b659f86 100644 | |
160 | --- a/arch/x86/kernel/dumpstack_64.c | |
161 | +++ b/arch/x86/kernel/dumpstack_64.c | |
162 | @@ -36,6 +36,9 @@ const char *stack_type_name(enum stack_type type) | |
163 | if (type == STACK_TYPE_IRQ) | |
164 | return "IRQ"; | |
165 | ||
166 | + if (type == STACK_TYPE_SYSENTER) | |
167 | + return "SYSENTER"; | |
168 | + | |
169 | if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST) | |
170 | return exception_stack_names[type - STACK_TYPE_EXCEPTION]; | |
171 | ||
172 | @@ -114,6 +117,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, | |
173 | if (in_irq_stack(stack, info)) | |
174 | goto recursion_check; | |
175 | ||
176 | + if (in_sysenter_stack(stack, info)) | |
177 | + goto recursion_check; | |
178 | + | |
179 | goto unknown; | |
180 | ||
181 | recursion_check: | |
182 | -- | |
183 | 2.14.2 | |
184 |