FROMLIST: arm: Invalidate BTB on prefetch abort outside of user mapping on Cortex A8, A9, A12 and A17
In order to prevent aliasing attacks on the branch predictor, invalidate the BTB on CPUs that are known to be affected when taking a prefetch abort on a address that is outside of a user task limit. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> (cherry picked from git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git kpti commit a07373c8c365746583f25f49fee41b1bc0ff94b2) CVE-2017-5715 Signed-off-by: Tao Huang <huangtao@rock-chips.com> Change-Id: Ibc33f2f58ab8ba6b92ed64c0ea4d967e089fa584
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system_misc.h>
|
||||
@@ -181,6 +183,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
||||
si.si_errno = 0;
|
||||
si.si_code = code;
|
||||
si.si_addr = (void __user *)addr;
|
||||
|
||||
force_sig_info(sig, &si, tsk);
|
||||
}
|
||||
|
||||
@@ -393,12 +396,35 @@ no_context:
|
||||
__do_kernel_fault(mm, addr, fsr, regs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
{
|
||||
if (addr > TASK_SIZE) {
|
||||
switch(read_cpuid_part()) {
|
||||
case ARM_CPU_PART_CORTEX_A8:
|
||||
case ARM_CPU_PART_CORTEX_A9:
|
||||
case ARM_CPU_PART_CORTEX_A12:
|
||||
case ARM_CPU_PART_CORTEX_A17:
|
||||
asm volatile("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return do_page_fault(addr, fsr, regs);
|
||||
}
|
||||
#else /* CONFIG_MMU */
|
||||
static int
|
||||
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
/*
|
||||
|
||||
@@ -50,7 +50,7 @@ static struct fsr_info ifsr_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "unknown 4" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
|
||||
{ do_bad, SIGBUS, 0, "external abort on non-linefetch" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 10" },
|
||||
@@ -58,7 +58,7 @@ static struct fsr_info ifsr_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "external abort on translation" },
|
||||
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
|
||||
{ do_bad, SIGBUS, 0, "external abort on translation" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 16" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 17" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 18" },
|
||||
|
||||
@@ -65,4 +65,69 @@ static struct fsr_info fsr_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "unknown 63" },
|
||||
};
|
||||
|
||||
#define ifsr_info fsr_info
|
||||
static struct fsr_info ifsr_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "unknown 0" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 1" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 2" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 3" },
|
||||
{ do_bad, SIGBUS, 0, "reserved translation fault" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
|
||||
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
|
||||
{ do_bad, SIGBUS, 0, "reserved permission fault" },
|
||||
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
|
||||
{ do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort" },
|
||||
{ do_bad, SIGBUS, 0, "asynchronous external abort" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 18" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 19" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error" },
|
||||
{ do_bad, SIGBUS, 0, "asynchronous parity error" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 26" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 27" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 32" },
|
||||
{ do_bad, SIGBUS, BUS_ADRALN, "alignment fault" },
|
||||
{ do_bad, SIGBUS, 0, "debug event" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 35" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 36" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 37" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 38" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 39" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 40" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 41" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 42" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 43" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 44" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 45" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 46" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 47" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 48" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 49" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 50" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 51" },
|
||||
{ do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 53" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 54" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 55" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 56" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 57" },
|
||||
{ do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 59" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 60" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 61" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 62" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 63" },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user