Linux Perf Users
 help / color / mirror / Atom feed
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: sashiko-reviews@lists.linux.dev
Cc: sashiko-bot@kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v7 01/10] tracing: wprobe: Add watchpoint probe event based on hardware breakpoint
Date: Thu, 16 Jul 2026 00:11:33 +0900	[thread overview]
Message-ID: <20260716001133.657b9a4fe095965a06b218bc@kernel.org> (raw)
In-Reply-To: <20260715020140.005751F000E9@smtp.kernel.org>

On Wed, 15 Jul 2026 02:01:39 +0000
sashiko-bot@kernel.org wrote:

> Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
> - [High] Missing error rollback in enable_trace_wprobe() leaves dangling event file links and active hardware breakpoints, leading to Use-After-Free and resource leaks.
> - [High] Format string bugs in trace_wprobe_show break the dynamic_events save and restore functionality.
> - [Medium] wprobes silently drop all perf events because the hardware breakpoint handler lacks perf ring buffer delivery logic.
> - [Medium] wprobe_trace_handler silently drops events if the hardware breakpoint address was updated, contradicting the stated design.
> - [Medium] Unconditional memory leak of the dynamically allocated `symbol` string in `__trace_wprobe_create()`.
> - [Medium] Undocumented `$value` variable is implemented, contradicting the commit message claims.

Thanks for the comments.

