All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
@ 2026-08-13  6:05 Deepanshu Kartikey
  2026-08-13  6:22 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Deepanshu Kartikey @ 2026-08-13  6:05 UTC (permalink / raw)
  To: peterz, mingo, acme, namhyung, mark.rutland, alexander.shishkin,
	jolsa, olsajiri, irogers, adrian.hunter, james.clark, song,
	kpsingh, mattbobrowski, ast, daniel, andrii, eddyz87, memxor,
	martin.lau, yonghong.song, emil, rostedt, mhiramat,
	mathieu.desnoyers
  Cc: linux-perf-users, linux-kernel, bpf, linux-trace-kernel,
	Deepanshu Kartikey, syzbot+651d2774bd1d8395595f

Fix multiple data races involving event->prog field:

1. __perf_event_overflow() reads event->prog twice without
   synchronization creating a TOCTOU race. Fix by using READ_ONCE()
   to capture prog into a local variable and pass it directly to
   bpf_overflow_handler() to avoid a second read inside that function.

2. perf_event_set_bpf_handler() and perf_event_free_bpf_handler()
   perform plain writes to event->prog without WRITE_ONCE(), failing
   to pair with the READ_ONCE() in __perf_event_overflow(). Fix by
   using WRITE_ONCE() in all write paths including
   perf_event_detach_bpf_prog().

3. perf_event_alloc() reads parent_event->prog locklessly during
   fork() which can race with a concurrent detach clearing and freeing
   the prog, potentially causing a NULL pointer dereference or
   use-after-free in bpf_prog_inc(). Fix by holding bpf_event_mutex
   when inheriting the BPF program. Make bpf_event_mutex non-static
   and declare it extern in perf_event.h so it is accessible from
   kernel/events/core.c.

Reported-by: syzbot+651d2774bd1d8395595f@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=651d2774bd1d8395595f
Link: https://lore.kernel.org/all/20260811235331.10044-1-kartikey406@gmail.com/T/ [v1]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
v2:
- Pass validated prog pointer directly to bpf_overflow_handler()
  to avoid TOCTOU race from second READ_ONCE() inside the handler
- Add WRITE_ONCE() to perf_event_set_bpf_handler() and
  perf_event_free_bpf_handler() to pair with READ_ONCE() in overflow
- Fix lockless access in perf_event_alloc() during fork() by holding
  bpf_event_mutex to prevent concurrent detach UAF
- Make bpf_event_mutex non-static and export via perf_event.h
---
 include/linux/perf_event.h |  2 ++
 kernel/events/core.c       | 23 +++++++++++++----------
 kernel/trace/bpf_trace.c   |  4 ++--
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 48d851fbd8ea..5c6dabb6dccb 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -2136,4 +2136,6 @@ static inline void perf_lopwr_cb(bool mode)
 }
 #endif
 
+extern struct mutex bpf_event_mutex;
+
 #endif /* _LINUX_PERF_EVENT_H */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index ba5bd6a78fe7..6f8d3b57fa01 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -10652,20 +10652,19 @@ static inline bool sample_is_allowed(struct perf_event *event, struct pt_regs *r
 #ifdef CONFIG_BPF_SYSCALL
 static int bpf_overflow_handler(struct perf_event *event,
 				struct perf_sample_data *data,
-				struct pt_regs *regs)
+				struct pt_regs *regs,
+				struct bpf_prog *prog)
 {
 	struct bpf_perf_event_data_kern ctx = {
 		.data = data,
 		.event = event,
 	};
-	struct bpf_prog *prog;
 	int ret = 0;
 
 	ctx.regs = perf_arch_bpf_user_pt_regs(regs);
 	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
 		goto out;
 	rcu_read_lock();
-	prog = READ_ONCE(event->prog);
 	if (prog) {
 		perf_prepare_sample(data, event, regs);
 		ret = bpf_prog_run(prog, &ctx);
@@ -10708,7 +10707,7 @@ static inline int perf_event_set_bpf_handler(struct perf_event *event,
 		return -EPROTO;
 	}
 
-	event->prog = prog;
+	WRITE_ONCE(event->prog, prog);
 	event->bpf_cookie = bpf_cookie;
 	return 0;
 }
@@ -10720,7 +10719,7 @@ static inline void perf_event_free_bpf_handler(struct perf_event *event)
 	if (!prog)
 		return;
 
-	event->prog = NULL;
+	WRITE_ONCE(event->prog, NULL);
 	bpf_prog_put(prog);
 }
 #else
