As discussed before, to completely fix this problem, we must do
the spectre operation after the user mode is trapped in the kernel
and before the interrupt is enabled.
I have tried to add a hook function and it in fsr_info to avoid
performance deterioration (The preceding example will trigger
"level 2 permission fault", which is cold code in normal cases).
However, this does not work. I find that the user program can
also trigger "translation fault" or "access flag fault"
when accessing a kernel address.
Therefore, extra performance overhead is inevitable.
(An if branch needs to be added before the interrupt is enabled.)
I have tried to reduce the impact on performance.
If the page fault comes from the user mode,
the interrupt must be enabled. In this case,
a judgment can be reduced.
Fixes: f5fe12b1eaee ("ARM: spectre-v2: harden user aborts in kernel space")
Signed-off-by: Xie Yuanbin <xieyuanbin1@huawei.com>
---
arch/arm/mm/fault.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index ab01b51de559..3425a12a8f52 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -272,25 +272,35 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (kprobe_page_fault(regs, fsr))
return 0;
/* Enable interrupts if they were enabled in the parent context. */
- if (interrupts_enabled(regs))
- local_irq_enable();
+ if (likely(user_mode(regs))) {
+ if (IS_ENABLED(CONFIG_PREEMPT) &&
+ IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR) &&
+ unlikely(addr >= TASK_SIZE)) {
+
+ __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+ return 0;
+ }
+
+ flags |= FAULT_FLAG_USER;
+ } else if (!interrupts_enabled(regs))
+ goto irq_disabled;
+
+ local_irq_enable();
+irq_disabled:
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
if (faulthandler_disabled() || !mm)
goto no_context;
- if (user_mode(regs))
- flags |= FAULT_FLAG_USER;
-
if (is_write_fault(fsr)) {
flags |= FAULT_FLAG_WRITE;
vm_flags = VM_WRITE;
}
if (fsr & FSR_LNX_PF) {
--
2.48.1