Syzbot has found a breakpoint overcommit issue:
https://lore.kernel.org/lkml/[email protected]/ It took me a long time to find out what the actual root problem was. Also its reproducer only worked on a few month old kernel but it didn't feel like the issue was actually solved. I eventually cooked a reproducer that works with latest upstream, see in the end of this message. The fix is just a few liner but implies to shut down the context swapping optimization for contexts containing breakpoints. Also I feel like uprobes may be concerned as well as it seems to make use of event.hw->target after pmu::init(). git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks.git perf/pin HEAD: 35b749650cc72402ae47beb5e0048c36636a4002 Thanks, Frederic --- Frederic Weisbecker (2): perf: Allow a pmu to pin context perf/hw_breakpoints: Pin perf contexts of breakpoints include/linux/perf_event.h | 2 ++ kernel/events/core.c | 6 ++++++ kernel/events/hw_breakpoint.c | 1 + 3 files changed, 9 insertions(+) --- #define _GNU_SOURCE #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <unistd.h> #include <sys/syscall.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h> #include <time.h> static struct perf_event_attr attr = { .type = PERF_TYPE_BREAKPOINT, .size = sizeof(attr), .config = 0, .sample_period = 1, .sample_type = PERF_SAMPLE_IP, .read_format = PERF_FORMAT_ID, .inherit = 1, .pinned = 1, .wakeup_events = 1, .bp_type = HW_BREAKPOINT_W, .bp_addr = 0, .bp_len = 8, }; static void loop(int secs) { struct timespec tp; int start; clock_gettime(CLOCK_MONOTONIC, &tp); start = tp.tv_sec; for (;;) { clock_gettime(CLOCK_MONOTONIC, &tp); if (tp.tv_sec - start >= secs) return; } } int main(int argc, char **argv) { int fd, i, status; pid_t child1, child2; for (i = 0; i < 4; i++) { fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); if (fd < 0) perror("perf_event_open"); } child1 = fork(); if (child1 == 0) { loop(1); return 0; } child2 = fork(); if (child2 == 0) { loop(2); fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); if (fd < 0) perror("perf_event_open"); return 0; } return 0; }