@@ -10753,6 +10752,7 @@ static int __perf_event_overflow(struct perf_event *event,
 {
 	int events = atomic_read(&event->event_limit);
 	int ret = 0;
+	struct bpf_prog *prog;
 
 	/*
 	 * Non-sampling counters might still use the PMI to fold short
@@ -10766,8 +10766,9 @@ static int __perf_event_overflow(struct perf_event *event,
 	if (event->attr.aux_pause)
 		perf_event_aux_pause(event->aux_event, true);
 
-	if (event->prog && event->prog->type == BPF_PROG_TYPE_PERF_EVENT &&
-	    !bpf_overflow_handler(event, data, regs))
+	prog = READ_ONCE(event->prog);
+	if (prog && prog->type == BPF_PROG_TYPE_PERF_EVENT &&
+	    !bpf_overflow_handler(event, data, regs, prog))
 		goto out;
 
 	/*
@@ -13433,12 +13434,15 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
 		overflow_handler = parent_event->overflow_handler;
 		context = parent_event->overflow_handler_context;
 #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)
-		if (parent_event->prog) {
-			struct bpf_prog *prog = parent_event->prog;
-
+		struct bpf_prog *prog;
+
+		mutex_lock(&bpf_event_mutex);
+		prog = parent_event->prog;
+		if (prog) {
 			bpf_prog_inc(prog);
 			event->prog = prog;
 		}
+		mutex_unlock(&bpf_event_mutex);
 #endif
 	}
 
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 75495a5c3507..026b5c492115 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1944,7 +1944,7 @@ const struct bpf_verifier_ops perf_event_verifier_ops = {
 const struct bpf_prog_ops perf_event_prog_ops = {
 };
 
-static DEFINE_MUTEX(bpf_event_mutex);
+DEFINE_MUTEX(bpf_event_mutex);
 
 #define BPF_TRACE_MAX_PROGS 64
 
@@ -2018,7 +2018,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
 
 put:
 	prog = event->prog;
-	event->prog = NULL;
+	WRITE_ONCE(event->prog, NULL);
 
 unlock:
 	mutex_unlock(&bpf_event_mutex);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
  2026-08-13  6:05 Deepanshu Kartikey
@ 2026-08-13  6:22 ` sashiko-bot
  2026-08-13  7:11 ` bot+bpf-ci
  2026-08-13 11:05 ` Peter Zijlstra
  2 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-08-13  6:22 UTC (permalink / raw)
  To: Deepanshu Kartikey; +Cc: bpf, linux-trace-kernel, linux-perf-users

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [High] Unconditional use of `bpf_event_mutex` in `kernel/events/core.c` causes a linker error in valid Kconfig combinations where `CONFIG_BPF_EVENTS` is disabled.

Pre-existing issues:
- [High] The fix for the data race in `perf_event_alloc()` is incomplete because `bpf_event_mutex` is not held during the detachment of non-tracing BPF programs, leaving the use-after-free race unfixed.
- [High] Dereferencing prog->type without rcu_read_lock_trace() exposes sleepable BPF programs to Use-After-Free.
- [Medium] The patch misses a plain write to event->prog in perf_event_attach_bpf_prog(), leaving a data race with READ_ONCE(event->prog) unfixed.
- [Medium] `perf_event_free_bpf_handler()` still contains a plain read of `event->prog` which can race with a concurrent `WRITE_ONCE()` in `perf_event_set_bpf_handler()`.
- [Medium] Missing release barrier in perf_event_set_bpf_handler() allows BPF programs to observe uninitialized or stale bpf_cookie values.
--

--- Patch [1]: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling ---
commit f4518a73c55a1297eca26073838ec515d34cb05a
Author: Deepanshu Kartikey <kartikey406@gmail.com>
perf/bpf: Fix data races in BPF perf event handling

This commit attempts to fix data races around the event->prog field
by introducing READ_ONCE and WRITE_ONCE in various handlers, and acquiring
bpf_event_mutex during fork() in perf_event_alloc().

Link: https://lore.kernel.org/all/20260811235331.10044-1-kartikey406@gmail.com/T/

> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 48d851fbd8ea5..5c6dabb6dccb1 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -2136,4 +2136,6 @@ static inline void perf_lopwr_cb(bool mode)
>  }
>  #endif
>  
> +extern struct mutex bpf_event_mutex;
> +

[Severity: High]
Will this extern declaration lead to a linker error in valid Kconfig
combinations where CONFIG_BPF_EVENTS is disabled?

The bpf_event_mutex is defined in kernel/trace/bpf_trace.c, which is
only compiled when CONFIG_BPF_EVENTS=y. If a kernel is configured with
CONFIG_BPF_SYSCALL=y and CONFIG_EVENT_TRACING=y, but kprobe and uprobe
events are disabled, this might result in an unresolved external symbol.

>  #endif /* _LINUX_PERF_EVENT_H */
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index ba5bd6a78fe7b..1416066ef460e 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c

[ ... ]

> @@ -10708,7 +10707,7 @@ static inline int perf_event_set_bpf_handler(struct perf_event *event,
>  		return -EPROTO;
>  	}
>  
> -	event->prog = prog;
> +	WRITE_ONCE(event->prog, prog);
>  	event->bpf_cookie = bpf_cookie;
>  	return 0;
>  }

[Severity: Medium]
This is a pre-existing issue, but does publishing event->prog without a
release barrier allow concurrent readers in __perf_event_overflow() to
observe an uninitialized or stale bpf_cookie?

Without smp_store_release() or similar ordering, the CPU can reorder the
event->prog write and the plain store to event->bpf_cookie. Since the reader
uses READ_ONCE(), which lacks acquire semantics, a BPF program might read
the uninitialized cookie.

> @@ -10720,7 +10719,7 @@ static inline void perf_event_free_bpf_handler(struct perf_event *event)
>  	if (!prog)
>  		return;
>  
> -	event->prog = NULL;
> +	WRITE_ONCE(event->prog, NULL);
>  	bpf_prog_put(prog);
>  }

[Severity: Medium]
This is a pre-existing issue, but does perf_event_free_bpf_handler() still
contain a plain read of event->prog?

At the beginning of this function:
	struct bpf_prog *prog = event->prog;

Could this read race with a concurrent WRITE_ONCE() from
perf_event_set_bpf_handler() during ioctl(PERF_EVENT_IOC_SET_BPF)?

[Severity: High]
This is a pre-existing issue, but does perf_event_free_bpf_handler() need to
acquire bpf_event_mutex to safely detach non-tracing BPF programs?

Because this function clears event->prog and drops the program reference
locklessly, a concurrent fork() calling perf_event_alloc() could acquire the
mutex, read the program, and increment a zero-refcount object.

