From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: stable@vger.kernel.org
Cc: Bryan Brattlof <bb@ti.com>,
Daniel Wagner <daniel.wagner@monom.org>,
Jan Kiszka <jan.kiszka@siemens.com>,
cip-dev@lists.cip-project.org,
nobuhiro.iwamatsu.x90@mail.toshiba, pavel@nabladev.com,
Russell King <rmk+kernel@armlinux.org.uk>,
Xie Yuanbin <xieyuanbin1@huawei.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Subject: [PATCH 4/4] ARM: fix branch predictor hardening
Date: Mon, 22 Jun 2026 12:26:34 +0200 [thread overview]
Message-ID: <20260622102634.780100-5-bigeasy@linutronix.de> (raw)
In-Reply-To: <20260622102634.780100-1-bigeasy@linutronix.de>
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
commit fd2dee1c6e2256f726ba33fd3083a7be0efc80d3 upstream.
__do_user_fault() may be called with indeterminent interrupt enable
state, which means we may be preemptive at this point. This causes
problems when calling harden_branch_predictor(). For example, when
called from a data abort, do_alignment_fault()->do_bad_area().
Move harden_branch_predictor() out of __do_user_fault() and into the
calling contexts.
Moving it into do_kernel_address_page_fault(), we can be sure that
interrupts will be disabled here.
Converting do_translation_fault() to use do_kernel_address_page_fault()
rather than do_bad_area() means that we keep branch predictor handling
for translation faults. Interrupts will also be disabled at this call
site.
do_sect_fault() needs special handling, so detect user mode accesses
to kernel-addresses, and add an explicit call to branch predictor
hardening.
Finally, add branch predictor hardening to do_alignment() for the
faulting case (user mode accessing kernel addresses) before interrupts
are enabled.
This should cover all cases where harden_branch_predictor() is called,
ensuring that it is always has interrupts disabled, also ensuring that
it is called early in each call path.
Reviewed-by: Xie Yuanbin <xieyuanbin1@huawei.com>
Tested-by: Xie Yuanbin <xieyuanbin1@huawei.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
arch/arm/mm/alignment.c | 4 ++++
arch/arm/mm/fault.c | 39 ++++++++++++++++++++++++++-------------
2 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index f8dd0b3cc8e04..ee264737be6d2 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -22,6 +22,7 @@
#include <asm/cp15.h>
#include <asm/system_info.h>
+#include <asm/system_misc.h>
#include <asm/unaligned.h>
#include <asm/opcodes.h>
@@ -809,6 +810,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
int thumb2_32b = 0;
int fault;
+ if (addr >= TASK_SIZE && user_mode(regs))
+ harden_branch_predictor();
+
if (interrupts_enabled(regs))
local_irq_enable();
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 47eecdf29a831..87ed5da30e44f 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -199,9 +199,6 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
{
struct task_struct *tsk = current;
- if (addr > TASK_SIZE)
- harden_branch_predictor();
-
#ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
@@ -252,8 +249,10 @@ do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,
/*
* Fault from user mode for a kernel space address. User mode
* should not be faulting in kernel space, which includes the
- * vector/khelper page. Send a SIGSEGV.
+ * vector/khelper page. Handle the branch predictor hardening
+ * while interrupts are still disabled, then send a SIGSEGV.
*/
+ harden_branch_predictor();
__do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
} else {
/*
@@ -423,16 +422,20 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* We enter here because the first level page table doesn't contain
* a valid entry for the address.
*
- * If the address is in kernel space (>= TASK_SIZE), then we are
- * probably faulting in the vmalloc() area.
+ * If this is a user address (addr < TASK_SIZE), we handle this as a
+ * normal page fault. This leaves the remainder of the function to handle
+ * kernel address translation faults.
*
- * If the init_task's first level page tables contains the relevant
- * entry, we copy the it to this task. If not, we send the process
- * a signal, fixup the exception, or oops the kernel.
+ * Since user mode is not permitted to access kernel addresses, pass these
+ * directly to do_kernel_address_page_fault() to handle.
*
- * NOTE! We MUST NOT take any locks for this case. We may be in an
- * interrupt or a critical region, and should only copy the information
- * from the master page table, nothing more.
+ * Otherwise, we're probably faulting in the vmalloc() area, so try to fix
+ * that up. Note that we must not take any locks or enable interrupts in
+ * this case.
+ *
+ * If vmalloc() fixup fails, that means the non-leaf page tables did not
+ * contain an entry for this address, so handle this via
+ * do_kernel_address_page_fault().
*/
#ifdef CONFIG_MMU
static int __kprobes
@@ -498,7 +501,8 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
return 0;
bad_area:
- do_bad_area(addr, fsr, regs);
+ do_kernel_address_page_fault(current->mm, addr, fsr, regs);
+
return 0;
}
#else /* CONFIG_MMU */
@@ -518,7 +522,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
+ /*
+ * If this is a kernel address, but from user mode, then userspace
+ * is trying bad stuff. Invoke the branch predictor handling.
+ * Interrupts are disabled here.
+ */
+ if (addr >= TASK_SIZE && user_mode(regs))
+ harden_branch_predictor();
+
do_bad_area(addr, fsr, regs);
+
return 0;
}
#endif /* CONFIG_ARM_LPAE */
--
2.53.0
next prev parent reply other threads:[~2026-06-22 14:35 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-22 10:26 [PATCH 0/4] ARM: v6.6 and v6.1 stable backports Sebastian Andrzej Siewior
2026-06-22 10:26 ` [PATCH 1/4] ARM: group is_permission_fault() with is_translation_fault() Sebastian Andrzej Siewior
2026-06-22 10:26 ` [PATCH 2/4] ARM: allow __do_kernel_fault() to report execution of memory faults Sebastian Andrzej Siewior
2026-06-22 10:26 ` [PATCH 3/4] ARM: fix hash_name() fault Sebastian Andrzej Siewior
2026-06-22 10:26 ` Sebastian Andrzej Siewior [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-05-11 13:53 [PATCH 0/4] ARM: stable backports Sebastian Andrzej Siewior
2026-05-11 13:53 ` [PATCH 4/4] ARM: fix branch predictor hardening Sebastian Andrzej Siewior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260622102634.780100-5-bigeasy@linutronix.de \
--to=bigeasy@linutronix.de \
--cc=bb@ti.com \
--cc=cip-dev@lists.cip-project.org \
--cc=daniel.wagner@monom.org \
--cc=jan.kiszka@siemens.com \
--cc=nobuhiro.iwamatsu.x90@mail.toshiba \
--cc=pavel@nabladev.com \
--cc=rmk+kernel@armlinux.org.uk \
--cc=stable@vger.kernel.org \
--cc=xieyuanbin1@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox