aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/extable.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/extable.c')
-rw-r--r--arch/x86/mm/extable.c114
1 files changed, 100 insertions, 14 deletions
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 45f5d6cf65ae..6521134057e8 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -8,7 +8,8 @@
8#include <asm/kdebug.h> 8#include <asm/kdebug.h>
9 9
10typedef bool (*ex_handler_t)(const struct exception_table_entry *, 10typedef bool (*ex_handler_t)(const struct exception_table_entry *,
11 struct pt_regs *, int); 11 struct pt_regs *, int, unsigned long,
12 unsigned long);
12 13
13static inline unsigned long 14static inline unsigned long
14ex_fixup_addr(const struct exception_table_entry *x) 15ex_fixup_addr(const struct exception_table_entry *x)
@@ -22,7 +23,9 @@ ex_fixup_handler(const struct exception_table_entry *x)
22} 23}
23 24
24__visible bool ex_handler_default(const struct exception_table_entry *fixup, 25__visible bool ex_handler_default(const struct exception_table_entry *fixup,
25 struct pt_regs *regs, int trapnr) 26 struct pt_regs *regs, int trapnr,
27 unsigned long error_code,
28 unsigned long fault_addr)
26{ 29{
27 regs->ip = ex_fixup_addr(fixup); 30 regs->ip = ex_fixup_addr(fixup);
28 return true; 31 return true;
@@ -30,7 +33,9 @@ __visible bool ex_handler_default(const struct exception_table_entry *fixup,
30EXPORT_SYMBOL(ex_handler_default); 33EXPORT_SYMBOL(ex_handler_default);
31 34
32__visible bool ex_handler_fault(const struct exception_table_entry *fixup, 35__visible bool ex_handler_fault(const struct exception_table_entry *fixup,
33 struct pt_regs *regs, int trapnr) 36 struct pt_regs *regs, int trapnr,
37 unsigned long error_code,
38 unsigned long fault_addr)
34{ 39{
35 regs->ip = ex_fixup_addr(fixup); 40 regs->ip = ex_fixup_addr(fixup);
36 regs->ax = trapnr; 41 regs->ax = trapnr;
@@ -43,7 +48,9 @@ EXPORT_SYMBOL_GPL(ex_handler_fault);
43 * result of a refcount inc/dec/add/sub. 48 * result of a refcount inc/dec/add/sub.
44 */ 49 */
45__visible bool ex_handler_refcount(const struct exception_table_entry *fixup, 50__visible bool ex_handler_refcount(const struct exception_table_entry *fixup,
46 struct pt_regs *regs, int trapnr) 51 struct pt_regs *regs, int trapnr,
52 unsigned long error_code,
53 unsigned long fault_addr)
47{ 54{
48 /* First unconditionally saturate the refcount. */ 55 /* First unconditionally saturate the refcount. */
49 *(int *)regs->cx = INT_MIN / 2; 56 *(int *)regs->cx = INT_MIN / 2;
@@ -96,7 +103,9 @@ EXPORT_SYMBOL(ex_handler_refcount);
96 * out all the FPU registers) if we can't restore from the task's FPU state. 103 * out all the FPU registers) if we can't restore from the task's FPU state.
97 */ 104 */
98__visible bool ex_handler_fprestore(const struct exception_table_entry *fixup, 105__visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
99 struct pt_regs *regs, int trapnr) 106 struct pt_regs *regs, int trapnr,
107 unsigned long error_code,
108 unsigned long fault_addr)
100{ 109{
101 regs->ip = ex_fixup_addr(fixup); 110 regs->ip = ex_fixup_addr(fixup);
102 111
@@ -108,9 +117,79 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
108} 117}
109EXPORT_SYMBOL_GPL(ex_handler_fprestore); 118EXPORT_SYMBOL_GPL(ex_handler_fprestore);
110 119
120/* Helper to check whether a uaccess fault indicates a kernel bug. */
121static bool bogus_uaccess(struct pt_regs *regs, int trapnr,
122 unsigned long fault_addr)
123{
124 /* This is the normal case: #PF with a fault address in userspace. */
125 if (trapnr == X86_TRAP_PF && fault_addr < TASK_SIZE_MAX)
126 return false;
127
128 /*
129 * This code can be reached for machine checks, but only if the #MC
130 * handler has already decided that it looks like a candidate for fixup.
131 * This e.g. happens when attempting to access userspace memory which
132 * the CPU can't access because of uncorrectable bad memory.
133 */
134 if (trapnr == X86_TRAP_MC)
135 return false;
136
137 /*
138 * There are two remaining exception types we might encounter here:
139 * - #PF for faulting accesses to kernel addresses
140 * - #GP for faulting accesses to noncanonical addresses
141 * Complain about anything else.
142 */
143 if (trapnr != X86_TRAP_PF && trapnr != X86_TRAP_GP) {
144 WARN(1, "unexpected trap %d in uaccess\n", trapnr);
145 return false;
146 }
147
148 /*
149 * This is a faulting memory access in kernel space, on a kernel
150 * address, in a usercopy function. This can e.g. be caused by improper
151 * use of helpers like __put_user and by improper attempts to access
152 * userspace addresses in KERNEL_DS regions.
153 * The one (semi-)legitimate exception are probe_kernel_{read,write}(),
154 * which can be invoked from places like kgdb, /dev/mem (for reading)
155 * and privileged BPF code (for reading).
156 * The probe_kernel_*() functions set the kernel_uaccess_faults_ok flag
157 * to tell us that faulting on kernel addresses, and even noncanonical
158 * addresses, in a userspace accessor does not necessarily imply a
159 * kernel bug, root might just be doing weird stuff.
160 */
161 if (current->kernel_uaccess_faults_ok)
162 return false;
163
164 /* This is bad. Refuse the fixup so that we go into die(). */
165 if (trapnr == X86_TRAP_PF) {
166 pr_emerg("BUG: pagefault on kernel address 0x%lx in non-whitelisted uaccess\n",
167 fault_addr);
168 } else {
169 pr_emerg("BUG: GPF in non-whitelisted uaccess (non-canonical address?)\n");
170 }
171 return true;
172}
173
174__visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
175 struct pt_regs *regs, int trapnr,
176 unsigned long error_code,
177 unsigned long fault_addr)
178{
179 if (bogus_uaccess(regs, trapnr, fault_addr))
180 return false;
181 regs->ip = ex_fixup_addr(fixup);
182 return true;
183}
184EXPORT_SYMBOL(ex_handler_uaccess);
185
111__visible bool ex_handler_ext(const struct exception_table_entry *fixup, 186__visible bool ex_handler_ext(const struct exception_table_entry *fixup,
112 struct pt_regs *regs, int trapnr) 187 struct pt_regs *regs, int trapnr,
188 unsigned long error_code,
189 unsigned long fault_addr)
113{ 190{
191 if (bogus_uaccess(regs, trapnr, fault_addr))
192 return false;
114 /* Special hack for uaccess_err */ 193 /* Special hack for uaccess_err */
115 current->thread.uaccess_err = 1; 194 current->thread.uaccess_err = 1;
116 regs->ip = ex_fixup_addr(fixup); 195 regs->ip = ex_fixup_addr(fixup);
@@ -119,7 +198,9 @@ __visible bool ex_handler_ext(const struct exception_table_entry *fixup,
119EXPORT_SYMBOL(ex_handler_ext); 198EXPORT_SYMBOL(ex_handler_ext);
120 199
121__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup, 200__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
122 struct pt_regs *regs, int trapnr) 201 struct pt_regs *regs, int trapnr,
202 unsigned long error_code,
203 unsigned long fault_addr)
123{ 204{
124 if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n", 205 if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n",
125 (unsigned int)regs->cx, regs->ip, (void *)regs->ip)) 206 (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
@@ -134,7 +215,9 @@ __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup
134EXPORT_SYMBOL(ex_handler_rdmsr_unsafe); 215EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
135 216
136__visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup, 217__visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
137 struct pt_regs *regs, int trapnr) 218 struct pt_regs *regs, int trapnr,
219 unsigned long error_code,
220 unsigned long fault_addr)
138{ 221{
139 if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n", 222 if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n",
140 (unsigned int)regs->cx, (unsigned int)regs->dx, 223 (unsigned int)regs->cx, (unsigned int)regs->dx,
@@ -148,12 +231,14 @@ __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup
148EXPORT_SYMBOL(ex_handler_wrmsr_unsafe); 231EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
149 232
150__visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup, 233__visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
151 struct pt_regs *regs, int trapnr) 234 struct pt_regs *regs, int trapnr,
235 unsigned long error_code,
236 unsigned long fault_addr)
152{ 237{
153 if (static_cpu_has(X86_BUG_NULL_SEG)) 238 if (static_cpu_has(X86_BUG_NULL_SEG))
154 asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS)); 239 asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
155 asm volatile ("mov %0, %%fs" : : "rm" (0)); 240 asm volatile ("mov %0, %%fs" : : "rm" (0));
156 return ex_handler_default(fixup, regs, trapnr); 241 return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
157} 242}
158EXPORT_SYMBOL(ex_handler_clear_fs); 243EXPORT_SYMBOL(ex_handler_clear_fs);
159 244
@@ -170,7 +255,8 @@ __visible bool ex_has_fault_handler(unsigned long ip)
170 return handler == ex_handler_fault; 255 return handler == ex_handler_fault;
171} 256}
172 257
173int fixup_exception(struct pt_regs *regs, int trapnr) 258int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
259 unsigned long fault_addr)
174{ 260{
175 const struct exception_table_entry *e; 261 const struct exception_table_entry *e;
176 ex_handler_t handler; 262 ex_handler_t handler;
@@ -194,7 +280,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr)
194 return 0; 280 return 0;
195 281
196 handler = ex_fixup_handler(e); 282 handler = ex_fixup_handler(e);
197 return handler(e, regs, trapnr); 283 return handler(e, regs, trapnr, error_code, fault_addr);
198} 284}
199 285
200extern unsigned int early_recursion_flag; 286extern unsigned int early_recursion_flag;
@@ -230,9 +316,9 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
230 * result in a hard-to-debug panic. 316 * result in a hard-to-debug panic.
231 * 317 *
232 * Keep in mind that not all vectors actually get here. Early 318 * Keep in mind that not all vectors actually get here. Early
233 * fage faults, for example, are special. 319 * page faults, for example, are special.
234 */ 320 */
235 if (fixup_exception(regs, trapnr)) 321 if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
236 return; 322 return;
237 323
238 if (fixup_bug(regs, trapnr)) 324 if (fixup_bug(regs, trapnr))