Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 7496/1: hw_breakpoint: don't rely on dfsr to show watchpoint access type

From ARM debug architecture v7.1 onwards, a watchpoint exception causes
the DFAR to be updated with the faulting data address. However, DFSR.WnR
takes an UNKNOWN value and therefore cannot be used in general to
determine the access type that triggered the watchpoint.

This patch forbids watchpoints without an overflow handler from
specifying a specific access type (load/store). Those with overflow
handlers must be able to handle false positives potentially triggered by
a watchpoint of a different access type on the same address. For
SIGTRAP-based handlers (i.e. ptrace), this should have no impact.

Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Will Deacon and committed by
Russell King
bf880114 a849088a

+40 -15
+40 -15
arch/arm/kernel/hw_breakpoint.c
··· 159 159 arch >= ARM_DEBUG_ARCH_V7_1; 160 160 } 161 161 162 + /* Can we determine the watchpoint access type from the fsr? */ 163 + static int debug_exception_updates_fsr(void) 164 + { 165 + return 0; 166 + } 167 + 162 168 /* Determine number of WRP registers available. */ 163 169 static int get_num_wrp_resources(void) 164 170 { ··· 625 619 info->address &= ~alignment_mask; 626 620 info->ctrl.len <<= offset; 627 621 628 - /* 629 - * Currently we rely on an overflow handler to take 630 - * care of single-stepping the breakpoint when it fires. 631 - * In the case of userspace breakpoints on a core with V7 debug, 632 - * we can use the mismatch feature as a poor-man's hardware 633 - * single-step, but this only works for per-task breakpoints. 634 - */ 635 - if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) || 636 - !core_has_mismatch_brps() || !bp->hw.bp_target)) { 637 - pr_warning("overflow handler required but none found\n"); 638 - ret = -EINVAL; 622 + if (!bp->overflow_handler) { 623 + /* 624 + * Mismatch breakpoints are required for single-stepping 625 + * breakpoints. 626 + */ 627 + if (!core_has_mismatch_brps()) 628 + return -EINVAL; 629 + 630 + /* We don't allow mismatch breakpoints in kernel space. */ 631 + if (arch_check_bp_in_kernelspace(bp)) 632 + return -EPERM; 633 + 634 + /* 635 + * Per-cpu breakpoints are not supported by our stepping 636 + * mechanism. 637 + */ 638 + if (!bp->hw.bp_target) 639 + return -EINVAL; 640 + 641 + /* 642 + * We only support specific access types if the fsr 643 + * reports them. 644 + */ 645 + if (!debug_exception_updates_fsr() && 646 + (info->ctrl.type == ARM_BREAKPOINT_LOAD || 647 + info->ctrl.type == ARM_BREAKPOINT_STORE)) 648 + return -EINVAL; 639 649 } 650 + 640 651 out: 641 652 return ret; 642 653 } ··· 729 706 goto unlock; 730 707 731 708 /* Check that the access type matches. */ 732 - access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : 733 - HW_BREAKPOINT_R; 734 - if (!(access & hw_breakpoint_type(wp))) 735 - goto unlock; 709 + if (debug_exception_updates_fsr()) { 710 + access = (fsr & ARM_FSR_ACCESS_MASK) ? 711 + HW_BREAKPOINT_W : HW_BREAKPOINT_R; 712 + if (!(access & hw_breakpoint_type(wp))) 713 + goto unlock; 714 + } 736 715 737 716 /* We have a winner. */ 738 717 info->trigger = addr;