x86/fault: Improve kernel-executing-user-memory handling
Right now, the case of the kernel trying to execute from user memory is treated more or less just like the kernel getting a page fault on a user access. In the failure path, it checks for erratum #93, tries to otherwise fix up the error, and then oopses. If it manages to jump to the user address space, with or without SMEP, it should not try to resolve the page fault. This is an error, pure and simple. Rearrange the code so that this case is caught early, check for erratum #93, and bail out. [ bp: Massage commit message. ] Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/ab8719c7afb8bd501c4eee0e36493150fbbe5f6a.1612924255.git.luto@kernel.org
This commit is contained in:
Родитель
56e62cd28a
Коммит
03c81ea333
|
@ -447,6 +447,9 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
|
||||||
|| boot_cpu_data.x86 != 0xf)
|
|| boot_cpu_data.x86 != 0xf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (user_mode(regs))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (address != regs->ip)
|
if (address != regs->ip)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -744,9 +747,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
||||||
if (is_prefetch(regs, error_code, address))
|
if (is_prefetch(regs, error_code, address))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (is_errata93(regs, address))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buggy firmware could access regions which might page fault, try to
|
* Buggy firmware could access regions which might page fault, try to
|
||||||
* recover from such faults.
|
* recover from such faults.
|
||||||
|
@ -1239,6 +1239,21 @@ void do_user_addr_fault(struct pt_regs *regs,
|
||||||
tsk = current;
|
tsk = current;
|
||||||
mm = tsk->mm;
|
mm = tsk->mm;
|
||||||
|
|
||||||
|
if (unlikely((error_code & (X86_PF_USER | X86_PF_INSTR)) == X86_PF_INSTR)) {
|
||||||
|
/*
|
||||||
|
* Whoops, this is kernel mode code trying to execute from
|
||||||
|
* user memory. Unless this is AMD erratum #93, which
|
||||||
|
* corrupts RIP such that it looks like a user address,
|
||||||
|
* this is unrecoverable. Don't even try to look up the
|
||||||
|
* VMA.
|
||||||
|
*/
|
||||||
|
if (is_errata93(regs, address))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bad_area_nosemaphore(regs, error_code, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* kprobes don't want to hook the spurious faults: */
|
/* kprobes don't want to hook the spurious faults: */
|
||||||
if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF)))
|
if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF)))
|
||||||
return;
|
return;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче