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

bpf: Fix deadlock between rcu_tasks_trace and event_mutex.

Fix the following deadlock:
CPU A
_free_event()
perf_kprobe_destroy()
mutex_lock(&event_mutex)
perf_trace_event_unreg()
synchronize_rcu_tasks_trace()

There are several paths where _free_event() grabs event_mutex
and calls sync_rcu_tasks_trace. Above is one such case.

CPU B
bpf_prog_test_run_syscall()
rcu_read_lock_trace()
bpf_prog_run_pin_on_cpu()
bpf_prog_load()
bpf_tracing_func_proto()
trace_set_clr_event()
mutex_lock(&event_mutex)

Delegate trace_set_clr_event() to workqueue to avoid
such lock dependency.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20250224221637.4780-1-alexei.starovoitov@gmail.com

authored by

Alexei Starovoitov and committed by
Andrii Nakryiko
4580f4e0 b123480e

+4 -3
+4 -3
kernel/trace/bpf_trace.c
··· 392 392 .arg2_type = ARG_CONST_SIZE, 393 393 }; 394 394 395 - static void __set_printk_clr_event(void) 395 + static void __set_printk_clr_event(struct work_struct *work) 396 396 { 397 397 /* 398 398 * This program might be calling bpf_trace_printk, ··· 405 405 if (trace_set_clr_event("bpf_trace", "bpf_trace_printk", 1)) 406 406 pr_warn_ratelimited("could not enable bpf_trace_printk events"); 407 407 } 408 + static DECLARE_WORK(set_printk_work, __set_printk_clr_event); 408 409 409 410 const struct bpf_func_proto *bpf_get_trace_printk_proto(void) 410 411 { 411 - __set_printk_clr_event(); 412 + schedule_work(&set_printk_work); 412 413 return &bpf_trace_printk_proto; 413 414 } 414 415 ··· 452 451 453 452 const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void) 454 453 { 455 - __set_printk_clr_event(); 454 + schedule_work(&set_printk_work); 456 455 return &bpf_trace_vprintk_proto; 457 456 } 458 457