[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250507122820.41356-1-xieyuanbin1@huawei.com>
Date: Wed, 7 May 2025 20:28:20 +0800
From: Xie Yuanbin <xieyuanbin1@...wei.com>
To: <linux@...linux.org.uk>, <rmk+kernel@...linux.org.uk>, <kees@...nel.org>,
<yangyj.ee@...il.com>, <ardb@...nel.org>, <tony@...mide.com>,
<xieyuanbin1@...wei.com>
CC: <linux-arm-kernel@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
<will@...nel.org>, <nixiaoming@...wei.com>, <liaohua4@...wei.com>,
<wangbing6@...wei.com>, <lincheng8@...wei.com>, <wangfangpeng1@...wei.com>
Subject: [RFC PATCH] ARM: spectre-v2: fix the spectre operation that may be bypassed
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@...wei.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
Powered by blists - more mailing lists