]>
Commit | Line | Data |
---|---|---|
b10b0803 GKH |
1 | From 38dccaa0fb05bf353c3704763067688e6ec0c3a1 Mon Sep 17 00:00:00 2001 |
2 | From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
3 | Date: Mon, 31 Oct 2016 10:12:45 -0600 | |
4 | Subject: [PATCH 1/2] Revert "x86/mm: Expand the exception table logic to allow | |
5 | new handling options" | |
6 | ||
7 | This reverts commit fcf5e5198b447969ed2a56ec335dae3c695a6b46 which is | |
8 | 548acf19234dbda5a52d5a8e7e205af46e9da840 upstream. | |
9 | ||
10 | Cc: Tony Luck <tony.luck@intel.com> | |
11 | Cc: Borislav Petkov <bp@suse.de> | |
12 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
13 | Cc: Peter Zijlstra <peterz@infradead.org> | |
14 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
15 | Cc: Ingo Molnar <mingo@kernel.org> | |
16 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
17 | --- | |
18 | Documentation/x86/exception-tables.txt | 35 ----------- | |
19 | arch/x86/include/asm/asm.h | 40 +++++------- | |
20 | arch/x86/include/asm/uaccess.h | 16 ++--- | |
21 | arch/x86/kernel/kprobes/core.c | 2 | |
22 | arch/x86/kernel/traps.c | 6 - | |
23 | arch/x86/mm/extable.c | 102 +++++++++------------------------ | |
24 | arch/x86/mm/fault.c | 2 | |
25 | scripts/sortextable.c | 32 ---------- | |
26 | 8 files changed, 58 insertions(+), 177 deletions(-) | |
27 | ||
28 | --- a/Documentation/x86/exception-tables.txt | |
29 | +++ b/Documentation/x86/exception-tables.txt | |
30 | @@ -290,38 +290,3 @@ Due to the way that the exception table | |
31 | only use exceptions for code in the .text section. Any other section | |
32 | will cause the exception table to not be sorted correctly, and the | |
33 | exceptions will fail. | |
34 | - | |
35 | -Things changed when 64-bit support was added to x86 Linux. Rather than | |
36 | -double the size of the exception table by expanding the two entries | |
37 | -from 32-bits to 64 bits, a clever trick was used to store addresses | |
38 | -as relative offsets from the table itself. The assembly code changed | |
39 | -from: | |
40 | - .long 1b,3b | |
41 | -to: | |
42 | - .long (from) - . | |
43 | - .long (to) - . | |
44 | - | |
45 | -and the C-code that uses these values converts back to absolute addresses | |
46 | -like this: | |
47 | - | |
48 | - ex_insn_addr(const struct exception_table_entry *x) | |
49 | - { | |
50 | - return (unsigned long)&x->insn + x->insn; | |
51 | - } | |
52 | - | |
53 | -In v4.6 the exception table entry was expanded with a new field "handler". | |
54 | -This is also 32-bits wide and contains a third relative function | |
55 | -pointer which points to one of: | |
56 | - | |
57 | -1) int ex_handler_default(const struct exception_table_entry *fixup) | |
58 | - This is legacy case that just jumps to the fixup code | |
59 | -2) int ex_handler_fault(const struct exception_table_entry *fixup) | |
60 | - This case provides the fault number of the trap that occurred at | |
61 | - entry->insn. It is used to distinguish page faults from machine | |
62 | - check. | |
63 | -3) int ex_handler_ext(const struct exception_table_entry *fixup) | |
64 | - This case is used for uaccess_err ... we need to set a flag | |
65 | - in the task structure. Before the handler functions existed this | |
66 | - case was handled by adding a large offset to the fixup to tag | |
67 | - it as special. | |
68 | -More functions can easily be added. | |
69 | --- a/arch/x86/include/asm/asm.h | |
70 | +++ b/arch/x86/include/asm/asm.h | |
71 | @@ -44,22 +44,19 @@ | |
72 | ||
73 | /* Exception table entry */ | |
74 | #ifdef __ASSEMBLY__ | |
75 | -# define _ASM_EXTABLE_HANDLE(from, to, handler) \ | |
76 | +# define _ASM_EXTABLE(from,to) \ | |
77 | .pushsection "__ex_table","a" ; \ | |
78 | - .balign 4 ; \ | |
79 | + .balign 8 ; \ | |
80 | .long (from) - . ; \ | |
81 | .long (to) - . ; \ | |
82 | - .long (handler) - . ; \ | |
83 | .popsection | |
84 | ||
85 | -# define _ASM_EXTABLE(from, to) \ | |
86 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_default) | |
87 | - | |
88 | -# define _ASM_EXTABLE_FAULT(from, to) \ | |
89 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) | |
90 | - | |
91 | -# define _ASM_EXTABLE_EX(from, to) \ | |
92 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_ext) | |
93 | +# define _ASM_EXTABLE_EX(from,to) \ | |
94 | + .pushsection "__ex_table","a" ; \ | |
95 | + .balign 8 ; \ | |
96 | + .long (from) - . ; \ | |
97 | + .long (to) - . + 0x7ffffff0 ; \ | |
98 | + .popsection | |
99 | ||
100 | # define _ASM_NOKPROBE(entry) \ | |
101 | .pushsection "_kprobe_blacklist","aw" ; \ | |
102 | @@ -92,24 +89,19 @@ | |
103 | .endm | |
104 | ||
105 | #else | |
106 | -# define _EXPAND_EXTABLE_HANDLE(x) #x | |
107 | -# define _ASM_EXTABLE_HANDLE(from, to, handler) \ | |
108 | +# define _ASM_EXTABLE(from,to) \ | |
109 | " .pushsection \"__ex_table\",\"a\"\n" \ | |
110 | - " .balign 4\n" \ | |
111 | + " .balign 8\n" \ | |
112 | " .long (" #from ") - .\n" \ | |
113 | " .long (" #to ") - .\n" \ | |
114 | - " .long (" _EXPAND_EXTABLE_HANDLE(handler) ") - .\n" \ | |
115 | " .popsection\n" | |
116 | ||
117 | -# define _ASM_EXTABLE(from, to) \ | |
118 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_default) | |
119 | - | |
120 | -# define _ASM_EXTABLE_FAULT(from, to) \ | |
121 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) | |
122 | - | |
123 | -# define _ASM_EXTABLE_EX(from, to) \ | |
124 | - _ASM_EXTABLE_HANDLE(from, to, ex_handler_ext) | |
125 | - | |
126 | +# define _ASM_EXTABLE_EX(from,to) \ | |
127 | + " .pushsection \"__ex_table\",\"a\"\n" \ | |
128 | + " .balign 8\n" \ | |
129 | + " .long (" #from ") - .\n" \ | |
130 | + " .long (" #to ") - . + 0x7ffffff0\n" \ | |
131 | + " .popsection\n" | |
132 | /* For C file, we already have NOKPROBE_SYMBOL macro */ | |
133 | #endif | |
134 | ||
135 | --- a/arch/x86/include/asm/uaccess.h | |
136 | +++ b/arch/x86/include/asm/uaccess.h | |
137 | @@ -90,11 +90,12 @@ static inline bool __chk_range_not_ok(un | |
138 | likely(!__range_not_ok(addr, size, user_addr_max())) | |
139 | ||
140 | /* | |
141 | - * The exception table consists of triples of addresses relative to the | |
142 | - * exception table entry itself. The first address is of an instruction | |
143 | - * that is allowed to fault, the second is the target at which the program | |
144 | - * should continue. The third is a handler function to deal with the fault | |
145 | - * caused by the instruction in the first field. | |
146 | + * The exception table consists of pairs of addresses relative to the | |
147 | + * exception table enty itself: the first is the address of an | |
148 | + * instruction that is allowed to fault, and the second is the address | |
149 | + * at which the program should continue. No registers are modified, | |
150 | + * so it is entirely up to the continuation code to figure out what to | |
151 | + * do. | |
152 | * | |
153 | * All the routines below use bits of fixup code that are out of line | |
154 | * with the main instruction path. This means when everything is well, | |
155 | @@ -103,14 +104,13 @@ static inline bool __chk_range_not_ok(un | |
156 | */ | |
157 | ||
158 | struct exception_table_entry { | |
159 | - int insn, fixup, handler; | |
160 | + int insn, fixup; | |
161 | }; | |
162 | /* This is not the generic standard exception_table_entry format */ | |
163 | #define ARCH_HAS_SORT_EXTABLE | |
164 | #define ARCH_HAS_SEARCH_EXTABLE | |
165 | ||
166 | -extern int fixup_exception(struct pt_regs *regs, int trapnr); | |
167 | -extern bool ex_has_fault_handler(unsigned long ip); | |
168 | +extern int fixup_exception(struct pt_regs *regs); | |
169 | extern int early_fixup_exception(unsigned long *ip); | |
170 | ||
171 | /* | |
172 | --- a/arch/x86/kernel/kprobes/core.c | |
173 | +++ b/arch/x86/kernel/kprobes/core.c | |
174 | @@ -1000,7 +1000,7 @@ int kprobe_fault_handler(struct pt_regs | |
175 | * In case the user-specified fault handler returned | |
176 | * zero, try to fix up. | |
177 | */ | |
178 | - if (fixup_exception(regs, trapnr)) | |
179 | + if (fixup_exception(regs)) | |
180 | return 1; | |
181 | ||
182 | /* | |
183 | --- a/arch/x86/kernel/traps.c | |
184 | +++ b/arch/x86/kernel/traps.c | |
185 | @@ -199,7 +199,7 @@ do_trap_no_signal(struct task_struct *ts | |
186 | } | |
187 | ||
188 | if (!user_mode(regs)) { | |
189 | - if (!fixup_exception(regs, trapnr)) { | |
190 | + if (!fixup_exception(regs)) { | |
191 | tsk->thread.error_code = error_code; | |
192 | tsk->thread.trap_nr = trapnr; | |
193 | die(str, regs, error_code); | |
194 | @@ -453,7 +453,7 @@ do_general_protection(struct pt_regs *re | |
195 | ||
196 | tsk = current; | |
197 | if (!user_mode(regs)) { | |
198 | - if (fixup_exception(regs, X86_TRAP_GP)) | |
199 | + if (fixup_exception(regs)) | |
200 | return; | |
201 | ||
202 | tsk->thread.error_code = error_code; | |
203 | @@ -699,7 +699,7 @@ static void math_error(struct pt_regs *r | |
204 | conditional_sti(regs); | |
205 | ||
206 | if (!user_mode(regs)) { | |
207 | - if (!fixup_exception(regs, trapnr)) { | |
208 | + if (!fixup_exception(regs)) { | |
209 | task->thread.error_code = error_code; | |
210 | task->thread.trap_nr = trapnr; | |
211 | die(str, regs, error_code); | |
212 | --- a/arch/x86/mm/extable.c | |
213 | +++ b/arch/x86/mm/extable.c | |
214 | @@ -3,9 +3,6 @@ | |
215 | #include <linux/sort.h> | |
216 | #include <asm/uaccess.h> | |
217 | ||
218 | -typedef bool (*ex_handler_t)(const struct exception_table_entry *, | |
219 | - struct pt_regs *, int); | |
220 | - | |
221 | static inline unsigned long | |
222 | ex_insn_addr(const struct exception_table_entry *x) | |
223 | { | |
224 | @@ -16,56 +13,11 @@ ex_fixup_addr(const struct exception_tab | |
225 | { | |
226 | return (unsigned long)&x->fixup + x->fixup; | |
227 | } | |
228 | -static inline ex_handler_t | |
229 | -ex_fixup_handler(const struct exception_table_entry *x) | |
230 | -{ | |
231 | - return (ex_handler_t)((unsigned long)&x->handler + x->handler); | |
232 | -} | |
233 | - | |
234 | -bool ex_handler_default(const struct exception_table_entry *fixup, | |
235 | - struct pt_regs *regs, int trapnr) | |
236 | -{ | |
237 | - regs->ip = ex_fixup_addr(fixup); | |
238 | - return true; | |
239 | -} | |
240 | -EXPORT_SYMBOL(ex_handler_default); | |
241 | - | |
242 | -bool ex_handler_fault(const struct exception_table_entry *fixup, | |
243 | - struct pt_regs *regs, int trapnr) | |
244 | -{ | |
245 | - regs->ip = ex_fixup_addr(fixup); | |
246 | - regs->ax = trapnr; | |
247 | - return true; | |
248 | -} | |
249 | -EXPORT_SYMBOL_GPL(ex_handler_fault); | |
250 | - | |
251 | -bool ex_handler_ext(const struct exception_table_entry *fixup, | |
252 | - struct pt_regs *regs, int trapnr) | |
253 | -{ | |
254 | - /* Special hack for uaccess_err */ | |
255 | - current_thread_info()->uaccess_err = 1; | |
256 | - regs->ip = ex_fixup_addr(fixup); | |
257 | - return true; | |
258 | -} | |
259 | -EXPORT_SYMBOL(ex_handler_ext); | |
260 | ||
261 | -bool ex_has_fault_handler(unsigned long ip) | |
262 | +int fixup_exception(struct pt_regs *regs) | |
263 | { | |
264 | - const struct exception_table_entry *e; | |
265 | - ex_handler_t handler; | |
266 | - | |
267 | - e = search_exception_tables(ip); | |
268 | - if (!e) | |
269 | - return false; | |
270 | - handler = ex_fixup_handler(e); | |
271 | - | |
272 | - return handler == ex_handler_fault; | |
273 | -} | |
274 | - | |
275 | -int fixup_exception(struct pt_regs *regs, int trapnr) | |
276 | -{ | |
277 | - const struct exception_table_entry *e; | |
278 | - ex_handler_t handler; | |
279 | + const struct exception_table_entry *fixup; | |
280 | + unsigned long new_ip; | |
281 | ||
282 | #ifdef CONFIG_PNPBIOS | |
283 | if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { | |
284 | @@ -81,34 +33,42 @@ int fixup_exception(struct pt_regs *regs | |
285 | } | |
286 | #endif | |
287 | ||
288 | - e = search_exception_tables(regs->ip); | |
289 | - if (!e) | |
290 | - return 0; | |
291 | + fixup = search_exception_tables(regs->ip); | |
292 | + if (fixup) { | |
293 | + new_ip = ex_fixup_addr(fixup); | |
294 | + | |
295 | + if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) { | |
296 | + /* Special hack for uaccess_err */ | |
297 | + current_thread_info()->uaccess_err = 1; | |
298 | + new_ip -= 0x7ffffff0; | |
299 | + } | |
300 | + regs->ip = new_ip; | |
301 | + return 1; | |
302 | + } | |
303 | ||
304 | - handler = ex_fixup_handler(e); | |
305 | - return handler(e, regs, trapnr); | |
306 | + return 0; | |
307 | } | |
308 | ||
309 | /* Restricted version used during very early boot */ | |
310 | int __init early_fixup_exception(unsigned long *ip) | |
311 | { | |
312 | - const struct exception_table_entry *e; | |
313 | + const struct exception_table_entry *fixup; | |
314 | unsigned long new_ip; | |
315 | - ex_handler_t handler; | |
316 | - | |
317 | - e = search_exception_tables(*ip); | |
318 | - if (!e) | |
319 | - return 0; | |
320 | ||
321 | - new_ip = ex_fixup_addr(e); | |
322 | - handler = ex_fixup_handler(e); | |
323 | + fixup = search_exception_tables(*ip); | |
324 | + if (fixup) { | |
325 | + new_ip = ex_fixup_addr(fixup); | |
326 | + | |
327 | + if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) { | |
328 | + /* uaccess handling not supported during early boot */ | |
329 | + return 0; | |
330 | + } | |
331 | ||
332 | - /* special handling not supported during early boot */ | |
333 | - if (handler != ex_handler_default) | |
334 | - return 0; | |
335 | + *ip = new_ip; | |
336 | + return 1; | |
337 | + } | |
338 | ||
339 | - *ip = new_ip; | |
340 | - return 1; | |
341 | + return 0; | |
342 | } | |
343 | ||
344 | /* | |
345 | @@ -173,8 +133,6 @@ void sort_extable(struct exception_table | |
346 | i += 4; | |
347 | p->fixup += i; | |
348 | i += 4; | |
349 | - p->handler += i; | |
350 | - i += 4; | |
351 | } | |
352 | ||
353 | sort(start, finish - start, sizeof(struct exception_table_entry), | |
354 | @@ -187,8 +145,6 @@ void sort_extable(struct exception_table | |
355 | i += 4; | |
356 | p->fixup -= i; | |
357 | i += 4; | |
358 | - p->handler -= i; | |
359 | - i += 4; | |
360 | } | |
361 | } | |
362 | ||
363 | --- a/arch/x86/mm/fault.c | |
364 | +++ b/arch/x86/mm/fault.c | |
365 | @@ -663,7 +663,7 @@ no_context(struct pt_regs *regs, unsigne | |
366 | int sig; | |
367 | ||
368 | /* Are we prepared to handle this kernel fault? */ | |
369 | - if (fixup_exception(regs, X86_TRAP_PF)) { | |
370 | + if (fixup_exception(regs)) { | |
371 | /* | |
372 | * Any interrupt that takes a fault gets the fixup. This makes | |
373 | * the below recursive fault logic only apply to a faults from | |
374 | --- a/scripts/sortextable.c | |
375 | +++ b/scripts/sortextable.c | |
376 | @@ -209,35 +209,6 @@ static int compare_relative_table(const | |
377 | return 0; | |
378 | } | |
379 | ||
380 | -static void x86_sort_relative_table(char *extab_image, int image_size) | |
381 | -{ | |
382 | - int i; | |
383 | - | |
384 | - i = 0; | |
385 | - while (i < image_size) { | |
386 | - uint32_t *loc = (uint32_t *)(extab_image + i); | |
387 | - | |
388 | - w(r(loc) + i, loc); | |
389 | - w(r(loc + 1) + i + 4, loc + 1); | |
390 | - w(r(loc + 2) + i + 8, loc + 2); | |
391 | - | |
392 | - i += sizeof(uint32_t) * 3; | |
393 | - } | |
394 | - | |
395 | - qsort(extab_image, image_size / 12, 12, compare_relative_table); | |
396 | - | |
397 | - i = 0; | |
398 | - while (i < image_size) { | |
399 | - uint32_t *loc = (uint32_t *)(extab_image + i); | |
400 | - | |
401 | - w(r(loc) - i, loc); | |
402 | - w(r(loc + 1) - (i + 4), loc + 1); | |
403 | - w(r(loc + 2) - (i + 8), loc + 2); | |
404 | - | |
405 | - i += sizeof(uint32_t) * 3; | |
406 | - } | |
407 | -} | |
408 | - | |
409 | static void sort_relative_table(char *extab_image, int image_size) | |
410 | { | |
411 | int i; | |
412 | @@ -310,9 +281,6 @@ do_file(char const *const fname) | |
413 | break; | |
414 | case EM_386: | |
415 | case EM_X86_64: | |
416 | - custom_sort = x86_sort_relative_table; | |
417 | - break; | |
418 | - | |
419 | case EM_S390: | |
420 | custom_sort = sort_relative_table; | |
421 | break; |