[PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed

Jiri Olsa posted 11 patches 1 month ago
[PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Jiri Olsa 1 month ago
If uprobe consumer changes instruction pointer we still execute
(single step or emulate) the original instruction and increment
the ip register with the size of the instruction.

In case the instruction is emulated, the new ip register value is
incremented with the instructions size and process is likely to
crash with illegal instruction.

In case the instruction is single-stepped, the ip register change
is lost and process continues with the original ip register value.

If user decided to take execution elsewhere, it makes little sense
to execute the original instruction, so let's skip it. Allowing this
behaviour only for uprobe with unique consumer attached.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 kernel/events/uprobes.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index b9b088f7333a..da8291941c6b 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -2568,7 +2568,7 @@ static bool ignore_ret_handler(int rc)
 	return rc == UPROBE_HANDLER_REMOVE || rc == UPROBE_HANDLER_IGNORE;
 }
 
-static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs, bool *is_unique)
 {
 	struct uprobe_consumer *uc;
 	bool has_consumers = false, remove = true;
@@ -2582,6 +2582,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
 		__u64 cookie = 0;
 		int rc = 0;
 
+		if (is_unique)
+			*is_unique |= uc->is_unique;
+
 		if (uc->handler) {
 			rc = uc->handler(uc, regs, &cookie);
 			WARN(rc < 0 || rc > 2,
@@ -2735,6 +2738,7 @@ static void handle_swbp(struct pt_regs *regs)
 {
 	struct uprobe *uprobe;
 	unsigned long bp_vaddr;
+	bool is_unique = false;
 	int is_swbp;
 
 	bp_vaddr = uprobe_get_swbp_addr(regs);
@@ -2789,7 +2793,10 @@ static void handle_swbp(struct pt_regs *regs)
 	if (arch_uprobe_ignore(&uprobe->arch, regs))
 		goto out;
 
-	handler_chain(uprobe, regs);
+	handler_chain(uprobe, regs, &is_unique);
+
+	if (is_unique && instruction_pointer(regs) != bp_vaddr)
+		goto out;
 
 	/* Try to optimize after first hit. */
 	arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
@@ -2819,7 +2826,7 @@ void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr)
 		return;
 	if (arch_uprobe_ignore(&uprobe->arch, regs))
 		return;
-	handler_chain(uprobe, regs);
+	handler_chain(uprobe, regs, NULL);
 }
 
 /*
-- 
2.51.0
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Oleg Nesterov 4 weeks, 1 day ago
On 09/02, Jiri Olsa wrote:
>
> If user decided to take execution elsewhere, it makes little sense
> to execute the original instruction, so let's skip it.

Exactly.

So why do we need all these "is_unique" complications? Only a single
is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
can just do

	handler_chain(uprobe, regs);
	if (instruction_pointer(regs) != bp_vaddr)
		goto out;


> Allowing this
> behaviour only for uprobe with unique consumer attached.

But if a non-exclusive consumer changes regs->ip, we have a problem
anyway, right?

We can probably add something like

		rc = uc->handler(uc, regs, &cookie);
	+	WARN_ON(!uc->is_unique && instruction_pointer(regs) != bp_vaddr);

into handler_chain(), although I don't think this is needed.

Oleg.

> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  kernel/events/uprobes.c | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index b9b088f7333a..da8291941c6b 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -2568,7 +2568,7 @@ static bool ignore_ret_handler(int rc)
>  	return rc == UPROBE_HANDLER_REMOVE || rc == UPROBE_HANDLER_IGNORE;
>  }
>  
> -static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> +static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs, bool *is_unique)
>  {
>  	struct uprobe_consumer *uc;
>  	bool has_consumers = false, remove = true;
> @@ -2582,6 +2582,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
>  		__u64 cookie = 0;
>  		int rc = 0;
>  
> +		if (is_unique)
> +			*is_unique |= uc->is_unique;
> +
>  		if (uc->handler) {
>  			rc = uc->handler(uc, regs, &cookie);
>  			WARN(rc < 0 || rc > 2,
> @@ -2735,6 +2738,7 @@ static void handle_swbp(struct pt_regs *regs)
>  {
>  	struct uprobe *uprobe;
>  	unsigned long bp_vaddr;
> +	bool is_unique = false;
>  	int is_swbp;
>  
>  	bp_vaddr = uprobe_get_swbp_addr(regs);
> @@ -2789,7 +2793,10 @@ static void handle_swbp(struct pt_regs *regs)
>  	if (arch_uprobe_ignore(&uprobe->arch, regs))
>  		goto out;
>  
> -	handler_chain(uprobe, regs);
> +	handler_chain(uprobe, regs, &is_unique);
> +
> +	if (is_unique && instruction_pointer(regs) != bp_vaddr)
> +		goto out;
>  
>  	/* Try to optimize after first hit. */
>  	arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
> @@ -2819,7 +2826,7 @@ void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr)
>  		return;
>  	if (arch_uprobe_ignore(&uprobe->arch, regs))
>  		return;
> -	handler_chain(uprobe, regs);
> +	handler_chain(uprobe, regs, NULL);
>  }
>  
>  /*
> -- 
> 2.51.0
>
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Jiri Olsa 4 weeks, 1 day ago
On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> On 09/02, Jiri Olsa wrote:
> >
> > If user decided to take execution elsewhere, it makes little sense
> > to execute the original instruction, so let's skip it.
> 
> Exactly.
> 
> So why do we need all these "is_unique" complications? Only a single
> is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> can just do
> 
> 	handler_chain(uprobe, regs);
> 	if (instruction_pointer(regs) != bp_vaddr)
> 		goto out;

hum, that's what I did in rfc [1] but I thought you did not like that [2]

[1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
[2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/

I guess I misunderstood your reply [2], I'd be happy to drop the
unique/exclusive flag

jirka

> 
> 
> > Allowing this
> > behaviour only for uprobe with unique consumer attached.
> 
> But if a non-exclusive consumer changes regs->ip, we have a problem
> anyway, right?
> 
> We can probably add something like
> 
> 		rc = uc->handler(uc, regs, &cookie);
> 	+	WARN_ON(!uc->is_unique && instruction_pointer(regs) != bp_vaddr);
> 
> into handler_chain(), although I don't think this is needed.
> 
> Oleg.
> 
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  kernel/events/uprobes.c | 13 ++++++++++---
> >  1 file changed, 10 insertions(+), 3 deletions(-)
> > 
> > diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> > index b9b088f7333a..da8291941c6b 100644
> > --- a/kernel/events/uprobes.c
> > +++ b/kernel/events/uprobes.c
> > @@ -2568,7 +2568,7 @@ static bool ignore_ret_handler(int rc)
> >  	return rc == UPROBE_HANDLER_REMOVE || rc == UPROBE_HANDLER_IGNORE;
> >  }
> >  
> > -static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> > +static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs, bool *is_unique)
> >  {
> >  	struct uprobe_consumer *uc;
> >  	bool has_consumers = false, remove = true;
> > @@ -2582,6 +2582,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> >  		__u64 cookie = 0;
> >  		int rc = 0;
> >  
> > +		if (is_unique)
> > +			*is_unique |= uc->is_unique;
> > +
> >  		if (uc->handler) {
> >  			rc = uc->handler(uc, regs, &cookie);
> >  			WARN(rc < 0 || rc > 2,
> > @@ -2735,6 +2738,7 @@ static void handle_swbp(struct pt_regs *regs)
> >  {
> >  	struct uprobe *uprobe;
> >  	unsigned long bp_vaddr;
> > +	bool is_unique = false;
> >  	int is_swbp;
> >  
> >  	bp_vaddr = uprobe_get_swbp_addr(regs);
> > @@ -2789,7 +2793,10 @@ static void handle_swbp(struct pt_regs *regs)
> >  	if (arch_uprobe_ignore(&uprobe->arch, regs))
> >  		goto out;
> >  
> > -	handler_chain(uprobe, regs);
> > +	handler_chain(uprobe, regs, &is_unique);
> > +
> > +	if (is_unique && instruction_pointer(regs) != bp_vaddr)
> > +		goto out;
> >  
> >  	/* Try to optimize after first hit. */
> >  	arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
> > @@ -2819,7 +2826,7 @@ void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr)
> >  		return;
> >  	if (arch_uprobe_ignore(&uprobe->arch, regs))
> >  		return;
> > -	handler_chain(uprobe, regs);
> > +	handler_chain(uprobe, regs, NULL);
> >  }
> >  
> >  /*
> > -- 
> > 2.51.0
> > 
>
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Oleg Nesterov 4 weeks, 1 day ago
On 09/03, Jiri Olsa wrote:
>
> On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> > On 09/02, Jiri Olsa wrote:
> > >
> > > If user decided to take execution elsewhere, it makes little sense
> > > to execute the original instruction, so let's skip it.
> >
> > Exactly.
> >
> > So why do we need all these "is_unique" complications? Only a single
> > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > can just do
> >
> > 	handler_chain(uprobe, regs);
> > 	if (instruction_pointer(regs) != bp_vaddr)
> > 		goto out;
>
> hum, that's what I did in rfc [1] but I thought you did not like that [2]
>
> [1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
> [2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/
>
> I guess I misunderstood your reply [2], I'd be happy to drop the
> unique/exclusive flag

Well, but that rfc didn't introduce the exclusive consumers, and I think
we agree that even with these changes the non-exclusive consumers must
never change regs->ip?

> > But if a non-exclusive consumer changes regs->ip, we have a problem
> > anyway, right?
> >
> > We can probably add something like
> >
> > 		rc = uc->handler(uc, regs, &cookie);
> > 	+	WARN_ON(!uc->is_unique && instruction_pointer(regs) != bp_vaddr);
> >
> > into handler_chain(), although I don't think this is needed.

Oleg.
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Jiri Olsa 4 weeks ago
On Thu, Sep 04, 2025 at 10:49:50AM +0200, Oleg Nesterov wrote:
> On 09/03, Jiri Olsa wrote:
> >
> > On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> > > On 09/02, Jiri Olsa wrote:
> > > >
> > > > If user decided to take execution elsewhere, it makes little sense
> > > > to execute the original instruction, so let's skip it.
> > >
> > > Exactly.
> > >
> > > So why do we need all these "is_unique" complications? Only a single
> > > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > > can just do
> > >
> > > 	handler_chain(uprobe, regs);
> > > 	if (instruction_pointer(regs) != bp_vaddr)
> > > 		goto out;
> >
> > hum, that's what I did in rfc [1] but I thought you did not like that [2]
> >
> > [1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
> > [2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/
> >
> > I guess I misunderstood your reply [2], I'd be happy to drop the
> > unique/exclusive flag
> 
> Well, but that rfc didn't introduce the exclusive consumers, and I think
> we agree that even with these changes the non-exclusive consumers must
> never change regs->ip?

ok, got excited too soon.. so you meant getting rid of is_unique
check only for this patch and have just change below..  but keep
the unique/exclusive flag from patch#1

IIUC Andrii would remove the unique flag completely?

jirka


--
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index b9b088f7333a..1baf5d2792ff 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -2791,6 +2791,9 @@ static void handle_swbp(struct pt_regs *regs)
 
 	handler_chain(uprobe, regs);
 
+	if (instruction_pointer(regs) != bp_vaddr)
+		goto out;
+
 	/* Try to optimize after first hit. */
 	arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Oleg Nesterov 4 weeks ago
