Merge tag 'drivers-5.10-2020-10-12' of git://git.kernel.dk/linux-block
[linux-2.6-block.git] / arch / x86 / mm / extable.c
CommitLineData
457c8996 1// SPDX-License-Identifier: GPL-2.0-only
744c193e 2#include <linux/extable.h>
7c0f6ba6 3#include <linux/uaccess.h>
b17b0153 4#include <linux/sched/debug.h>
42b3a4cb 5#include <xen/xen.h>
b17b0153 6
d5c8028b 7#include <asm/fpu/internal.h>
0d0efc07 8#include <asm/traps.h>
81c2949f 9#include <asm/kdebug.h>
6d48583b 10
548acf19 11typedef bool (*ex_handler_t)(const struct exception_table_entry *,
81fd9c18
JH
12 struct pt_regs *, int, unsigned long,
13 unsigned long);
548acf19 14
70627654
PA
15static inline unsigned long
16ex_fixup_addr(const struct exception_table_entry *x)
17{
18 return (unsigned long)&x->fixup + x->fixup;
19}
548acf19
TL
20static inline ex_handler_t
21ex_fixup_handler(const struct exception_table_entry *x)
22{
23 return (ex_handler_t)((unsigned long)&x->handler + x->handler);
24}
6d48583b 25
80a3e394 26__visible bool ex_handler_default(const struct exception_table_entry *fixup,
81fd9c18
JH
27 struct pt_regs *regs, int trapnr,
28 unsigned long error_code,
29 unsigned long fault_addr)
6d48583b 30{
548acf19
TL
31 regs->ip = ex_fixup_addr(fixup);
32 return true;
33}
34EXPORT_SYMBOL(ex_handler_default);
35
80a3e394 36__visible bool ex_handler_fault(const struct exception_table_entry *fixup,
81fd9c18
JH
37 struct pt_regs *regs, int trapnr,
38 unsigned long error_code,
39 unsigned long fault_addr)
548acf19
TL
40{
41 regs->ip = ex_fixup_addr(fixup);
42 regs->ax = trapnr;
43 return true;
44}
45EXPORT_SYMBOL_GPL(ex_handler_fault);
46
d5c8028b
EB
47/*
48 * Handler for when we fail to restore a task's FPU state. We should never get
49 * here because the FPU state of a task using the FPU (task->thread.fpu.state)
50 * should always be valid. However, past bugs have allowed userspace to set
51 * reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn().
52 * These caused XRSTOR to fail when switching to the task, leaking the FPU
53 * registers of the task previously executing on the CPU. Mitigate this class
54 * of vulnerability by restoring from the initial state (essentially, zeroing
55 * out all the FPU registers) if we can't restore from the task's FPU state.
56 */
80a3e394 57__visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
81fd9c18
JH
58 struct pt_regs *regs, int trapnr,
59 unsigned long error_code,
60 unsigned long fault_addr)
d5c8028b
EB
61{
62 regs->ip = ex_fixup_addr(fixup);
63
64 WARN_ONCE(1, "Bad FPU state detected at %pB, reinitializing FPU registers.",
65 (void *)instruction_pointer(regs));
66
67 __copy_kernel_to_fpregs(&init_fpstate, -1);
68 return true;
69}
70EXPORT_SYMBOL_GPL(ex_handler_fprestore);
71
75045f77 72__visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
81fd9c18
JH
73 struct pt_regs *regs, int trapnr,
74 unsigned long error_code,
75 unsigned long fault_addr)
75045f77 76{
00c42373 77 WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
75045f77
JH
78 regs->ip = ex_fixup_addr(fixup);
79 return true;
80}
81EXPORT_SYMBOL(ex_handler_uaccess);
82
278b917f
YS
83__visible bool ex_handler_copy(const struct exception_table_entry *fixup,
84 struct pt_regs *regs, int trapnr,
85 unsigned long error_code,
86 unsigned long fault_addr)
87{
88 WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
89 regs->ip = ex_fixup_addr(fixup);
90 regs->ax = trapnr;
91 return true;
92}
93EXPORT_SYMBOL(ex_handler_copy);
94
80a3e394 95__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
81fd9c18
JH
96 struct pt_regs *regs, int trapnr,
97 unsigned long error_code,
98 unsigned long fault_addr)
fbd70437 99{
d75f773c 100 if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
81c2949f
BP
101 (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
102 show_stack_regs(regs);
fbd70437
AL
103
104 /* Pretend that the read succeeded and returned 0. */
105 regs->ip = ex_fixup_addr(fixup);
106 regs->ax = 0;
107 regs->dx = 0;
108 return true;
109}
110EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
111
80a3e394 112__visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
81fd9c18
JH
113 struct pt_regs *regs, int trapnr,
114 unsigned long error_code,
115 unsigned long fault_addr)
fbd70437 116{
d75f773c 117 if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
81c2949f
BP
118 (unsigned int)regs->cx, (unsigned int)regs->dx,
119 (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
120 show_stack_regs(regs);
fbd70437
AL
121
122 /* Pretend that the write succeeded. */
123 regs->ip = ex_fixup_addr(fixup);
124 return true;
125}
126EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
127
80a3e394 128__visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
81fd9c18
JH
129 struct pt_regs *regs, int trapnr,
130 unsigned long error_code,
131 unsigned long fault_addr)
45e876f7
AL
132{
133 if (static_cpu_has(X86_BUG_NULL_SEG))
134 asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
135 asm volatile ("mov %0, %%fs" : : "rm" (0));
81fd9c18 136 return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
45e876f7
AL
137}
138EXPORT_SYMBOL(ex_handler_clear_fs);
139
a05d54c4 140enum handler_type ex_get_fault_handler_type(unsigned long ip)
548acf19
TL
141{
142 const struct exception_table_entry *e;
143 ex_handler_t handler;
144
145 e = search_exception_tables(ip);
146 if (!e)
a05d54c4 147 return EX_HANDLER_NONE;
548acf19 148 handler = ex_fixup_handler(e);
a05d54c4
TL
149 if (handler == ex_handler_fault)
150 return EX_HANDLER_FAULT;
278b917f 151 else if (handler == ex_handler_uaccess || handler == ex_handler_copy)
a05d54c4
TL
152 return EX_HANDLER_UACCESS;
153 else
154 return EX_HANDLER_OTHER;
548acf19
TL
155}
156
81fd9c18
JH
157int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
158 unsigned long fault_addr)
548acf19
TL
159{
160 const struct exception_table_entry *e;
161 ex_handler_t handler;
6d48583b
HH
162
163#ifdef CONFIG_PNPBIOS
164 if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
165 extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
166 extern u32 pnp_bios_is_utter_crap;
167 pnp_bios_is_utter_crap = 1;
168 printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
169 __asm__ volatile(
170 "movl %0, %%esp\n\t"
171 "jmp *%1\n\t"
172 : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
173 panic("do_trap: can't hit this");
174 }
175#endif
176
548acf19
TL
177 e = search_exception_tables(regs->ip);
178 if (!e)
179 return 0;
6d48583b 180
548acf19 181 handler = ex_fixup_handler(e);
81fd9c18 182 return handler(e, regs, trapnr, error_code, fault_addr);
6d48583b 183}
6a1ea279 184
0e861fbb
AL
185extern unsigned int early_recursion_flag;
186
6a1ea279 187/* Restricted version used during very early boot */
0e861fbb 188void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
6a1ea279 189{
0d0efc07
AL
190 /* Ignore early NMIs. */
191 if (trapnr == X86_TRAP_NMI)
0e861fbb
AL
192 return;
193
194 if (early_recursion_flag > 2)
195 goto halt_loop;
196
fc0e81b2
AL
197 /*
198 * Old CPUs leave the high bits of CS on the stack
199 * undefined. I'm not sure which CPUs do this, but at least
200 * the 486 DX works this way.
42b3a4cb 201 * Xen pv domains are not using the default __KERNEL_CS.
fc0e81b2 202 */
42b3a4cb 203 if (!xen_pv_domain() && regs->cs != __KERNEL_CS)
0e861fbb 204 goto fail;
0d0efc07 205
60a0e203
AL
206 /*
207 * The full exception fixup machinery is available as soon as
208 * the early IDT is loaded. This means that it is the
209 * responsibility of extable users to either function correctly
210 * when handlers are invoked early or to simply avoid causing
211 * exceptions before they're ready to handle them.
212 *
213 * This is better than filtering which handlers can be used,
214 * because refusing to call a handler here is guaranteed to
215 * result in a hard-to-debug panic.
216 *
217 * Keep in mind that not all vectors actually get here. Early
81fd9c18 218 * page faults, for example, are special.
60a0e203 219 */
81fd9c18 220 if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
ae7ef45e 221 return;
0e861fbb 222
15a416e8
AL
223 if (trapnr == X86_TRAP_UD) {
224 if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
225 /* Skip the ud2. */
226 regs->ip += LEN_UD2;
227 return;
228 }
229
230 /*
231 * If this was a BUG and report_bug returns or if this
232 * was just a normal #UD, we want to continue onward and
233 * crash.
234 */
235 }
8a524f80 236
0e861fbb
AL
237fail:
238 early_printk("PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx\n",
239 (unsigned)trapnr, (unsigned long)regs->cs, regs->ip,
240 regs->orig_ax, read_cr2());
241
242 show_regs(regs);
243
244halt_loop:
245 while (true)
246 halt();
6a1ea279 247}