[PATCH 1/2] arm64/debug: update perf slots in sync with BP registers
Ada Couprie Diaz
ada.coupriediaz at arm.com
Wed May 27 09:15:52 PDT 2026
The current order of operations in `hw_breakpoint_control()` is unsound
and can lead to the kernel getting stuck on a hardware breakpoint in
some edge cases[0], as it can be called with debug exceptions unmasked.
As we search a relevant perf slot and update depending on the operation
directly in `hw_breakpoint_setup_slot()`, when uninstalling a breakpoint
it can still be triggered while its slot has been cleared, preventing
the debug handlers from handling it properly and getting stuck on it.
Hoist the perf slot updates out of `hw_breakpoint_setup_slot()` into
`hw_breakpoint_control()` : set up the slot before writing to the register
when installing (no change) but clear it after writing to the register
when uninstalling.
Rename `hw_breakpoint_setup_slot()` to `hw_breakpoint_find_slot()`, as
the slot setup is now done directly in `hw_breakpoint_control()`.
[0]: https://lore.kernel.org/linux-arm-kernel/adeE4MD0RgapI8aL@J2N7QTR9R3/
Signed-off-by: Ada Couprie Diaz <ada.coupriediaz at arm.com>
---
arch/arm64/kernel/hw_breakpoint.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ab76b36dce82..ce99a00c8596 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -174,12 +174,11 @@ static int is_compat_bp(struct perf_event *bp)
}
/**
- * hw_breakpoint_slot_setup - Find and setup a perf slot according to
- * operations
+ * hw_breakpoint_find_slot - Find a perf slot according to operation
*
* @slots: pointer to array of slots
* @max_slots: max number of slots
- * @bp: perf_event to setup
+ * @bp: perf_event to find, for uninstall and restore operations
* @ops: operation to be carried out on the slot
*
* Return:
@@ -187,30 +186,26 @@ static int is_compat_bp(struct perf_event *bp)
* -ENOSPC if no slot is available/matches
* -EINVAL on wrong operations parameter
*/
-static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
+static int hw_breakpoint_find_slot(struct perf_event **slots, int max_slots,
struct perf_event *bp,
enum hw_breakpoint_ops ops)
{
int i;
- struct perf_event **slot;
+ struct perf_event *slot;
for (i = 0; i < max_slots; ++i) {
- slot = &slots[i];
+ slot = slots[i];
switch (ops) {
case HW_BREAKPOINT_INSTALL:
- if (!*slot) {
- *slot = bp;
+ if (!slot)
return i;
- }
break;
case HW_BREAKPOINT_UNINSTALL:
- if (*slot == bp) {
- *slot = NULL;
+ if (slot == bp)
return i;
- }
break;
case HW_BREAKPOINT_RESTORE:
- if (*slot == bp)
+ if (slot == bp)
return i;
break;
default:
@@ -247,13 +242,15 @@ static int hw_breakpoint_control(struct perf_event *bp,
reg_enable = !debug_info->wps_disabled;
}
- i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);
+ i = hw_breakpoint_find_slot(slots, max_slots, bp, ops);
if (WARN_ONCE(i < 0, "Can't find any breakpoint slot"))
return i;
switch (ops) {
case HW_BREAKPOINT_INSTALL:
+ slots[i] = bp;
+ barrier();
/*
* Ensure debug monitors are enabled at the correct exception
* level.
@@ -278,6 +275,9 @@ static int hw_breakpoint_control(struct perf_event *bp,
* level.
*/
disable_debug_monitors(dbg_el);
+
+ barrier();
+ slots[i] = NULL;
break;
}
--
2.43.0
More information about the linux-arm-kernel
mailing list