This patch was send by "Sebastian Andrzej Siewior <bige...@linutronix.de>" in [1] and rebase in v5.10-rc6.
The original commit message: > On non-LPAE systems a write to 0xbffffff0 (modules area) from userland > results in: > | BUG: using smp_processor_id() in preemptible [00000000] code: mem-tc/521 > | caller is __do_user_fault.constprop.2+0x4c/0x74 > | CPU: 1 PID: 521 Comm: mem-tc Not tainted 5.1.0-rc1 #4 > | [<c04614e4>] (debug_smp_processor_id) from [<c0116378>] > (__do_user_fault.constprop.2+0x4c/0x74) > | [<c0116378>] (__do_user_fault.constprop.2) from [<c011668c>] > (do_page_fault+0x278/0x37c) > | [<c011668c>] (do_page_fault) from [<c0116904>] (do_DataAbort+0x3c/0xa8) > | [<c0116904>] (do_DataAbort) from [<c0101e1c>] (__dabt_usr+0x3c/0x40) > > Move harden_branch_predictor() from __do_user_fault() to its both > callers (do_bad_area() and do_page_fault()). The invocation in > do_page_fault() is added before interrupst are enabled. The invocation > in do_bad_area() is added just before __do_user_fault() is invoked. The BUG still exists in v5.10-rc, and the previous disscussion was [2]. This issue can be easily reproduced in ARM with CONFIG_DEBUG_PREEMPT and CONFIG_HARDEN_BRANCH_PREDICTOR by the following userspace program: int *p = 0xffff3ff4; *p = 123; [1]: https://patchwork.kernel.org/project/linux-arm-kernel/patch/20190319203239.gl46fxnfz6gze...@linutronix.de/ [2]: https://lkml.org/lkml/2019/6/3/426 Fixes: f5fe12b1eaee2 ("ARM: spectre-v2: harden user aborts in kernel space") Reported-by: Bernd Edlinger <bernd.edlin...@hotmail.de> Signed-off-by: Sebastian Andrzej Siewior <bige...@linutronix.de> Signed-off-by: Lecopzer Chen <lecopzer.c...@mediatek.com> Cc: YJ Chiang <yj.chi...@mediatek.com> --- arch/arm/mm/fault.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index efa402025031..f1b57b7d5a0c 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -138,9 +138,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))) { @@ -173,8 +170,11 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) * If we are in kernel mode at this point, we * have no context to handle this fault with. */ - if (user_mode(regs)) + if (user_mode(regs)) { + if (addr > TASK_SIZE) + harden_branch_predictor(); __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs); + } else __do_kernel_fault(mm, addr, fsr, regs); } @@ -251,6 +251,9 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) tsk = current; mm = tsk->mm; + if (addr > TASK_SIZE && user_mode(regs)) + harden_branch_predictor(); + /* Enable interrupts if they were enabled in the parent context. */ if (interrupts_enabled(regs)) local_irq_enable(); -- 2.18.0