* [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire()
@ 2026-07-29 14:44 Breno Leitao
2026-07-29 16:02 ` Oleg Nesterov
0 siblings, 1 reply; 5+ messages in thread
From: Breno Leitao @ 2026-07-29 14:44 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, James Clark, Masami Hiramatsu,
Oleg Nesterov, Andrii Nakryiko
Cc: linux-perf-users, linux-kernel, linux-trace-kernel, kernel-team,
stable, Breno Leitao
Forking a task that has a pending uretprobe can oops the kernel with a
NULL pointer dereference in the clone() path:
BUG: kernel NULL pointer dereference, address: 0000000000000018
Oops: 0002 [#1] SMP NOPTI
RIP: 0010:hprobe_expire
CR2: 0000000000000018
Call Trace:
uprobe_copy_process
copy_process
kernel_clone
__x64_sys_clone
do_syscall_64
entry_SYSCALL_64_after_hwframe
This was found on real hosts on Meta fleet.
I've got the impression that this is what is happening:
CPU 1 CPU 2 (traced task)
----- -------------------
hit uprobe, prepare_uretprobe():
hprobe LEASED, refcount >= 1
uprobe_unregister()
put_uprobe(): refcount -> 0
fork() -> dup_utask()
hprobe_expire(hprobe, true)
try_get_uprobe() -> NULL
get_uprobe(NULL) <-- Oops
Only take the extra reference when the uprobe is non-NULL; a NULL means
it is gone and is the correct value to return.
Fixes: dd1a7567784e ("uprobes: SRCU-protect uretprobe lifetime (with timeout)")
Cc: stable@vger.kernel.org
Signed-off-by: Breno Leitao <leitao@debian.org>
---
kernel/events/uprobes.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 07f69dd3093d5..950108f92079d 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -832,7 +832,7 @@ static struct uprobe *hprobe_expire(struct hprobe *hprobe, bool get)
if (try_cmpxchg(&hprobe->state, &hstate, uprobe ? HPROBE_STABLE : HPROBE_GONE)) {
/* We won the race, we are the ones to unlock SRCU */
__srcu_read_unlock(&uretprobes_srcu, hprobe->srcu_idx);
- return get ? get_uprobe(uprobe) : uprobe;
+ return get && uprobe ? get_uprobe(uprobe) : uprobe;
}
/*
---
base-commit: 3652b49adac266a3d27cb41cdfdb7d8790fc3633
change-id: 20260729-uprobe-b142b0863572
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire()
2026-07-29 14:44 [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire() Breno Leitao
@ 2026-07-29 16:02 ` Oleg Nesterov
2026-07-29 19:31 ` Andrii Nakryiko
0 siblings, 1 reply; 5+ messages in thread
From: Oleg Nesterov @ 2026-07-29 16:02 UTC (permalink / raw)
To: Breno Leitao
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, James Clark, Masami Hiramatsu,
Andrii Nakryiko, linux-perf-users, linux-kernel,
linux-trace-kernel, kernel-team, stable
On 07/29, Breno Leitao wrote:
>
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -832,7 +832,7 @@ static struct uprobe *hprobe_expire(struct hprobe *hprobe, bool get)
> if (try_cmpxchg(&hprobe->state, &hstate, uprobe ? HPROBE_STABLE : HPROBE_GONE)) {
> /* We won the race, we are the ones to unlock SRCU */
> __srcu_read_unlock(&uretprobes_srcu, hprobe->srcu_idx);
> - return get ? get_uprobe(uprobe) : uprobe;
> + return get && uprobe ? get_uprobe(uprobe) : uprobe;
Well, looks "obviously correct". At least the current code is obviously
wrong, it even checks uprobe != NULL 3 lines above.
Andrii ?
Acked-by: Oleg Nesterov <oleg@redhat.com>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire()
2026-07-29 16:02 ` Oleg Nesterov
@ 2026-07-29 19:31 ` Andrii Nakryiko
2026-07-29 23:54 ` Masami Hiramatsu
0 siblings, 1 reply; 5+ messages in thread
From: Andrii Nakryiko @ 2026-07-29 19:31 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Breno Leitao, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Masami Hiramatsu, Andrii Nakryiko, linux-perf-users,
linux-kernel, linux-trace-kernel, kernel-team, stable
On Wed, Jul 29, 2026 at 9:02 AM Oleg Nesterov <oleg@redhat.com> wrote:
>
> On 07/29, Breno Leitao wrote:
> >
> > --- a/kernel/events/uprobes.c
> > +++ b/kernel/events/uprobes.c
> > @@ -832,7 +832,7 @@ static struct uprobe *hprobe_expire(struct hprobe *hprobe, bool get)
> > if (try_cmpxchg(&hprobe->state, &hstate, uprobe ? HPROBE_STABLE : HPROBE_GONE)) {
> > /* We won the race, we are the ones to unlock SRCU */
> > __srcu_read_unlock(&uretprobes_srcu, hprobe->srcu_idx);
> > - return get ? get_uprobe(uprobe) : uprobe;
> > + return get && uprobe ? get_uprobe(uprobe) : uprobe;
>
> Well, looks "obviously correct". At least the current code is obviously
> wrong, it even checks uprobe != NULL 3 lines above.
>
> Andrii ?
>
Yes, indeed, I'm more surprised this didn't come up much earlier
(probably it's rare enough to have uretprobe with refcnt at zero
during fork). The fix looks good, thanks!
Acked-by: Andrii Nakryiko <andrii@kernel.org>
> Acked-by: Oleg Nesterov <oleg@redhat.com>
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire()
2026-07-29 19:31 ` Andrii Nakryiko
@ 2026-07-29 23:54 ` Masami Hiramatsu
2026-07-30 10:38 ` Peter Zijlstra
0 siblings, 1 reply; 5+ messages in thread
From: Masami Hiramatsu @ 2026-07-29 23:54 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Oleg Nesterov, Breno Leitao, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Masami Hiramatsu, Andrii Nakryiko, linux-perf-users,
linux-kernel, linux-trace-kernel, kernel-team, stable
On Wed, 29 Jul 2026 12:31:08 -0700
Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
> On Wed, Jul 29, 2026 at 9:02 AM Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > On 07/29, Breno Leitao wrote:
> > >
> > > --- a/kernel/events/uprobes.c
> > > +++ b/kernel/events/uprobes.c
> > > @@ -832,7 +832,7 @@ static struct uprobe *hprobe_expire(struct hprobe *hprobe, bool get)
> > > if (try_cmpxchg(&hprobe->state, &hstate, uprobe ? HPROBE_STABLE : HPROBE_GONE)) {
> > > /* We won the race, we are the ones to unlock SRCU */
> > > __srcu_read_unlock(&uretprobes_srcu, hprobe->srcu_idx);
> > > - return get ? get_uprobe(uprobe) : uprobe;
> > > + return get && uprobe ? get_uprobe(uprobe) : uprobe;
> >
> > Well, looks "obviously correct". At least the current code is obviously
> > wrong, it even checks uprobe != NULL 3 lines above.
> >
> > Andrii ?
> >
>
> Yes, indeed, I'm more surprised this didn't come up much earlier
> (probably it's rare enough to have uretprobe with refcnt at zero
> during fork). The fix looks good, thanks!
>
> Acked-by: Andrii Nakryiko <andrii@kernel.org>
>
> > Acked-by: Oleg Nesterov <oleg@redhat.com>
> >
Thanks, this seems good to me. (uprobe is NULL checked in try_cmpxchg(),
so it could be NULL.)
Can I pick this to probes/fixes branch?
Thank you,
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire()
2026-07-29 23:54 ` Masami Hiramatsu
@ 2026-07-30 10:38 ` Peter Zijlstra
0 siblings, 0 replies; 5+ messages in thread
From: Peter Zijlstra @ 2026-07-30 10:38 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrii Nakryiko, Oleg Nesterov, Breno Leitao, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Andrii Nakryiko, linux-perf-users, linux-kernel,
linux-trace-kernel, kernel-team, stable
On Thu, Jul 30, 2026 at 08:54:21AM +0900, Masami Hiramatsu wrote:
> On Wed, 29 Jul 2026 12:31:08 -0700
> Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> > On Wed, Jul 29, 2026 at 9:02 AM Oleg Nesterov <oleg@redhat.com> wrote:
> > >
> > > On 07/29, Breno Leitao wrote:
> > > >
> > > > --- a/kernel/events/uprobes.c
> > > > +++ b/kernel/events/uprobes.c
> > > > @@ -832,7 +832,7 @@ static struct uprobe *hprobe_expire(struct hprobe *hprobe, bool get)
> > > > if (try_cmpxchg(&hprobe->state, &hstate, uprobe ? HPROBE_STABLE : HPROBE_GONE)) {
> > > > /* We won the race, we are the ones to unlock SRCU */
> > > > __srcu_read_unlock(&uretprobes_srcu, hprobe->srcu_idx);
> > > > - return get ? get_uprobe(uprobe) : uprobe;
> > > > + return get && uprobe ? get_uprobe(uprobe) : uprobe;
> > >
> > > Well, looks "obviously correct". At least the current code is obviously
> > > wrong, it even checks uprobe != NULL 3 lines above.
> > >
> > > Andrii ?
> > >
> >
> > Yes, indeed, I'm more surprised this didn't come up much earlier
> > (probably it's rare enough to have uretprobe with refcnt at zero
> > during fork). The fix looks good, thanks!
> >
> > Acked-by: Andrii Nakryiko <andrii@kernel.org>
> >
> > > Acked-by: Oleg Nesterov <oleg@redhat.com>
> > >
>
> Thanks, this seems good to me. (uprobe is NULL checked in try_cmpxchg(),
> so it could be NULL.)
>
> Can I pick this to probes/fixes branch?
tip/perf/urgent ?
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-30 10:38 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 14:44 [PATCH] uprobes: Fix NULL pointer dereference in hprobe_expire() Breno Leitao
2026-07-29 16:02 ` Oleg Nesterov
2026-07-29 19:31 ` Andrii Nakryiko
2026-07-29 23:54 ` Masami Hiramatsu
2026-07-30 10:38 ` Peter Zijlstra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox