提交 26320b23 编写于 作者: W Will Deacon 提交者: Yang Yingliang

ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess watchpoints

commit eec13b42d41b0f3339dcf0c4da43734427c68620 upstream.

Unprivileged memory accesses generated by the so-called "translated"
instructions (e.g. LDRT) in kernel mode can cause user watchpoints to fire
unexpectedly. In such cases, the hw_breakpoint logic will invoke the user
overflow handler which will typically raise a SIGTRAP back to the current
task. This is futile when returning back to the kernel because (a) the
signal won't have been delivered and (b) userspace can't handle the thing
anyway.

Avoid invoking the user overflow handler for watchpoints triggered by
kernel uaccess routines, and instead single-step over the faulting
instruction as we would if no overflow handler had been installed.

Cc: <stable@vger.kernel.org>
Fixes: f81ef4a9 ("ARM: 6356/1: hw-breakpoint: add ARM backend for the hw-breakpoint framework")
Reported-by: NLuis Machado <luis.machado@linaro.org>
Tested-by: NLuis Machado <luis.machado@linaro.org>
Signed-off-by: NWill Deacon <will@kernel.org>
Signed-off-by: NRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 8d39d491
...@@ -688,6 +688,12 @@ static void disable_single_step(struct perf_event *bp) ...@@ -688,6 +688,12 @@ static void disable_single_step(struct perf_event *bp)
arch_install_hw_breakpoint(bp); arch_install_hw_breakpoint(bp);
} }
static int watchpoint_fault_on_uaccess(struct pt_regs *regs,
struct arch_hw_breakpoint *info)
{
return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER;
}
static void watchpoint_handler(unsigned long addr, unsigned int fsr, static void watchpoint_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs) struct pt_regs *regs)
{ {
...@@ -747,16 +753,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, ...@@ -747,16 +753,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
} }
pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
/*
* If we triggered a user watchpoint from a uaccess routine,
* then handle the stepping ourselves since userspace really
* can't help us with this.
*/
if (watchpoint_fault_on_uaccess(regs, info))
goto step;
perf_bp_event(wp, regs); perf_bp_event(wp, regs);
/* /*
* If no overflow handler is present, insert a temporary * Defer stepping to the overflow handler if one is installed.
* mismatch breakpoint so we can single-step over the * Otherwise, insert a temporary mismatch breakpoint so that
* watchpoint trigger. * we can single-step over the watchpoint trigger.
*/ */
if (is_default_overflow_handler(wp)) if (!is_default_overflow_handler(wp))
enable_single_step(wp, instruction_pointer(regs)); goto unlock;
step:
enable_single_step(wp, instruction_pointer(regs));
unlock: unlock:
rcu_read_unlock(); rcu_read_unlock();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册