From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Andrii Nakryiko <andrii@kernel.org>
Cc: linux-trace-kernel@vger.kernel.org, rostedt@goodmis.org,
x86@kernel.org, peterz@infradead.org, mingo@redhat.com,
tglx@linutronix.de, bpf@vger.kernel.org, rihams@fb.com,
linux-perf-users@vger.kernel.org, Riham Selim <rihams@meta.com>
Subject: Re: [PATCH v2 2/4] perf,uprobes: fix user stack traces in the presence of pending uretprobes
Date: Tue, 4 Jun 2024 23:13:14 +0900 [thread overview]
Message-ID: <20240604231314.e924c51f7b9a18428a8a7f0f@kernel.org> (raw)
In-Reply-To: <20240522013845.1631305-3-andrii@kernel.org>
On Tue, 21 May 2024 18:38:43 -0700
Andrii Nakryiko <andrii@kernel.org> wrote:
> When kernel has pending uretprobes installed, it hijacks original user
> function return address on the stack with a uretprobe trampoline
> address. There could be multiple such pending uretprobes (either on
> different user functions or on the same recursive one) at any given
> time within the same task.
>
> This approach interferes with the user stack trace capture logic, which
> would report suprising addresses (like 0x7fffffffe000) that correspond
> to a special "[uprobes]" section that kernel installs in the target
> process address space for uretprobe trampoline code, while logically it
> should be an address somewhere within the calling function of another
> traced user function.
>
> This is easy to correct for, though. Uprobes subsystem keeps track of
> pending uretprobes and records original return addresses. This patch is
> using this to do a post-processing step and restore each trampoline
> address entries with correct original return address. This is done only
> if there are pending uretprobes for current task.
>
> This is a similar approach to what fprobe/kretprobe infrastructure is
> doing when capturing kernel stack traces in the presence of pending
> return probes.
>
This looks good to me because this trampoline information is only
managed in uprobes. And it should be provided when unwinding user
stack.
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Thank you!
> Reported-by: Riham Selim <rihams@meta.com>
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> ---
> kernel/events/callchain.c | 43 ++++++++++++++++++++++++++++++++++++++-
> kernel/events/uprobes.c | 9 ++++++++
> 2 files changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 1273be84392c..b17e3323f7f6 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c
> @@ -11,6 +11,7 @@
> #include <linux/perf_event.h>
> #include <linux/slab.h>
> #include <linux/sched/task_stack.h>
> +#include <linux/uprobes.h>
>
> #include "internal.h"
>
> @@ -176,13 +177,51 @@ put_callchain_entry(int rctx)
> put_recursion_context(this_cpu_ptr(callchain_recursion), rctx);
> }
>
> +static void fixup_uretprobe_trampoline_entries(struct perf_callchain_entry *entry,
> + int start_entry_idx)
> +{
> +#ifdef CONFIG_UPROBES
> + struct uprobe_task *utask = current->utask;
> + struct return_instance *ri;
> + __u64 *cur_ip, *last_ip, tramp_addr;
> +
> + if (likely(!utask || !utask->return_instances))
> + return;
> +
> + cur_ip = &entry->ip[start_entry_idx];
> + last_ip = &entry->ip[entry->nr - 1];
> + ri = utask->return_instances;
> + tramp_addr = uprobe_get_trampoline_vaddr();
> +
> + /*
> + * If there are pending uretprobes for the current thread, they are
> + * recorded in a list inside utask->return_instances; each such
> + * pending uretprobe replaces traced user function's return address on
> + * the stack, so when stack trace is captured, instead of seeing
> + * actual function's return address, we'll have one or many uretprobe
> + * trampoline addresses in the stack trace, which are not helpful and
> + * misleading to users.
> + * So here we go over the pending list of uretprobes, and each
> + * encountered trampoline address is replaced with actual return
> + * address.
> + */
> + while (ri && cur_ip <= last_ip) {
> + if (*cur_ip == tramp_addr) {
> + *cur_ip = ri->orig_ret_vaddr;
> + ri = ri->next;
> + }
> + cur_ip++;
> + }
> +#endif
> +}
> +
> struct perf_callchain_entry *
> get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
> u32 max_stack, bool crosstask, bool add_mark)
> {
> struct perf_callchain_entry *entry;
> struct perf_callchain_entry_ctx ctx;
> - int rctx;
> + int rctx, start_entry_idx;
>
> entry = get_callchain_entry(&rctx);
> if (!entry)
> @@ -215,7 +254,9 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
> if (add_mark)
> perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
>
> + start_entry_idx = entry->nr;
> perf_callchain_user(&ctx, regs);
> + fixup_uretprobe_trampoline_entries(entry, start_entry_idx);
> }
> }
>
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d60d24f0f2f4..1c99380dc89d 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -2149,6 +2149,15 @@ static void handle_trampoline(struct pt_regs *regs)
>
> instruction_pointer_set(regs, ri->orig_ret_vaddr);
> do {
> + /* pop current instance from the stack of pending return instances,
> + * as it's not pending anymore: we just fixed up original
> + * instruction pointer in regs and are about to call handlers;
> + * this allows fixup_uretprobe_trampoline_entries() to properly fix up
> + * captured stack traces from uretprobe handlers, in which pending
> + * trampoline addresses on the stack are replaced with correct
> + * original return addresses
> + */
> + utask->return_instances = ri->next;
> if (valid)
> handle_uretprobe_chain(ri, regs);
> ri = free_ret_instance(ri);
> --
> 2.43.0
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
next prev parent reply other threads:[~2024-06-04 14:13 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-22 1:38 [PATCH v2 0/4] Fix user stack traces captured from uprobes Andrii Nakryiko
2024-05-22 1:38 ` [PATCH v2 1/4] uprobes: rename get_trampoline_vaddr() and make it global Andrii Nakryiko
2024-06-25 0:28 ` Masami Hiramatsu
2024-06-25 1:02 ` Masami Hiramatsu
2024-05-22 1:38 ` [PATCH v2 2/4] perf,uprobes: fix user stack traces in the presence of pending uretprobes Andrii Nakryiko
2024-06-04 14:13 ` Masami Hiramatsu [this message]
2024-06-04 17:16 ` Andrii Nakryiko
2024-06-17 22:37 ` Andrii Nakryiko
2024-06-24 20:32 ` Andrii Nakryiko
2024-06-25 0:39 ` Masami Hiramatsu
2024-06-25 2:51 ` Andrii Nakryiko
2024-05-22 1:38 ` [PATCH v2 3/4] perf,x86: avoid missing caller address in stack traces captured in uprobe Andrii Nakryiko
2024-06-04 9:24 ` Jiri Olsa
2024-06-04 14:06 ` Masami Hiramatsu
2024-06-04 17:13 ` Andrii Nakryiko
2024-05-22 1:38 ` [PATCH v2 4/4] selftests/bpf: add test validating uprobe/uretprobe stack traces Andrii Nakryiko
2024-06-04 9:24 ` Jiri Olsa
2024-06-25 1:14 ` Masami Hiramatsu
2024-06-25 2:53 ` Andrii Nakryiko
2024-06-25 1:22 ` Masami Hiramatsu
2024-06-03 21:09 ` [PATCH v2 0/4] Fix user stack traces captured from uprobes Andrii Nakryiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240604231314.e924c51f7b9a18428a8a7f0f@kernel.org \
--to=mhiramat@kernel.org \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rihams@fb.com \
--cc=rihams@meta.com \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).