Skip to content

Commit eec13b4

Browse files
willdeaconRussell King
authored andcommitted
ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess watchpoints
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: <[email protected]> Fixes: f81ef4a ("ARM: 6356/1: hw-breakpoint: add ARM backend for the hw-breakpoint framework") Reported-by: Luis Machado <[email protected]> Tested-by: Luis Machado <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent dcb7fd8 commit eec13b4

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

arch/arm/kernel/hw_breakpoint.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,12 @@ static void disable_single_step(struct perf_event *bp)
683683
arch_install_hw_breakpoint(bp);
684684
}
685685

686+
static int watchpoint_fault_on_uaccess(struct pt_regs *regs,
687+
struct arch_hw_breakpoint *info)
688+
{
689+
return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER;
690+
}
691+
686692
static void watchpoint_handler(unsigned long addr, unsigned int fsr,
687693
struct pt_regs *regs)
688694
{
@@ -742,16 +748,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
742748
}
743749

744750
pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
751+
752+
/*
753+
* If we triggered a user watchpoint from a uaccess routine,
754+
* then handle the stepping ourselves since userspace really
755+
* can't help us with this.
756+
*/
757+
if (watchpoint_fault_on_uaccess(regs, info))
758+
goto step;
759+
745760
perf_bp_event(wp, regs);
746761

747762
/*
748-
* If no overflow handler is present, insert a temporary
749-
* mismatch breakpoint so we can single-step over the
750-
* watchpoint trigger.
763+
* Defer stepping to the overflow handler if one is installed.
764+
* Otherwise, insert a temporary mismatch breakpoint so that
765+
* we can single-step over the watchpoint trigger.
751766
*/
752-
if (is_default_overflow_handler(wp))
753-
enable_single_step(wp, instruction_pointer(regs));
767+
if (!is_default_overflow_handler(wp))
768+
goto unlock;
754769

770+
step:
771+
enable_single_step(wp, instruction_pointer(regs));
755772
unlock:
756773
rcu_read_unlock();
757774
}

0 commit comments

Comments
 (0)