All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ian Rogers" <irogers@google.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v1 2/2] perf inject: Fix itrace branch stack synthesis
Date: Tue, 28 Apr 2026 20:20:17 +0000	[thread overview]
Message-ID: <20260428202018.4FD63C2BCAF@smtp.kernel.org> (raw)
In-Reply-To: <20260428070328.1880314-3-irogers@google.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Silent data corruption due to removed error check in perf_event__convert_sample_callchain().
- [High] Pipe mode attribute headers incorrectly advertise PERF_SAMPLE_AUX, breaking downstream parsers.
- [High] Out-of-bounds write and parser breakage in perf_event__repipe_attr().
- [High] Unadvertised `size` field left in payload by perf_inject__cut_auxtrace_sample() breaks parsing.
- [High] Off-by-one error in sample size overflow check causes infinite parsing loops.
- [High] Dangling pointer vulnerability via `sample->branch_stack` stack variable assignment.
- [High] `hw_idx` omission in PEBS synthesis causes header vs payload mismatch.
--

commit e339fa2584e0f4ca5e2c4e8eb68d763fd40fbc59
Author: Ian Rogers <irogers@google.com>

perf inject: Fix itrace branch stack synthesis

This patch fixes several issues with perf inject --itrace=L when synthesizing
branch stacks from AUX data. It adjusts the sample types and event layout,
and addresses parsing issues and potential heap overflows.

> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c

[ ... ]

> @@ -223,6 +223,11 @@ static int perf_event__repipe_attr(const struct perf_tool *tool,
>  						  tool);
>  	int ret;
>  
> +	if (inject->itrace_synth_opts.add_last_branch) {
> +		event->attr.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
> +		event->attr.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
> +	}
> +

Does modifying event->attr.attr.sample_type before calling
perf_event__process_attr() risk an out-of-bounds write if the event buffer
is truncated?

Also, this populates the session's internal evsel with
PERF_SAMPLE_BRANCH_STACK, which might cause perf_evsel__parse_sample() to
fail on subsequent raw records that lack this data.

For pipe mode, this function dynamically emits headers but doesn't clear
PERF_SAMPLE_AUX from the repiped event->attr. Since the payload has the AUX
data stripped, does this cause downstream parsers to misinterpret event
boundaries because the header advertises data that isn't there?

>  	ret = perf_event__process_attr(tool, event, pevlist);

[ ... ]