> --
> 
> --- Patch [1]: [PATCH v7 01/10] tracing: wprobe: Add watchpoint probe event based on hardware breakpoint ---
> commit f8a7aeb231575f15f9227ab411134bde7408e480
> Author: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> 
> tracing: wprobe: Add watchpoint probe event based on hardware breakpoint
>     
> This patch adds a new dynamic event for hardware breakpoints, called a
> wprobe-event. It allows users to trace memory access at specified addresses
> or symbols, supporting both ftrace and perf interfaces.
> 
> Link: https://lore.kernel.org/all/175859021100.374439.8723137923620348816.stgit@devnote2/
> 
> > User also can use $addr to fetch the accessed address. But no other
> > variables are supported. To record updated value, use '+0($addr)'.
> 
> [Severity: Medium]
> Is this documentation accurate?
> 
> Looking at parse_probe_vars(), it explicitly parses and handles a $value
> variable:
> 
> parse_probe_vars() {
>     ...
>     if (!strcmp(arg, "value")) {
>         code->op = FETCH_OP_BADDR;
>         code++;
>         code->op = FETCH_OP_DEREF;
> ...
> 
> Should the commit message be updated to reflect that $value is actually
> supported?

Good catch! Yeah $value was added, so we don't need to use +0($addr).
The $addr is used for ensuring watching address. That will be useful when
wprobe trigger is introduced.

> 
> > diff --git a/kernel/trace/trace_wprobe.c b/kernel/trace/trace_wprobe.c
> > new file mode 100644
> > index 0000000000000..b52f3eac719f9
> > --- /dev/null
> > +++ b/kernel/trace/trace_wprobe.c
> 
> [ ... ]
> 
> > +static void wprobe_trace_handler(struct trace_wprobe *tw,
> > +				 unsigned long addr,
> > +				 struct pt_regs *regs,
> > +				 struct trace_event_file *trace_file)
> > +{
> 
> [ ... ]
> 
> > +	if (trace_trigger_soft_disabled(trace_file))
> > +		return;
> > +
> > +	if (tw->addr != addr)
> > +		return;
> 
> [Severity: Medium]
> Does this strict address comparison inadvertently drop valid events if the
> hardware breakpoint address was updated dynamically?

Yes, to avoid confusion, if the watchpoint is changed on another CPU,
it is better to be skipped.

> 
> The v7 changelog mentions using the dynamic address because the original
> address can be updated from another CPU, but this check causes the handler
> to exit immediately if the updated address differs from the statically
> recorded tw->addr.

Yeah, this is something for wprobe trigger, which will dynamically update
the tw->addr. So maybe we can move this in wprobe event trigger patch.

> 
> [ ... ]
> 
> > +static void wprobe_perf_handler(struct perf_event *bp,
> > +			      struct perf_sample_data *data,
> > +			      struct pt_regs *regs)
> > +{
> > +	struct trace_wprobe *tw = bp->overflow_handler_context;
> > +	struct event_file_link *link;
> > +	unsigned long addr = bp->attr.bp_addr;
> > +
> > +	trace_probe_for_each_link_rcu(link, &tw->tp)
> > +		wprobe_trace_handler(tw, addr, regs, link->file);
> > +}
> 
> [Severity: Medium]
> Does this handler omit the necessary logic to generate and submit perf
> samples?

Ah, OK. This should not be used from perf. I think this should be
explicitly prohibited at this moment.


> 
> [ ... ]
> 
> > +static int enable_trace_wprobe(struct trace_event_call *call,
> > +			       struct trace_event_file *file)
> > +{
> 
> [ ... ]
> 
> > +	if (file) {
> > +		ret = trace_probe_add_file(tp, file);
> > +		if (ret)
> > +			return ret;
> > +	} else {
> > +		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
> > +	}
> > +
> > +	if (!enabled) {
> > +		list_for_each_entry(tw, trace_probe_probe_list(tp), tp.list) {
> > +			ret = __register_trace_wprobe(tw);
> > +			if (ret < 0) {
> > +				/* TODO: rollback */
> > +				return ret;
> > +			}
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> 
> [Severity: High]
> Could this missing rollback logic lead to a use-after-free or memory
> corruption if a later hardware breakpoint registration fails?

OK, to avoid memory corruption add a rollback logic here.

> [ ... ]
> 
> > +static int parse_address_spec(const char *spec, unsigned long *addr, int *type,
> > +			      int *len, char **symbol)
> > +{
> 
> [ ... ]
> 
> > +	if (kstrtoul(at + 1, 0, &_addr) != 0) {
> > +		char *off_str = strpbrk(at + 1, "+-");
> > +		int offset = 0;
> > +
> > +		if (off_str) {
> > +			if (kstrtoint(off_str, 0, &offset) != 0) {
> > +				trace_probe_log_err(off_str - _spec, BAD_PROBE_ADDR);
> > +				return -EINVAL;
> > +			}
> > +			*off_str = '\0';
> > +		}
> > +		_addr = kallsyms_lookup_name(at + 1);
> > +		if (!_addr) {
> > +			trace_probe_log_err(at + 1 - _spec, BAD_ACCESS_ADDR);
> > +			return -ENOENT;
> > +		}
> > +		_addr += offset;
> > +		*symbol = kstrdup(at + 1, GFP_KERNEL);
> > +		if (!*symbol)
> > +			return -ENOMEM;
> > +	}
> 
> [Severity: High]
> Could the null terminator injection here break dynamic_events save and
> restore functionality for events with symbol offsets?
> 
> When the event is created with a symbol offset (like symbol+8), *off_str
> is overwritten with a null byte. This truncates the string before it gets
> duplicated into *symbol.
> 
> Later, trace_wprobe_show() outputs the truncated base symbol without the
> offset, meaning the restored event will monitor the wrong memory address.

Since the symbol is used for making the event name, it should not have
offset.  However, in trace_wprobe_show(), the symbol is directly used
to show the target address. Thus, instead of changing
parse_address_spec(), we need to update trace_wprobe_show() to use
kallsyms_lookup_name() to find the symbol address and calculate the
offset from tw->addr and symbol address, and print out the "symbol+offset".

> 
> [ ... ]
> 
> > +static int __trace_wprobe_create(int argc, const char *argv[])
> > +{
> 
> [ ... ]
> 
> > +	char *symbol = NULL;
> > +	unsigned long addr;
> > +	int len, type, i;
> > +	int ret = 0;
> > +
> 
> [ ... ]
> 
> > +	trace_probe_log_set_index(1);
> > +	ret = parse_address_spec(argv[1], &addr, &type, &len, &symbol);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (!event)
> > +		event = symbol ? symbol : "wprobe";
> > +
> > +	argc -= 2; argv += 2;
> > +	tw = alloc_trace_wprobe(group, event, symbol, addr, len, type, argc);
> > +	if (IS_ERR(tw))
> > +		return PTR_ERR(tw);
> 
> [Severity: Medium]
> Does this leak the dynamically allocated symbol string?
> 
> The symbol variable is populated with an allocated string from
> parse_address_spec(). When passed to alloc_trace_wprobe(), that function
> duplicates the string again:
> 
> alloc_trace_wprobe() {
>     ...
>     if (symbol) {
>         tw->symbol = kstrdup(symbol, GFP_KERNEL);
>     ...
> }
> 
> However, __trace_wprobe_create() never frees the original symbol string on
> either the success or error paths.

Yes, let me use __free() macro to free it.

> 
> [ ... ]
> 
> > +static int trace_wprobe_show(struct seq_file *m, struct dyn_event *ev)
> > +{
> > +	struct trace_wprobe *tw = to_trace_wprobe(ev);
> > +	int i;
> > +
> > +	seq_printf(m, "w:%s/%s", trace_probe_group_name(&tw->tp),
> > +		   trace_probe_name(&tw->tp));
> > +
> > +	char type_char;
> > +
> > +	if (tw->type == HW_BREAKPOINT_R)
> > +		type_char = 'r';
> > +	else if (tw->type == HW_BREAKPOINT_W)
> > +		type_char = 'w';
> > +	else
> > +		type_char = 'x'; /* Should be rw */
> 
> [Severity: High]
> Will outputting 'x' for HW_BREAKPOINT_RW cause parse_address_spec() to
> reject the configuration upon restore?
> 
> If type_char is set to 'x', the formatted string saved to dynamic_events
> will be invalid. When the system attempts to restore the event across
> reboots, parse_address_spec() checks strictly for 'r', 'w', or 'rw', and
> will fail with -EINVAL for 'x'.
> 
> Should this be adjusted to output a string like "rw" instead?

Ah, good catch. Let me use rw instead.

Thank you,

-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

  reply	other threads:[~2026-07-15 15:11 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-15  1:43 [PATCH v7 00/10] tracing: wprobe: x86: Add wprobe for watchpoint Masami Hiramatsu (Google)
2026-07-15  1:44 ` [PATCH v7 01/10] tracing: wprobe: Add watchpoint probe event based on hardware breakpoint Masami Hiramatsu (Google)
2026-07-15  2:01   ` sashiko-bot
2026-07-15 15:11     ` Masami Hiramatsu [this message]
2026-07-15  1:44 ` [PATCH v7 02/10] x86: hw_breakpoint: Add a kconfig to clarify when a breakpoint fires Masami Hiramatsu (Google)
2026-07-15  1:57   ` sashiko-bot
2026-07-15  1:44 ` [PATCH v7 03/10] selftests: tracing: Add a basic testcase for wprobe Masami Hiramatsu (Google)
2026-07-15  1:52   ` sashiko-bot
2026-07-15  1:44 ` [PATCH v7 04/10] selftests: tracing: Add syntax " Masami Hiramatsu (Google)
2026-07-15  1:44 ` [PATCH v7 05/10] tracing: wprobe: Use a new seq_print_ip_sym_offset() wrapper Masami Hiramatsu (Google)
2026-07-15  2:02   ` sashiko-bot
2026-07-15  1:45 ` [PATCH v7 06/10] x86/hw_breakpoint: Unify breakpoint install/uninstall Masami Hiramatsu (Google)
2026-07-15  1:59   ` sashiko-bot
2026-07-15  1:45 ` [PATCH v7 07/10] x86/hw_breakpoint: Add arch_reinstall_hw_breakpoint Masami Hiramatsu (Google)
2026-07-15  2:13   ` sashiko-bot
2026-07-15  1:45 ` [PATCH v7 08/10] HWBP: Add modify_wide_hw_breakpoint_local() API Masami Hiramatsu (Google)
2026-07-15  2:00   ` sashiko-bot
2026-07-15  1:45 ` [PATCH v7 09/10] tracing: wprobe: Add wprobe event trigger Masami Hiramatsu (Google)
2026-07-15  2:05   ` sashiko-bot
2026-07-15  1:45 ` [PATCH v7 10/10] selftests: ftrace: Add wprobe trigger testcase Masami Hiramatsu (Google)
2026-07-15  2:16   ` sashiko-bot

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=20260716001133.657b9a4fe095965a06b218bc@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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