diff options
Diffstat (limited to 'arch/x86/mm/extable.c')
-rw-r--r-- | arch/x86/mm/extable.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index c076f710de4c..c3521e2be396 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/uaccess.h> | 2 | #include <linux/uaccess.h> |
3 | #include <linux/sched/debug.h> | 3 | #include <linux/sched/debug.h> |
4 | 4 | ||
5 | #include <asm/fpu/internal.h> | ||
5 | #include <asm/traps.h> | 6 | #include <asm/traps.h> |
6 | #include <asm/kdebug.h> | 7 | #include <asm/kdebug.h> |
7 | 8 | ||
@@ -78,6 +79,29 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup, | |||
78 | } | 79 | } |
79 | EXPORT_SYMBOL_GPL(ex_handler_refcount); | 80 | EXPORT_SYMBOL_GPL(ex_handler_refcount); |
80 | 81 | ||
82 | /* | ||
83 | * Handler for when we fail to restore a task's FPU state. We should never get | ||
84 | * here because the FPU state of a task using the FPU (task->thread.fpu.state) | ||
85 | * should always be valid. However, past bugs have allowed userspace to set | ||
86 | * reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn(). | ||
87 | * These caused XRSTOR to fail when switching to the task, leaking the FPU | ||
88 | * registers of the task previously executing on the CPU. Mitigate this class | ||
89 | * of vulnerability by restoring from the initial state (essentially, zeroing | ||
90 | * out all the FPU registers) if we can't restore from the task's FPU state. | ||
91 | */ | ||
92 | bool ex_handler_fprestore(const struct exception_table_entry *fixup, | ||
93 | struct pt_regs *regs, int trapnr) | ||
94 | { | ||
95 | regs->ip = ex_fixup_addr(fixup); | ||
96 | |||
97 | WARN_ONCE(1, "Bad FPU state detected at %pB, reinitializing FPU registers.", | ||
98 | (void *)instruction_pointer(regs)); | ||
99 | |||
100 | __copy_kernel_to_fpregs(&init_fpstate, -1); | ||
101 | return true; | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(ex_handler_fprestore); | ||
104 | |||
81 | bool ex_handler_ext(const struct exception_table_entry *fixup, | 105 | bool ex_handler_ext(const struct exception_table_entry *fixup, |
82 | struct pt_regs *regs, int trapnr) | 106 | struct pt_regs *regs, int trapnr) |
83 | { | 107 | { |