[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250902143504.1224726-3-jolsa@kernel.org>
Date: Tue, 2 Sep 2025 16:34:55 +0200
From: Jiri Olsa <jolsa@...nel.org>
To: Oleg Nesterov <oleg@...hat.com>,
Masami Hiramatsu <mhiramat@...nel.org>,
Peter Zijlstra <peterz@...radead.org>,
Andrii Nakryiko <andrii@...nel.org>
Cc: bpf@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-trace-kernel@...r.kernel.org,
x86@...nel.org,
Song Liu <songliubraving@...com>,
Yonghong Song <yhs@...com>,
John Fastabend <john.fastabend@...il.com>,
Hao Luo <haoluo@...gle.com>,
Steven Rostedt <rostedt@...dmis.org>,
Ingo Molnar <mingo@...nel.org>
Subject: [PATCH perf/core 02/11] uprobes: Skip emulate/sstep on unique uprobe when ip is changed
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@...nel.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
Powered by blists - more mailing lists