> @@ -375,7 +380,60 @@ static int perf_event__repipe_sample(const struct perf_tool *tool,
>  
>  	build_id__mark_dso_hit(tool, event, sample, evsel, machine);
>  
> -	if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
> +	if (inject->itrace_synth_opts.set &&
> +	    (inject->itrace_synth_opts.last_branch ||
> +	     inject->itrace_synth_opts.add_last_branch)) {
> +		union perf_event *event_copy = (void *)inject->event_copy;
> +		struct branch_stack dummy_bs = { .nr = 0, .hw_idx = 0 };
> +		int err;

[ ... ]

> +		if (!sample->branch_stack)
> +			sample->branch_stack = &dummy_bs;

If PERF_FORMAT_GROUP is used, could this leave a dangling pointer?

If deliver_sample_group() reuses the exact same sample structure for
subsequent deliveries, sample->branch_stack will point to dummy_bs which
is allocated on the stack and goes out of scope when this function returns.

> +
> +		if (inject->itrace_synth_opts.add_last_branch) {
> +			/* Temporarily add in type bits for synthesis. */
> +			evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
> +			evsel->core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
> +		}
> +		evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
> +
> +		sz = perf_event__sample_event_size(sample, evsel->core.attr.sample_type,
> +						   evsel->core.attr.read_format,
> +						   evsel->core.attr.branch_sample_type);
> +
> +		if (sz > PERF_SAMPLE_MAX_SIZE) {

Does this allow sz to be exactly PERF_SAMPLE_MAX_SIZE (65536)?

If sz evaluates to 65536, assigning it to event_copy->header.size (a __u16)
would overflow and wrap to 0. Emitting an event with header.size = 0 can
cause downstream parsers to enter an infinite loop.

Should this check be >= PERF_SAMPLE_MAX_SIZE?

> +			pr_err("Sample size %zu exceeds max size %d\n", sz, PERF_SAMPLE_MAX_SIZE);
> +			return -EFAULT;
> +		}

[ ... ]

> +		if (err) {
> +			pr_err("Failed to synthesize sample\n");
> +			return err;
> +		}
> +		event = event_copy;
> +	} else if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
>  		event = perf_inject__cut_auxtrace_sample(inject, event, sample);

This fallback leaves an 8-byte size field (set to 0) in the sample payload.

Since PERF_SAMPLE_AUX is now globally cleared from the evsel headers in
__cmd_inject(), will parsers misinterpret this 8-byte field as the next
field in the format (like DATA_SRC) and shift all subsequent fields?

>  		if (IS_ERR(event))
>  			return PTR_ERR(event);

[ ... ]

> @@ -463,13 +521,9 @@ static int perf_event__convert_sample_callchain(const struct perf_tool *tool,
>  	/* remove sample_type {STACK,REGS}_USER for synthesize */
>  	sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER);
>  
> -	ret = perf_event__synthesize_sample(event_copy, evsel->core.attr.sample_type,
> -					    evsel->core.attr.read_format,
> -					    evsel->core.attr.branch_sample_type, sample);
> -	if (ret) {
> -		pr_err("Failed to synthesize sample\n");
> -		return ret;
> -	}
> +	perf_event__synthesize_sample(event_copy, sample_type,
> +				      evsel->core.attr.read_format,
> +				      evsel->core.attr.branch_sample_type, sample);
>  	return perf_event__repipe_synth(tool, event_copy);

Is it safe to remove the error check here?

If synthesis fails and returns a negative error code, event_copy might
remain uninitialized. Unconditionally passing it to perf_event__repipe_synth()
could write malformed or uninitialized memory to the output stream.

>  }

[ ... ]

> diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
> --- a/tools/perf/util/intel-pt.c
> +++ b/tools/perf/util/intel-pt.c

[ ... ]

> @@ -1731,6 +1731,7 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt,
>  static int intel_pt_inject_event(union perf_event *event,
>  				 struct perf_sample *sample, u64 type)
>  {
> +	event->header.type = PERF_RECORD_SAMPLE;
>  	event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
>  							   /*branch_sample_type=*/0);
>  

Since __cmd_inject() globally sets PERF_SAMPLE_BRANCH_HW_INDEX on all evsels
when add_last_branch is true, does passing branch_sample_type=0 here omit
the hw_idx field from synthesized PEBS samples?

Downstream parsers might misalign the payload if the file header advertises
its presence but the payload omits it.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260428070328.1880314-1-irogers@google.com?part=2

  reply	other threads:[~2026-04-28 20:20 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-28  7:03 [PATCH v1 0/2] perf inject intel-PT LBR/brstack synthesis fixes Ian Rogers
2026-04-28  7:03 ` [PATCH v1 1/2] perf event: Fix size of synthesized sample with branch stacks Ian Rogers
2026-04-28 23:19   ` Namhyung Kim
2026-04-28  7:03 ` [PATCH v1 2/2] perf inject: Fix itrace branch stack synthesis Ian Rogers
2026-04-28 20:20   ` sashiko-bot [this message]
2026-04-29 18:11 ` [PATCH v2 0/2] perf inject intel-PT LBR/brstack synthesis fixes Ian Rogers
2026-04-29 18:11   ` [PATCH v2 1/2] perf event: Fix size of synthesized sample with branch stacks Ian Rogers
2026-04-29 20:51     ` sashiko-bot
2026-04-29 18:11   ` [PATCH v2 2/2] perf inject: Fix itrace branch stack synthesis Ian Rogers
2026-04-29 21:18     ` 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=20260428202018.4FD63C2BCAF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=irogers@google.com \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.