On 09/04, Jiri Olsa wrote:
>
> On Thu, Sep 04, 2025 at 10:49:50AM +0200, Oleg Nesterov wrote:
> > On 09/03, Jiri Olsa wrote:
> > >
> > > On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> > > > On 09/02, Jiri Olsa wrote:
> > > > >
> > > > > If user decided to take execution elsewhere, it makes little sense
> > > > > to execute the original instruction, so let's skip it.
> > > >
> > > > Exactly.
> > > >
> > > > So why do we need all these "is_unique" complications? Only a single
> > > > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > > > can just do
> > > >
> > > > 	handler_chain(uprobe, regs);
> > > > 	if (instruction_pointer(regs) != bp_vaddr)
> > > > 		goto out;
> > >
> > > hum, that's what I did in rfc [1] but I thought you did not like that [2]
> > >
> > > [1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
> > > [2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/
> > >
> > > I guess I misunderstood your reply [2], I'd be happy to drop the
> > > unique/exclusive flag
> >
> > Well, but that rfc didn't introduce the exclusive consumers, and I think
> > we agree that even with these changes the non-exclusive consumers must
> > never change regs->ip?
>
> ok, got excited too soon.. so you meant getting rid of is_unique
> check only for this patch and have just change below..  but keep
> the unique/exclusive flag from patch#1

Yes, this is what I meant,

> IIUC Andrii would remove the unique flag completely?

Lets wait for Andrii...

Oleg.
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Alexei Starovoitov 4 weeks ago
On Thu, Sep 4, 2025 at 4:26 AM Oleg Nesterov <oleg@redhat.com> wrote:
>
> On 09/04, Jiri Olsa wrote:
> >
> > On Thu, Sep 04, 2025 at 10:49:50AM +0200, Oleg Nesterov wrote:
> > > On 09/03, Jiri Olsa wrote:
> > > >
> > > > On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> > > > > On 09/02, Jiri Olsa wrote:
> > > > > >
> > > > > > If user decided to take execution elsewhere, it makes little sense
> > > > > > to execute the original instruction, so let's skip it.
> > > > >
> > > > > Exactly.
> > > > >
> > > > > So why do we need all these "is_unique" complications? Only a single
> > > > > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > > > > can just do
> > > > >
> > > > >         handler_chain(uprobe, regs);
> > > > >         if (instruction_pointer(regs) != bp_vaddr)
> > > > >                 goto out;
> > > >
> > > > hum, that's what I did in rfc [1] but I thought you did not like that [2]
> > > >
> > > > [1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
> > > > [2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/
> > > >
> > > > I guess I misunderstood your reply [2], I'd be happy to drop the
> > > > unique/exclusive flag
> > >
> > > Well, but that rfc didn't introduce the exclusive consumers, and I think
> > > we agree that even with these changes the non-exclusive consumers must
> > > never change regs->ip?
> >
> > ok, got excited too soon.. so you meant getting rid of is_unique
> > check only for this patch and have just change below..  but keep
> > the unique/exclusive flag from patch#1
>
> Yes, this is what I meant,
>
> > IIUC Andrii would remove the unique flag completely?
>
> Lets wait for Andrii...

Not Andrii, but I see only negatives in this extra flag.
It doesn't add any safety or guardrails.
No need to pollute uapi with pointless flags.
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Andrii Nakryiko 4 weeks ago
On Thu, Sep 4, 2025 at 8:02 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Thu, Sep 4, 2025 at 4:26 AM Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > On 09/04, Jiri Olsa wrote:
> > >
> > > On Thu, Sep 04, 2025 at 10:49:50AM +0200, Oleg Nesterov wrote:
> > > > On 09/03, Jiri Olsa wrote:
> > > > >
> > > > > On Wed, Sep 03, 2025 at 01:26:48PM +0200, Oleg Nesterov wrote:
> > > > > > On 09/02, Jiri Olsa wrote:
> > > > > > >
> > > > > > > If user decided to take execution elsewhere, it makes little sense
> > > > > > > to execute the original instruction, so let's skip it.
> > > > > >
> > > > > > Exactly.
> > > > > >
> > > > > > So why do we need all these "is_unique" complications? Only a single
> > > > > > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > > > > > can just do
> > > > > >
> > > > > >         handler_chain(uprobe, regs);
> > > > > >         if (instruction_pointer(regs) != bp_vaddr)
> > > > > >                 goto out;
> > > > >
> > > > > hum, that's what I did in rfc [1] but I thought you did not like that [2]
> > > > >
> > > > > [1] https://lore.kernel.org/bpf/20250801210238.2207429-2-jolsa@kernel.org/
> > > > > [2] https://lore.kernel.org/bpf/20250802103426.GC31711@redhat.com/
> > > > >
> > > > > I guess I misunderstood your reply [2], I'd be happy to drop the
> > > > > unique/exclusive flag
> > > >
> > > > Well, but that rfc didn't introduce the exclusive consumers, and I think
> > > > we agree that even with these changes the non-exclusive consumers must
> > > > never change regs->ip?
> > >
> > > ok, got excited too soon.. so you meant getting rid of is_unique
> > > check only for this patch and have just change below..  but keep
> > > the unique/exclusive flag from patch#1
> >
> > Yes, this is what I meant,
> >
> > > IIUC Andrii would remove the unique flag completely?
> >
> > Lets wait for Andrii...
>
> Not Andrii, but I see only negatives in this extra flag.
> It doesn't add any safety or guardrails.
> No need to pollute uapi with pointless flags.

+1. I think it's fine to just have something like

if (unlikely(instruction_pointer(regs) != bp_vaddr))
      goto out;

after all uprobe callbacks were processed. Even if every single one of
them modify IP, the last one that did that wins. Others (if they care)
can detect this.

Generally speaking, this is a very specialized use case (which is why
the opposition to complicating UAPI for all of that), and I'd expect
to have at most 1 such uprobe callbacks at any attach point, while all
others (if there are any "others") are read-only and won't care about
return IP.
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Oleg Nesterov 4 weeks ago
On 09/04, Andrii Nakryiko wrote:
>
> On Thu, Sep 4, 2025 at 8:02 AM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Thu, Sep 4, 2025 at 4:26 AM Oleg Nesterov <oleg@redhat.com> wrote:
> > >
> > > On 09/04, Jiri Olsa wrote:
> > > >
> > > >
> > > > ok, got excited too soon.. so you meant getting rid of is_unique
> > > > check only for this patch and have just change below..  but keep
> > > > the unique/exclusive flag from patch#1
> > >
> > > Yes, this is what I meant,
> > >
> > > > IIUC Andrii would remove the unique flag completely?
> > >
> > > Lets wait for Andrii...
> >
> > Not Andrii, but I see only negatives in this extra flag.
> > It doesn't add any safety or guardrails.
> > No need to pollute uapi with pointless flags.
>
> +1. I think it's fine to just have something like
>
> if (unlikely(instruction_pointer(regs) != bp_vaddr))
>       goto out;
>
> after all uprobe callbacks were processed. Even if every single one of
> them modify IP, the last one that did that wins.

OK. If any consumer can change regs->ip, then I can only repeat:

	Yes... but what if we there are multiple consumers? The 1st one changes
	instruction_pointer, the next is unaware. Or it may change regs->ip too...

> Others (if they care)
> can detect this.

How? If the the consumer which changes regs->ip is not the 1st one?

That said. If you guys don't see a problem - I won't even try to argue.

As I said many times, I have no idea how people actually use uprobes ;)

Oleg.

Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Andrii Nakryiko 4 weeks ago
On Thu, Sep 4, 2025 at 11:57 AM Oleg Nesterov <oleg@redhat.com> wrote:
>
> On 09/04, Andrii Nakryiko wrote:
> >
> > On Thu, Sep 4, 2025 at 8:02 AM Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> > >
> > > On Thu, Sep 4, 2025 at 4:26 AM Oleg Nesterov <oleg@redhat.com> wrote:
> > > >
> > > > On 09/04, Jiri Olsa wrote:
> > > > >
> > > > >
> > > > > ok, got excited too soon.. so you meant getting rid of is_unique
> > > > > check only for this patch and have just change below..  but keep
> > > > > the unique/exclusive flag from patch#1
> > > >
> > > > Yes, this is what I meant,
> > > >
> > > > > IIUC Andrii would remove the unique flag completely?
> > > >
> > > > Lets wait for Andrii...
> > >
> > > Not Andrii, but I see only negatives in this extra flag.
> > > It doesn't add any safety or guardrails.
> > > No need to pollute uapi with pointless flags.
> >
> > +1. I think it's fine to just have something like
> >
> > if (unlikely(instruction_pointer(regs) != bp_vaddr))
> >       goto out;
> >
> > after all uprobe callbacks were processed. Even if every single one of
> > them modify IP, the last one that did that wins.
>
> OK. If any consumer can change regs->ip, then I can only repeat:
>
>         Yes... but what if we there are multiple consumers? The 1st one changes
>         instruction_pointer, the next is unaware. Or it may change regs->ip too...
>
> > Others (if they care)
> > can detect this.
>
> How? If the the consumer which changes regs->ip is not the 1st one?
>

We are probably speaking past each other. uprobe consumers (including
BPF ones) see struct pt_regs, so they get what's the latest regs->ip.
Sure, they won't know that it was changed, but oh well, not sure that
matters all that much. And if it does matter, then we can solve that
by giving users ability to carefully order consumers (we have similar
problems and some solutions for that in BPF for some other BPF
programs; it just never been necessary for uprobes/kprobes
specifically).

> That said. If you guys don't see a problem - I won't even try to argue.

I don't, yep.

>
> As I said many times, I have no idea how people actually use uprobes ;)
>
> Oleg.
>
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Oleg Nesterov 4 weeks ago
On 09/04, Andrii Nakryiko wrote:
>
> On Thu, Sep 4, 2025 at 11:57 AM Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > That said. If you guys don't see a problem - I won't even try to argue.
>
> I don't, yep.

OK. Then I am fine with that too.

Oleg.

Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Andrii Nakryiko 4 weeks, 1 day ago
On Wed, Sep 3, 2025 at 4:28 AM Oleg Nesterov <oleg@redhat.com> wrote:
>
> On 09/02, Jiri Olsa wrote:
> >
> > If user decided to take execution elsewhere, it makes little sense
> > to execute the original instruction, so let's skip it.
>
> Exactly.
>
> So why do we need all these "is_unique" complications? Only a single

I second this. This whole is_unique flag just seems like an
unnecessary thing that spills all around (extra kernel and libbpf
flags/APIs), and it's all just not to confuse the second uprobe
attached? Let's just allow uprobes to override user registers and
handle IP change on kernel side (as unlikely() check)?

> is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> can just do
>
>         handler_chain(uprobe, regs);
>         if (instruction_pointer(regs) != bp_vaddr)
>                 goto out;
>
>
> > Allowing this
> > behaviour only for uprobe with unique consumer attached.
>
> But if a non-exclusive consumer changes regs->ip, we have a problem
> anyway, right?
>
> We can probably add something like
>
>                 rc = uc->handler(uc, regs, &cookie);
>         +       WARN_ON(!uc->is_unique && instruction_pointer(regs) != bp_vaddr);
>
> into handler_chain(), although I don't think this is needed.
>
> Oleg.
>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  kernel/events/uprobes.c | 13 ++++++++++---
> >  1 file changed, 10 insertions(+), 3 deletions(-)
> >
> > diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> > index b9b088f7333a..da8291941c6b 100644
> > --- a/kernel/events/uprobes.c
> > +++ b/kernel/events/uprobes.c
> > @@ -2568,7 +2568,7 @@ static bool ignore_ret_handler(int rc)
> >       return rc == UPROBE_HANDLER_REMOVE || rc == UPROBE_HANDLER_IGNORE;
> >  }
> >
> > -static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> > +static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs, bool *is_unique)
> >  {
> >       struct uprobe_consumer *uc;
> >       bool has_consumers = false, remove = true;
> > @@ -2582,6 +2582,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> >               __u64 cookie = 0;
> >               int rc = 0;
> >
> > +             if (is_unique)
> > +                     *is_unique |= uc->is_unique;
> > +
> >               if (uc->handler) {
> >                       rc = uc->handler(uc, regs, &cookie);
> >                       WARN(rc < 0 || rc > 2,
> > @@ -2735,6 +2738,7 @@ static void handle_swbp(struct pt_regs *regs)
> >  {
> >       struct uprobe *uprobe;
> >       unsigned long bp_vaddr;
> > +     bool is_unique = false;
> >       int is_swbp;
> >
> >       bp_vaddr = uprobe_get_swbp_addr(regs);
> > @@ -2789,7 +2793,10 @@ static void handle_swbp(struct pt_regs *regs)
> >       if (arch_uprobe_ignore(&uprobe->arch, regs))
> >               goto out;
> >
> > -     handler_chain(uprobe, regs);
> > +     handler_chain(uprobe, regs, &is_unique);
> > +
> > +     if (is_unique && instruction_pointer(regs) != bp_vaddr)
> > +             goto out;
> >
> >       /* Try to optimize after first hit. */
> >       arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
> > @@ -2819,7 +2826,7 @@ void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr)
> >               return;
> >       if (arch_uprobe_ignore(&uprobe->arch, regs))
> >               return;
> > -     handler_chain(uprobe, regs);
> > +     handler_chain(uprobe, regs, NULL);
> >  }
> >
> >  /*
> > --
> > 2.51.0
> >
>
Re: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
Posted by Jiri Olsa 4 weeks, 1 day ago
On Wed, Sep 03, 2025 at 11:20:01AM -0700, Andrii Nakryiko wrote:
> On Wed, Sep 3, 2025 at 4:28 AM Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > On 09/02, Jiri Olsa wrote:
> > >
> > > If user decided to take execution elsewhere, it makes little sense
> > > to execute the original instruction, so let's skip it.
> >
> > Exactly.
> >
> > So why do we need all these "is_unique" complications? Only a single
> 
> I second this. This whole is_unique flag just seems like an
> unnecessary thing that spills all around (extra kernel and libbpf
> flags/APIs), and it's all just not to confuse the second uprobe
> attached? Let's just allow uprobes to override user registers and
> handle IP change on kernel side (as unlikely() check)?

yes! ;-) I'd just refresh rfc version then

thanks,
jirka



> 
> > is_unique/exclusive consumer can change regs->ip, so I guess handle_swbp()
> > can just do
> >
> >         handler_chain(uprobe, regs);
> >         if (instruction_pointer(regs) != bp_vaddr)
> >                 goto out;
> >
> >
> > > Allowing this
> > > behaviour only for uprobe with unique consumer attached.
> >
> > But if a non-exclusive consumer changes regs->ip, we have a problem
> > anyway, right?
> >
> > We can probably add something like
> >
> >                 rc = uc->handler(uc, regs, &cookie);
> >         +       WARN_ON(!uc->is_unique && instruction_pointer(regs) != bp_vaddr);
> >
> > into handler_chain(), although I don't think this is needed.
> >
> > Oleg.
> >
> > > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > > ---
> > >  kernel/events/uprobes.c | 13 ++++++++++---
> > >  1 file changed, 10 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> > > index b9b088f7333a..da8291941c6b 100644
> > > --- a/kernel/events/uprobes.c
> > > +++ b/kernel/events/uprobes.c
> > > @@ -2568,7 +2568,7 @@ static bool ignore_ret_handler(int rc)
> > >       return rc == UPROBE_HANDLER_REMOVE || rc == UPROBE_HANDLER_IGNORE;
> > >  }
> > >
> > > -static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> > > +static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs, bool *is_unique)
> > >  {
> > >       struct uprobe_consumer *uc;
> > >       bool has_consumers = false, remove = true;
> > > @@ -2582,6 +2582,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> > >               __u64 cookie = 0;
> > >               int rc = 0;
> > >
> > > +             if (is_unique)
> > > +                     *is_unique |= uc->is_unique;
> > > +
> > >               if (uc->handler) {
> > >                       rc = uc->handler(uc, regs, &cookie);
> > >                       WARN(rc < 0 || rc > 2,
> > > @@ -2735,6 +2738,7 @@ static void handle_swbp(struct pt_regs *regs)
> > >  {
> > >       struct uprobe *uprobe;
> > >       unsigned long bp_vaddr;
> > > +     bool is_unique = false;
> > >       int is_swbp;
> > >
> > >       bp_vaddr = uprobe_get_swbp_addr(regs);
> > > @@ -2789,7 +2793,10 @@ static void handle_swbp(struct pt_regs *regs)
> > >       if (arch_uprobe_ignore(&uprobe->arch, regs))
> > >               goto out;
> > >
> > > -     handler_chain(uprobe, regs);
> > > +     handler_chain(uprobe, regs, &is_unique);
> > > +
> > > +     if (is_unique && instruction_pointer(regs) != bp_vaddr)
> > > +             goto out;
> > >
> > >       /* Try to optimize after first hit. */
> > >       arch_uprobe_optimize(&uprobe->arch, bp_vaddr);
> > > @@ -2819,7 +2826,7 @@ void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr)
> > >               return;
> > >       if (arch_uprobe_ignore(&uprobe->arch, regs))
> > >               return;
> > > -     handler_chain(uprobe, regs);
> > > +     handler_chain(uprobe, regs, NULL);
> > >  }
> > >
> > >  /*
> > > --
> > > 2.51.0
> > >
> >