>  #else
> @@ -10753,6 +10752,7 @@ static int __perf_event_overflow(struct perf_event *event,
>  {
>  	int events = atomic_read(&event->event_limit);
>  	int ret = 0;
> +	struct bpf_prog *prog;
>  
>  	/*
>  	 * Non-sampling counters might still use the PMI to fold short
> @@ -10766,8 +10766,9 @@ static int __perf_event_overflow(struct perf_event *event,
>  	if (event->attr.aux_pause)
>  		perf_event_aux_pause(event->aux_event, true);
>  
> -	if (event->prog && event->prog->type == BPF_PROG_TYPE_PERF_EVENT &&
> -	    !bpf_overflow_handler(event, data, regs))
> +	prog = READ_ONCE(event->prog);
> +	if (prog && prog->type == BPF_PROG_TYPE_PERF_EVENT &&
> +	    !bpf_overflow_handler(event, data, regs, prog))

[Severity: High]
This is a pre-existing issue, but does dereferencing prog->type here
without rcu_read_lock_trace() expose sleepable BPF programs to a
use-after-free?

RCU Tasks Trace grace periods do not wait for NMIs or preemption-disabled
sections (Classic RCU context). If a sleepable program is detached and freed
via call_rcu_tasks_trace(), couldn't it be freed while __perf_event_overflow()
is still executing and evaluating prog->type?

>  		goto out;
>  
>  	/*
> @@ -13433,12 +13434,15 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
>  		overflow_handler = parent_event->overflow_handler;
>  		context = parent_event->overflow_handler_context;
>  #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)
> -		if (parent_event->prog) {
> -			struct bpf_prog *prog = parent_event->prog;
>  
> +		struct bpf_prog *prog;
>  
> +		mutex_lock(&bpf_event_mutex);
> +		prog = parent_event->prog;
> +		if (prog) {
>  			bpf_prog_inc(prog);
>  			event->prog = prog;
>  		}
> +		mutex_unlock(&bpf_event_mutex);
>  #endif

[Severity: High]
As mentioned above, since bpf_event_mutex is only compiled when
CONFIG_BPF_EVENTS=y, will unconditionally locking it here cause a build
failure on kernels where that configuration is disabled?

>  	}
>  
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 75495a5c35079..026b5c4921158 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c

[ ... ]

> @@ -2018,7 +2018,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
>  
>  put:
>  	prog = event->prog;
> -	event->prog = NULL;
> +	WRITE_ONCE(event->prog, NULL);
>  
>  unlock:
>  	mutex_unlock(&bpf_event_mutex);

[Severity: Medium]
This isn't a bug introduced by this patch, but doesn't
perf_event_attach_bpf_prog() still contain a plain write to event->prog?

Since this patch fixes data races against the READ_ONCE() in the fast
path, should the plain write:
    event->prog = prog;

in the attach path also be converted to a WRITE_ONCE()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260813060528.365959-1-kartikey406@gmail.com?part=1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
  2026-08-13  6:05 Deepanshu Kartikey
  2026-08-13  6:22 ` sashiko-bot
@ 2026-08-13  7:11 ` bot+bpf-ci
  2026-08-13 11:05 ` Peter Zijlstra
  2 siblings, 0 replies; 7+ messages in thread
From: bot+bpf-ci @ 2026-08-13  7:11 UTC (permalink / raw)
  To: kartikey406, peterz, mingo, acme, namhyung, mark.rutland,
	alexander.shishkin, jolsa, olsajiri, irogers, adrian.hunter,
	james.clark, song, kpsingh, mattbobrowski, ast, daniel, andrii,
	eddyz87, memxor, martin.lau, yonghong.song, emil, rostedt,
	mhiramat, mathieu.desnoyers
  Cc: linux-perf-users, linux-kernel, bpf, linux-trace-kernel,
	kartikey406, syzbot+651d2774bd1d8395595f, ast, andrii, daniel,
	martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 13991 bytes --]

> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 48d851fbd8ea5..5c6dabb6dccb1 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -2136,4 +2136,6 @@ static inline void perf_lopwr_cb(bool mode)
>  }
>  #endif
>
> +extern struct mutex bpf_event_mutex;
> +
>  #endif /* _LINUX_PERF_EVENT_H */

bpf_event_mutex is defined in kernel/trace/bpf_trace.c, which is only
built when CONFIG_BPF_EVENTS=y:

  kernel/trace/Makefile: obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o

CONFIG_BPF_EVENTS depends on BPF_SYSCALL and also requires either
KPROBE_EVENTS or UPROBE_EVENTS (kernel/trace/Kconfig:853-855). However,
the new reference in perf_event_alloc() is guarded by the weaker condition
'#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)'.

CONFIG_EVENT_TRACING is selected by CONFIG_TRACING and has no dependency
on KPROBE_EVENTS or UPROBE_EVENTS. This means a config with
CONFIG_PERF_EVENTS=y, CONFIG_BPF_SYSCALL=y, CONFIG_TRACING=y,
CONFIG_KPROBES=n, and CONFIG_UPROBE_EVENTS=n will have CONFIG_BPF_EVENTS=n
and produce an undefined reference to bpf_event_mutex at link time.

Should the declaration be moved to include/linux/trace_events.h with
appropriate CONFIG_BPF_EVENTS guards, similar to how
perf_event_attach_bpf_prog() and perf_event_detach_bpf_prog() are
declared there?

> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index ba5bd6a78fe7b..1416066ef460e 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -10652,20 +10652,19 @@ static inline bool sample_is_allowed(struct perf_event *event, struct pt_regs *r
>  #ifdef CONFIG_BPF_SYSCALL
>  static int bpf_overflow_handler(struct perf_event *event,
>  				struct perf_sample_data *data,
> -				struct pt_regs *regs)
> +				struct pt_regs *regs,
> +				struct bpf_prog *prog)
>  {
>  	struct bpf_perf_event_data_kern ctx = {
>  		.data = data,
>  		.event = event,
>  	};
> -	struct bpf_prog *prog;
>  	int ret = 0;
>
>  	ctx.regs = perf_arch_bpf_user_pt_regs(regs);
>  	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
>  		goto out;
>  	rcu_read_lock();
> -	prog = READ_ONCE(event->prog);
>  	if (prog) {
>  		perf_prepare_sample(data, event, regs);
>  		ret = bpf_prog_run(prog, &ctx);

The function signature was updated to add the fourth parameter, but the
!CONFIG_BPF_SYSCALL stub at the end of this file was not updated:

  #else
  static inline int bpf_overflow_handler(struct perf_event *event,
                                         struct perf_sample_data *data,
                                         struct pt_regs *regs)
  {
      return 1;
  }

The call site at __perf_event_overflow() passes four arguments and is not
inside any CONFIG_BPF_SYSCALL guard. Since kernel/events/core.c is built
unconditionally for CONFIG_PERF_EVENTS=y, any CONFIG_PERF_EVENTS=y,
CONFIG_BPF_SYSCALL=n build will fail with "error: too many arguments to
function bpf_overflow_handler".

Should the stub also take the fourth 'struct bpf_prog *prog' parameter?

> @@ -10708,7 +10707,7 @@ static inline int perf_event_set_bpf_handler(struct perf_event *event,
>  		return -EPROTO;
>  	}
>
> -	event->prog = prog;
> +	WRITE_ONCE(event->prog, prog);
>  	event->bpf_cookie = bpf_cookie;
>  	return 0;
>  }
> @@ -10720,7 +10719,7 @@ static inline void perf_event_free_bpf_handler(struct perf_event *event)
>  	if (!prog)
>  		return;
>
> -	event->prog = NULL;
> +	WRITE_ONCE(event->prog, NULL);
>  	bpf_prog_put(prog);
>  }
>  #else
> @@ -10753,6 +10752,7 @@ static int __perf_event_overflow(struct perf_event *event,
>  {
>  	int events = atomic_read(&event->event_limit);
>  	int ret = 0;
> +	struct bpf_prog *prog;
>
>  	/*
>  	 * Non-sampling counters might still use the PMI to fold short
> @@ -10766,8 +10766,9 @@ static int __perf_event_overflow(struct perf_event *event,
>  	if (event->attr.aux_pause)
>  		perf_event_aux_pause(event->aux_event, true);
>
> -	if (event->prog && event->prog->type == BPF_PROG_TYPE_PERF_EVENT &&
> -	    !bpf_overflow_handler(event, data, regs))
> +	prog = READ_ONCE(event->prog);
> +	if (prog && prog->type == BPF_PROG_TYPE_PERF_EVENT &&
> +	    !bpf_overflow_handler(event, data, regs, prog))
>  		goto out;
>
>  	/*

[ ... ]

> @@ -13433,12 +13434,15 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
>  		overflow_handler = parent_event->overflow_handler;
>  		context = parent_event->overflow_handler_context;
>  #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)
> -		if (parent_event->prog) {
> -			struct bpf_prog *prog = parent_event->prog;
> +		struct bpf_prog *prog;
>
> +		mutex_lock(&bpf_event_mutex);
> +		prog = parent_event->prog;
> +		if (prog) {
>  			bpf_prog_inc(prog);
>  			event->prog = prog;
>  		}
> +		mutex_unlock(&bpf_event_mutex);
>  #endif
>  	}
>

bpf_event_mutex is taken to serialize against concurrent detach during
fork, but does this actually protect against all writers?

event->prog has two sets of writers:
(a) tracing events: perf_event_attach_bpf_prog() and
    perf_event_detach_bpf_prog() in kernel/trace/bpf_trace.c - these hold
    bpf_event_mutex
(b) non-tracing events (BPF_PROG_TYPE_PERF_EVENT):
    perf_event_set_bpf_handler() and perf_event_free_bpf_handler() in
    kernel/events/core.c - these do not hold bpf_event_mutex

For case (b), the concurrent path remains unprotected:

  bpf_perf_link_release()  (kernel/bpf/syscall.c, bpf_link fd close)
    -> perf_event_free_bpf_prog()
       -> perf_event_free_bpf_handler()
            struct bpf_prog *prog = event->prog;
            WRITE_ONCE(event->prog, NULL);
            bpf_prog_put(prog);

versus the fork path here:

  perf_event_init_context()  (holds parent_ctx->mutex only)
    -> inherit_task_group -> inherit_group -> inherit_event()
       -> perf_event_alloc()
            mutex_lock(&bpf_event_mutex);
            prog = parent_event->prog;
            if (prog) bpf_prog_inc(prog);

Timeline:
  CPU0: mutex_lock(&bpf_event_mutex); prog = parent_event->prog  -> P
  CPU0: preempted
  CPU1: perf_event_free_bpf_handler(): WRITE_ONCE(event->prog, NULL);
        bpf_prog_put(P); -> refcnt -> 0, free deferred by call_rcu()
  CPU0: bpf_prog_inc(P) on an object already at zero and queued for
        freeing

bpf_perf_link_release() takes neither ctx->mutex nor bpf_event_mutex, so
the NULL-deref/use-after-free window remains open for overflow-handler
progs.

Should perf_event_free_bpf_handler() also take bpf_event_mutex, or should
the inherit be serialized differently (e.g., under the event's ctx->mutex)?

Also, the read stayed a plain load rather than READ_ONCE(), so it still
data-races with the WRITE_ONCE(event->prog, NULL) added in this same
patch.

> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 29260951aa871..e91676ae6cfb4 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -1944,7 +1944,7 @@ const struct bpf_verifier_ops perf_event_verifier_ops = {
>  const struct bpf_prog_ops perf_event_prog_ops = {
>  };
>
> -static DEFINE_MUTEX(bpf_event_mutex);
> +DEFINE_MUTEX(bpf_event_mutex);
>
>  #define BPF_TRACE_MAX_PROGS 64

[ ... ]

> @@ -2018,7 +2018,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
>
>  put:
>  	prog = event->prog;
> -	event->prog = NULL;
> +	WRITE_ONCE(event->prog, NULL);
>
>  unlock:
>  	mutex_unlock(&bpf_event_mutex);

The commit message states "Fix by using WRITE_ONCE() in all write paths
including perf_event_detach_bpf_prog()", but the matching attach function
in the same file was left as a plain store:

  kernel/trace/bpf_trace.c perf_event_attach_bpf_prog():
      event->prog = prog;

perf_event_attach_bpf_prog() is a writer of the same field that
__perf_event_overflow() now reads with READ_ONCE(). The attach path can
be called on already-enabled tracepoint events that are concurrently
firing (via ioctl(PERF_EVENT_IOC_SET_BPF) or BPF_LINK_CREATE), so KCSAN
can still report 'data-race in __perf_event_overflow /
perf_event_attach_bpf_prog' (marked READ_ONCE vs plain write).

Similarly, several other plain reads remain:
- perf_event_free_bpf_handler(): 'struct bpf_prog *prog = event->prog;'
- perf_event_free_bpf_prog() read before dispatching
- perf_event_set_bpf_handler() checks before writing
- perf_event_detach_bpf_prog() reads before the WRITE_ONCE
- perf_event_alloc() read in the new mutex-protected section

Should the remaining plain writes be converted to WRITE_ONCE() and the
plain reads to READ_ONCE() to complete the annotation coverage?

---

The commit message describes the changes and their intent:

>     Fix multiple data races involving event->prog field:
>     1. __perf_event_overflow() reads event->prog twice without
>        synchronization creating a TOCTOU race. Fix by using READ_ONCE()
>        to capture prog into a local variable and pass it directly to
>        bpf_overflow_handler() to avoid a second read inside that function.

The fix does eliminate the double-read and the dropped-sample bug. However,
moving the READ_ONCE() out of bpf_overflow_handler() also moves it outside
the rcu_read_lock() that previously ensured the prog couldn't be freed
before bpf_prog_run().

Pre-patch: bpf_overflow_handler() did 'rcu_read_lock(); prog =
READ_ONCE(event->prog);' and then used that pointer. Since
perf_event_free_bpf_handler() stores NULL before bpf_prog_put(), and
freeing is RCU-deferred (call_rcu() in __bpf_prog_put_noref()), observing
a non-NULL prog inside the RCU section guaranteed the object couldn't be
freed before rcu_read_unlock().

Post-patch: the pointer is loaded in __perf_event_overflow() before
rcu_read_lock(), so in principle bpf_prog_run() could be handed an
already-freed prog if the grace period ends between the READ_ONCE() and
the rcu_read_lock().

Looking at the call paths, __perf_event_overflow() is reached with
preemption and IRQs disabled (perf_event_overflow() asserts
lockdep_assert_irqs_disabled()), which is an implicit RCU read-side
critical section covering the whole call, so the object is protected.

Should the commit message mention this trade-off, or should the code
document why the moved load is still safe despite being outside the
explicit rcu_read_lock()?

>     2. perf_event_set_bpf_handler() and perf_event_free_bpf_handler()
>        perform plain writes to event->prog without WRITE_ONCE(), failing
>        to pair with the READ_ONCE() in __perf_event_overflow().

Before this patch there was no READ_ONCE() in __perf_event_overflow() at
all - the only READ_ONCE(event->prog) was in bpf_overflow_handler(), and
this patch deletes it. The sentence describes the pre-existing code as
failing to pair with something the same patch introduces.

The substantive point (an unpaired marked read existed) is accurate, but
it was in bpf_overflow_handler(), not __perf_event_overflow().

Should this be clarified to say the plain writes failed to pair with the
READ_ONCE() that was in bpf_overflow_handler()?

>     3. perf_event_alloc() reads parent_event->prog locklessly during
>        fork() which can race with a concurrent detach clearing and freeing
>        the prog, potentially causing a NULL pointer dereference or
>        use-after-free in bpf_prog_inc(). Fix by holding bpf_event_mutex
>        when inheriting the BPF program.

As noted above, bpf_event_mutex is only held by the tracing event
attach/detach paths in kernel/trace/bpf_trace.c. It is not taken by
perf_event_free_bpf_handler(), which is the detach path for non-tracing
events (BPF_PROG_TYPE_PERF_EVENT).

perf_event_free_bpf_prog() dispatches based on perf_event_is_tracing()
and routes BPF_PROG_TYPE_PERF_EVENT progs to perf_event_free_bpf_handler(),
which does 'WRITE_ONCE(event->prog, NULL); bpf_prog_put(prog);' with no
lock at all.

A BPF_PROG_TYPE_PERF_EVENT prog can be attached to an inheritable sampling
event, and the inherit block in perf_event_alloc() is not restricted by
event type. For that case the NULL-deref/refcount-resurrection race
described above remains open.

Holding bpf_event_mutex does correctly close the race against
perf_event_detach_bpf_prog() (which clears event->prog under the mutex and
only calls bpf_prog_put() after unlocking).

Should the commit message clarify that the fix is partial and only covers
tracing events, or should perf_event_free_bpf_handler() also take
bpf_event_mutex?

>     Make bpf_event_mutex non-static and declare it extern in perf_event.h
>     so it is accessible from kernel/events/core.c.

The declaration is added to include/linux/perf_event.h outside any CONFIG
guard, but bpf_event_mutex is only defined when CONFIG_BPF_EVENTS=y
(kernel/trace/bpf_trace.o is only built for CONFIG_BPF_EVENTS).

The new mutex_lock/unlock reference in kernel/events/core.c is guarded by
'#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)', which
is strictly weaker than CONFIG_BPF_EVENTS (CONFIG_BPF_EVENTS additionally
requires KPROBE_EVENTS || UPROBE_EVENTS). A valid config with
CONFIG_BPF_SYSCALL=y, CONFIG_TRACING=y, CONFIG_KPROBES=n, and
CONFIG_UPROBE_EVENTS=n yields CONFIG_BPF_EVENTS=n and an undefined
reference at link time.

This creates both a build failure and a layering concern (exposing a
bpf_trace.c-internal mutex through the global perf_event.h). Other
bpf_trace.c functions (perf_event_attach_bpf_prog,
perf_event_detach_bpf_prog, perf_event_query_prog_array) are declared in
include/linux/trace_events.h under CONFIG_BPF_EVENTS with !BPF_EVENTS
stubs.

Should bpf_event_mutex follow the same pattern?

---

This commit fixes data races but lacks a Fixes: tag. The bugs were
introduced when BPF perf event support was first added. Suggested:

  Fixes: aa6a5f3cb2b2 ("perf, bpf: add perf events core support for BPF_PROG_TYPE_PERF_EVENT programs")


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31673322805

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
  2026-08-13  6:05 Deepanshu Kartikey
  2026-08-13  6:22 ` sashiko-bot
  2026-08-13  7:11 ` bot+bpf-ci
@ 2026-08-13 11:05 ` Peter Zijlstra
  2026-08-21  1:20   ` Deepanshu Kartikey
  2 siblings, 1 reply; 7+ messages in thread
From: Peter Zijlstra @ 2026-08-13 11:05 UTC (permalink / raw)
  To: Deepanshu Kartikey
  Cc: mingo, acme, namhyung, mark.rutland, alexander.shishkin, jolsa,
	olsajiri, irogers, adrian.hunter, james.clark, song, kpsingh,
	mattbobrowski, ast, daniel, andrii, eddyz87, memxor, martin.lau,
	yonghong.song, emil, rostedt, mhiramat, mathieu.desnoyers,
	linux-perf-users, linux-kernel, bpf, linux-trace-kernel,
	syzbot+651d2774bd1d8395595f

On Thu, Aug 13, 2026 at 11:35:28AM +0530, Deepanshu Kartikey wrote:
> Fix multiple data races involving event->prog field:
> 
> 1. __perf_event_overflow() reads event->prog twice without
>    synchronization creating a TOCTOU race. Fix by using READ_ONCE()
>    to capture prog into a local variable and pass it directly to
>    bpf_overflow_handler() to avoid a second read inside that function.

Well, first you have to show there is concurrency where this matters,
since I still don't believe in your next point.

Also, there's actually worse issues when you consider ->prog and
->bpf_cookie form a pair.

> 2. perf_event_set_bpf_handler() and perf_event_free_bpf_handler()
>    perform plain writes to event->prog without WRITE_ONCE(), failing
>    to pair with the READ_ONCE() in __perf_event_overflow(). Fix by
>    using WRITE_ONCE() in all write paths including
>    perf_event_detach_bpf_prog().

As I said yesterday, how can perf_event_detach_bpf_prog() run
concurrently with __perf_event_overflow()? Unless you answer that, this
patch ain't moving nowhere.

> 3. perf_event_alloc() reads parent_event->prog locklessly during
>    fork() which can race with a concurrent detach clearing and freeing
>    the prog, potentially causing a NULL pointer dereference or
>    use-after-free in bpf_prog_inc(). Fix by holding bpf_event_mutex
>    when inheriting the BPF program. Make bpf_event_mutex non-static
>    and declare it extern in perf_event.h so it is accessible from
>    kernel/events/core.c.

This seems like a separate issue and should thus be a separate patch.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
  2026-08-13 11:05 ` Peter Zijlstra
@ 2026-08-21  1:20   ` Deepanshu Kartikey
  0 siblings, 0 replies; 7+ messages in thread
From: Deepanshu Kartikey @ 2026-08-21  1:20 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: mingo, acme, namhyung, mark.rutland, alexander.shishkin, jolsa,
	olsajiri, irogers, adrian.hunter, james.clark, song, kpsingh,
	mattbobrowski, ast, daniel, andrii, eddyz87, memxor, martin.lau,
	yonghong.song, emil, rostedt, mhiramat, mathieu.desnoyers,
	linux-perf-users, linux-kernel, bpf, linux-trace-kernel,
	syzbot+651d2774bd1d8395595f

On Thu, Aug 13, 2026 at 4:35 PM Peter Zijlstra <peterz@infradead.org> wrote:
>

> As I said yesterday, how can perf_event_detach_bpf_prog() run
> concurrently with __perf_event_overflow()? Unless you answer that, this
> patch ain't moving nowhere.
>


You are right to question this. The KCSAN report from syzbot shows the
race was detected at runtime:

I don't have evidence to prove this race condition.

> > 3. perf_event_alloc() reads parent_event->prog locklessly during
> >    fork() which can race with a concurrent detach clearing and freeing
> >    the prog, potentially causing a NULL pointer dereference or
> >    use-after-free in bpf_prog_inc(). Fix by holding bpf_event_mutex
> >    when inheriting the BPF program. Make bpf_event_mutex non-static
> >    and declare it extern in perf_event.h so it is accessible from
> >    kernel/events/core.c.
>
> This seems like a separate issue and should thus be a separate patch.

Agreed. I will split the perf_event_alloc() fix into a separate patch.

Thanks

Deepanshu

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
@ 2026-08-25  3:25 kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2026-08-25  3:25 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp

:::::: 
:::::: Manual check reason: "linux-review patch is more than 7 days old, verify it wasn't already superseded"
:::::: 

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260813060528.365959-1-kartikey406@gmail.com>
References: <20260813060528.365959-1-kartikey406@gmail.com>
TO: Deepanshu Kartikey <kartikey406@gmail.com>
TO: peterz@infradead.org
TO: mingo@redhat.com
TO: acme@kernel.org
TO: namhyung@kernel.org
TO: mark.rutland@arm.com
TO: alexander.shishkin@linux.intel.com
TO: jolsa@kernel.org
TO: olsajiri@gmail.com
TO: irogers@google.com
TO: adrian.hunter@intel.com
TO: james.clark@linaro.org
TO: song@kernel.org
TO: kpsingh@kernel.org
TO: mattbobrowski@google.com
TO: ast@kernel.org
TO: daniel@iogearbox.net
TO: andrii@kernel.org
TO: eddyz87@gmail.com
TO: memxor@gmail.com
TO: martin.lau@linux.dev
TO: yonghong.song@linux.dev
TO: emil@etsalapatis.com
TO: rostedt@goodmis.org
TO: mhiramat@kernel.org
TO: mathieu.desnoyers@efficios.com
CC: linux-perf-users@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: bpf@vger.kernel.org
CC: linux-trace-kernel@vger.kernel.org
CC: Deepanshu Kartikey <kartikey406@gmail.com>

Hi Deepanshu,

kernel test robot noticed the following build errors:

[auto build test ERROR on perf-tools-next/perf-tools-next]
[also build test ERROR on tip/perf/core perf-tools/perf-tools linus/master v7.2 next-20260821]
[cannot apply to linux-review/Deepanshu-Kartikey/perf-bpf-Fix-data-race-in-__perf_event_overflow/20260812-052331 acme/perf/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Deepanshu-Kartikey/perf-bpf-Fix-data-races-in-BPF-perf-event-handling/20260813-113528
base:   https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf-tools-next
patch link:    https://lore.kernel.org/r/20260813060528.365959-1-kartikey406%40gmail.com
patch subject: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
:::::: branch date: 14 hours ago
:::::: commit date: 14 hours ago
config: sh-randconfig-r072-20260825 (https://download.01.org/0day-ci/archive/20260825/202608251117.NUwDpYQx-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 13.4.0
smatch: v0.5.0-9187-g5189e3fb
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260825/202608251117.NUwDpYQx-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202608251117.NUwDpYQx-lkp@intel.com/

All errors (new ones prefixed by >>):

   kernel/events/core.c: In function '__perf_event_overflow':
>> kernel/events/core.c:10771:14: error: too many arguments to function 'bpf_overflow_handler'
   10771 |             !bpf_overflow_handler(event, data, regs, prog))
         |              ^~~~~~~~~~~~~~~~~~~~
   kernel/events/core.c:10726:19: note: declared here
   10726 | static inline int bpf_overflow_handler(struct perf_event *event,
         |                   ^~~~~~~~~~~~~~~~~~~~


vim +/bpf_overflow_handler +10771 kernel/events/core.c

4c03fe11b96bda kernel/events/core.c  Kyle Huey                 2024-04-11  10744  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10745  /*
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10746   * Generic event overflow handling, sampling.
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10747   */
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10748  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10749  static int __perf_event_overflow(struct perf_event *event,
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10750  				 int throttle, struct perf_sample_data *data,
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10751  				 struct pt_regs *regs)
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10752  {
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10753  	int events = atomic_read(&event->event_limit);
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10754  	int ret = 0;
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10755  	struct bpf_prog *prog;
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10756  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10757  	/*
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10758  	 * Non-sampling counters might still use the PMI to fold short
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10759  	 * hardware counters, ignore those.
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10760  	 */
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10761  	if (unlikely(!is_sampling_event(event)))
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10762  		return 0;
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10763  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10764  	ret = __perf_event_account_interrupt(event, throttle);
cc1582c231ea04 kernel/events/core.c  Jin Yao                   2017-05-25  10765  
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10766  	if (event->attr.aux_pause)
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10767  		perf_event_aux_pause(event->aux_event, true);
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10768  
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10769  	prog = READ_ONCE(event->prog);
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10770  	if (prog && prog->type == BPF_PROG_TYPE_PERF_EVENT &&
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13 @10771  	    !bpf_overflow_handler(event, data, regs, prog))
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10772  		goto out;
c4fcc7d1f41532 kernel/events/core.c  Kyle Huey                 2024-04-11  10773  
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10774  	/*
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10775  	 * XXX event_limit might not quite work as expected on inherited
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10776  	 * events
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10777  	 */
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10778  
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10779  	event->pending_kill = POLL_IN;
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10780  	if (events && atomic_dec_and_test(&event->event_limit)) {
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10781  		ret = 1;
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10782  		event->pending_kill = POLL_HUP;
5aab90ce1ec449 kernel/events/core.c  Jiri Olsa                 2016-10-26  10783  		perf_event_disable_inatomic(event);
18dbcbfabfffc4 kernel/events/core.c  Kan Liang                 2025-08-11  10784  		event->pmu->stop(event, 0);
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10785  	}
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10786  
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10787  	if (event->attr.sigtrap) {
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10788  		/*
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10789  		 * The desired behaviour of sigtrap vs invalid samples is a bit
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10790  		 * tricky; on the one hand, one should not loose the SIGTRAP if
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10791  		 * it is the first event, on the other hand, we should also not
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10792  		 * trigger the WARN or override the data address.
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10793  		 */
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10794  		bool valid_sample = sample_is_allowed(event, regs);
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10795  		unsigned int pending_id = 1;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10796  		enum task_work_notify_mode notify_mode;
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10797  
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10798  		if (regs)
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10799  			pending_id = hash32_ptr((void *)instruction_pointer(regs)) ?: 1;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10800  
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10801  		notify_mode = in_nmi() ? TWA_NMI_CURRENT : TWA_RESUME;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10802  
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10803  		if (!event->pending_work &&
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10804  		    !task_work_add(current, &event->pending_task, notify_mode)) {
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10805  			event->pending_work = pending_id;
79bd2330108594 kernel/events/core.c  Ben Gainey                2024-07-30  10806  			local_inc(&event->ctx->nr_no_switch_fast);
56799bc0356587 kernel/events/core.c  Frederic Weisbecker       2025-03-04  10807  			WARN_ON_ONCE(!atomic_long_inc_not_zero(&event->refcount));
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10808  
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10809  			event->pending_addr = 0;
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10810  			if (valid_sample && (data->sample_flags & PERF_SAMPLE_ADDR))
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10811  				event->pending_addr = data->addr;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10812  
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10813  		} else if (event->attr.exclude_kernel && valid_sample) {
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10814  			/*
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10815  			 * Should not be able to return to user space without
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10816  			 * consuming pending_work; with exceptions:
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10817  			 *
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10818  			 *  1. Where !exclude_kernel, events can overflow again
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10819  			 *     in the kernel without returning to user space.
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10820  			 *
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10821  			 *  2. Events that can overflow again before the IRQ-
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10822  			 *     work without user space progress (e.g. hrtimer).
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10823  			 *     To approximate progress (with false negatives),
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10824  			 *     check 32-bit hash of the current IP.
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10825  			 */
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10826  			WARN_ON_ONCE(event->pending_work != pending_id);
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10827  		}
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10828  	}
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10829  
aa6a5f3cb2b2ed kernel/events/core.c  Alexei Starovoitov        2016-09-01  10830  	READ_ONCE(event->overflow_handler)(event, data, regs);
453f19eea7dbad kernel/perf_event.c   Peter Zijlstra            2009-11-20  10831  
fed66e2cdd4f12 kernel/events/core.c  Peter Zijlstra            2015-06-11  10832  	if (*perf_event_fasync(event) && event->pending_kill) {
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10833  		event->pending_wakeup = 1;
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10834  		irq_work_queue(&event->pending_irq);
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10835  	}
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10836  out:
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10837  	if (event->attr.aux_resume)
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10838  		perf_event_aux_pause(event->aux_event, false);
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10839  
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10840  	return ret;
f6c7d5fe58b484 kernel/perf_counter.c Peter Zijlstra            2009-04-06  10841  }
f6c7d5fe58b484 kernel/perf_counter.c Peter Zijlstra            2009-04-06  10842  

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
@ 2026-08-25  3:38 kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2026-08-25  3:38 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp

:::::: 
:::::: Manual check reason: "linux-review patch is more than 7 days old, verify it wasn't already superseded"
:::::: 

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260813060528.365959-1-kartikey406@gmail.com>
References: <20260813060528.365959-1-kartikey406@gmail.com>
TO: Deepanshu Kartikey <kartikey406@gmail.com>
TO: peterz@infradead.org
TO: mingo@redhat.com
TO: acme@kernel.org
TO: namhyung@kernel.org
TO: mark.rutland@arm.com
TO: alexander.shishkin@linux.intel.com
TO: jolsa@kernel.org
TO: olsajiri@gmail.com
TO: irogers@google.com
TO: adrian.hunter@intel.com
TO: james.clark@linaro.org
TO: song@kernel.org
TO: kpsingh@kernel.org
TO: mattbobrowski@google.com
TO: ast@kernel.org
TO: daniel@iogearbox.net
TO: andrii@kernel.org
TO: eddyz87@gmail.com
TO: memxor@gmail.com
TO: martin.lau@linux.dev
TO: yonghong.song@linux.dev
TO: emil@etsalapatis.com
TO: rostedt@goodmis.org
TO: mhiramat@kernel.org
TO: mathieu.desnoyers@efficios.com
CC: linux-perf-users@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: bpf@vger.kernel.org
CC: linux-trace-kernel@vger.kernel.org
CC: Deepanshu Kartikey <kartikey406@gmail.com>

Hi Deepanshu,

kernel test robot noticed the following build errors:

[auto build test ERROR on perf-tools-next/perf-tools-next]
[also build test ERROR on tip/perf/core perf-tools/perf-tools linus/master v7.2 next-20260821]
[cannot apply to linux-review/Deepanshu-Kartikey/perf-bpf-Fix-data-race-in-__perf_event_overflow/20260812-052331 acme/perf/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Deepanshu-Kartikey/perf-bpf-Fix-data-races-in-BPF-perf-event-handling/20260813-113528
base:   https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf-tools-next
patch link:    https://lore.kernel.org/r/20260813060528.365959-1-kartikey406%40gmail.com
patch subject: [PATCH v2] perf/bpf: Fix data races in BPF perf event handling
:::::: branch date: 14 hours ago
:::::: commit date: 14 hours ago
config: sh-defconfig (https://download.01.org/0day-ci/archive/20260825/202608251132.vyAbMLBM-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260825/202608251132.vyAbMLBM-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202608251132.vyAbMLBM-lkp@intel.com/

All errors (new ones prefixed by >>):

   kernel/events/core.c: In function '__perf_event_overflow':
>> kernel/events/core.c:10771:14: error: too many arguments to function 'bpf_overflow_handler'; expected 3, have 4
   10771 |             !bpf_overflow_handler(event, data, regs, prog))
         |              ^~~~~~~~~~~~~~~~~~~~                    ~~~~
   kernel/events/core.c:10726:19: note: declared here
   10726 | static inline int bpf_overflow_handler(struct perf_event *event,
         |                   ^~~~~~~~~~~~~~~~~~~~


vim +/bpf_overflow_handler +10771 kernel/events/core.c

4c03fe11b96bda kernel/events/core.c  Kyle Huey                 2024-04-11  10744  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10745  /*
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10746   * Generic event overflow handling, sampling.
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10747   */
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10748  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10749  static int __perf_event_overflow(struct perf_event *event,
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10750  				 int throttle, struct perf_sample_data *data,
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10751  				 struct pt_regs *regs)
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10752  {
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10753  	int events = atomic_read(&event->event_limit);
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10754  	int ret = 0;
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10755  	struct bpf_prog *prog;
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10756  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10757  	/*
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10758  	 * Non-sampling counters might still use the PMI to fold short
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10759  	 * hardware counters, ignore those.
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10760  	 */
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10761  	if (unlikely(!is_sampling_event(event)))
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10762  		return 0;
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10763  
475113d937adfd kernel/events/core.c  Jiri Olsa                 2016-12-28  10764  	ret = __perf_event_account_interrupt(event, throttle);
cc1582c231ea04 kernel/events/core.c  Jin Yao                   2017-05-25  10765  
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10766  	if (event->attr.aux_pause)
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10767  		perf_event_aux_pause(event->aux_event, true);
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10768  
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10769  	prog = READ_ONCE(event->prog);
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13  10770  	if (prog && prog->type == BPF_PROG_TYPE_PERF_EVENT &&
6910c8cf9c180b kernel/events/core.c  Deepanshu Kartikey        2026-08-13 @10771  	    !bpf_overflow_handler(event, data, regs, prog))
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10772  		goto out;
c4fcc7d1f41532 kernel/events/core.c  Kyle Huey                 2024-04-11  10773  
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10774  	/*
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10775  	 * XXX event_limit might not quite work as expected on inherited
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10776  	 * events
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10777  	 */
2023b359214bbc kernel/perf_counter.c Peter Zijlstra            2009-05-05  10778  
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10779  	event->pending_kill = POLL_IN;
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10780  	if (events && atomic_dec_and_test(&event->event_limit)) {
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10781  		ret = 1;
cdd6c482c9ff9c kernel/perf_event.c   Ingo Molnar               2009-09-21  10782  		event->pending_kill = POLL_HUP;
5aab90ce1ec449 kernel/events/core.c  Jiri Olsa                 2016-10-26  10783  		perf_event_disable_inatomic(event);
18dbcbfabfffc4 kernel/events/core.c  Kan Liang                 2025-08-11  10784  		event->pmu->stop(event, 0);
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10785  	}
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10786  
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10787  	if (event->attr.sigtrap) {
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10788  		/*
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10789  		 * The desired behaviour of sigtrap vs invalid samples is a bit
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10790  		 * tricky; on the one hand, one should not loose the SIGTRAP if
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10791  		 * it is the first event, on the other hand, we should also not
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10792  		 * trigger the WARN or override the data address.
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10793  		 */
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10794  		bool valid_sample = sample_is_allowed(event, regs);
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10795  		unsigned int pending_id = 1;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10796  		enum task_work_notify_mode notify_mode;
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10797  
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10798  		if (regs)
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10799  			pending_id = hash32_ptr((void *)instruction_pointer(regs)) ?: 1;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10800  
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10801  		notify_mode = in_nmi() ? TWA_NMI_CURRENT : TWA_RESUME;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10802  
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10803  		if (!event->pending_work &&
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10804  		    !task_work_add(current, &event->pending_task, notify_mode)) {
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10805  			event->pending_work = pending_id;
79bd2330108594 kernel/events/core.c  Ben Gainey                2024-07-30  10806  			local_inc(&event->ctx->nr_no_switch_fast);
56799bc0356587 kernel/events/core.c  Frederic Weisbecker       2025-03-04  10807  			WARN_ON_ONCE(!atomic_long_inc_not_zero(&event->refcount));
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10808  
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10809  			event->pending_addr = 0;
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10810  			if (valid_sample && (data->sample_flags & PERF_SAMPLE_ADDR))
058244c683111d kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10811  				event->pending_addr = data->addr;
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10812  
030a976efae83f kernel/events/core.c  Peter Zijlstra            2022-11-19  10813  		} else if (event->attr.exclude_kernel && valid_sample) {
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10814  			/*
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10815  			 * Should not be able to return to user space without
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10816  			 * consuming pending_work; with exceptions:
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10817  			 *
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10818  			 *  1. Where !exclude_kernel, events can overflow again
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10819  			 *     in the kernel without returning to user space.
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10820  			 *
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10821  			 *  2. Events that can overflow again before the IRQ-
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10822  			 *     work without user space progress (e.g. hrtimer).
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10823  			 *     To approximate progress (with false negatives),
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10824  			 *     check 32-bit hash of the current IP.
bb88f9695460be kernel/events/core.c  Marco Elver               2022-10-31  10825  			 */
c5d93d23a26012 kernel/events/core.c  Sebastian Andrzej Siewior 2024-07-04  10826  			WARN_ON_ONCE(event->pending_work != pending_id);
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10827  		}
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10828  	}
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10829  
aa6a5f3cb2b2ed kernel/events/core.c  Alexei Starovoitov        2016-09-01  10830  	READ_ONCE(event->overflow_handler)(event, data, regs);
453f19eea7dbad kernel/perf_event.c   Peter Zijlstra            2009-11-20  10831  
fed66e2cdd4f12 kernel/events/core.c  Peter Zijlstra            2015-06-11  10832  	if (*perf_event_fasync(event) && event->pending_kill) {
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10833  		event->pending_wakeup = 1;
ca6c21327c6af0 kernel/events/core.c  Peter Zijlstra            2022-10-06  10834  		irq_work_queue(&event->pending_irq);
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10835  	}
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10836  out:
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10837  	if (event->attr.aux_resume)
18d92bb57c3950 kernel/events/core.c  Adrian Hunter             2024-10-22  10838  		perf_event_aux_pause(event->aux_event, false);
f506b3dc0ec454 kernel/events/core.c  Peter Zijlstra            2011-05-26  10839  
79f146415623fe kernel/perf_counter.c Peter Zijlstra            2009-04-06  10840  	return ret;
f6c7d5fe58b484 kernel/perf_counter.c Peter Zijlstra            2009-04-06  10841  }
f6c7d5fe58b484 kernel/perf_counter.c Peter Zijlstra            2009-04-06  10842  

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-08-25  3:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25  3:38 [PATCH v2] perf/bpf: Fix data races in BPF perf event handling kernel test robot
  -- strict thread matches above, loose matches on Subject: below --
2026-08-25  3:25 kernel test robot
2026-08-13  6:05 Deepanshu Kartikey
2026-08-13  6:22 ` sashiko-bot
2026-08-13  7:11 ` bot+bpf-ci
2026-08-13 11:05 ` Peter Zijlstra
2026-08-21  1:20   ` Deepanshu Kartikey

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.