Linux Perf Users
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ian Rogers" <irogers@google.com>
Cc: bpf@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [RFC PATCH v1 6/8] perf inject: Extend perf inject to support bid_offset conversion
Date: Fri, 07 Aug 2026 09:18:52 +0000	[thread overview]
Message-ID: <20260807091852.EDDE61F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260807071818.718751-7-irogers@google.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Integer overflow in `u16 max_size` calculation bypasses bounds check, leading to a massive heap buffer overflow.
- [High] Missing `inject_bid_offset_tool__new` instantiation and fatal invalid pointer free on error path.
- [High] Unused attribute rewriting functions lead to complete data corruption in output `perf.data`.
- [High] Raw event copying incorrectly checks `branch_sample_type` flags against the `sample_type` bitmask, aliasing with other flags.
- [High] Incorrect event boundary calculations allow the tool to read out-of-bounds memory up to 16 bytes past the event buffer.
- [High] Missing curly braces around `PERF_SAMPLE_READ` format condition checks leads to unconditional array execution, corrupting the sample payload.
- [Medium] Missing explicit inclusion of POSIX standard libc headers `<errno.h>` and `<string.h>` breaks musl compatibility.
--

--- Patch [6]: [RFC PATCH v1 6/8] perf inject: Extend perf inject to support bid_offset conversion ---
commit 00dac7cb64934c318662c48215a38d4a8f9ec625
Author: Ian Rogers <irogers@google.com>

perf inject: Extend perf inject to support bid_offset conversion

This patch adds a --sample-buildids option to perf inject. It drops MMAP
events and rewrites samples to use build IDs and offsets instead of virtual
addresses.

> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index 6aa9e3eea4383..8f8d5267a37e2 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
[ ... ]
> @@ -2880,8 +2889,11 @@ int cmd_inject(int argc, const char **argv)
>  
>  	if (IS_ERR(inject.session)) {
>  		ret = PTR_ERR(inject.session);
> +
>  		if (inject.aslr)
>  			aslr_tool__delete(tool);
> +		if (inject.build_id_style == BID_RWS__SAMPLE_BUILDID)
> +			inject_bid_offset_tool__delete(tool);

[Severity: High]
Does this code call inject_bid_offset_tool__delete() on an invalid pointer
if __perf_session__new() fails? It appears inject_bid_offset_tool__new() is
never called to instantiate the tool during setup, so when running with
--sample-buildids, this error path will use container_of() and free() on an
uninitialized or incorrect pointer, crashing the tool.

>  		goto out_close_output;
>  	}
>  
> diff --git a/tools/perf/util/inject_bid_offset.c b/tools/perf/util/inject_bid_offset.c
> new file mode 100644
> index 0000000000000..f7b5fb05fac79
> --- /dev/null
> +++ b/tools/perf/util/inject_bid_offset.c
> @@ -0,0 +1,504 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include "inject_bid_offset.h"
> +
> +#include <stdlib.h>
> +
> +#include <linux/compiler.h>
> +#include <linux/string.h>

[Severity: Medium]
Will this file fail to build against musl libc? According to the POSIX
standard, files using POSIX constants like -E2BIG, -EFAULT and functions
like memcpy() need to explicitly include <errno.h> and <string.h>.

> +#include <linux/zalloc.h>
[ ... ]
> +int perf_event__rewrite_attr_for_build_id_offset(struct perf_event_attr *attr)
> +{

[Severity: High]
Is this attribute rewriting function dead code? It seems to be defined but
never called. Since inject_bid_offset_tool__sample() strips PERF_SAMPLE_IP
and appends PERF_SAMPLE_BUILD_ID_OFFSET, leaving the event attributes
unmodified will cause downstream tools like perf report to parse the
rewritten build-id payloads using the old schema, corrupting the data.

> +	if (attr->sample_type & (PERF_SAMPLE_BUILD_ID_OFFSET |
> +				 PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET)) {
[ ... ]
> +static int inject_bid_offset_tool__sample(const struct perf_tool *tool,
> +					  union perf_event *event,
> +					  struct perf_sample *sample,
> +					  struct machine *machine)
> +{
[ ... ]
> +	__u64 i = 0, j = 0;
> +	__u64 *in_array, *out_array;
> +	__u64 sample_type = evsel->core.attr.sample_type;
> +	const __u64 max_i = event->header.size / sizeof(__u64);
> +	struct thread *thread;
> +	u16 max_size = event->header.size;

[Severity: Critical]
Can this variable overflow when adding the callchain size below? Because
max_size is typed as u16, when processing an event with a large
sample->callchain->nr, adding the size could cause it to wrap around.

> +
> +	if ((sample_type & (PERF_SAMPLE_IP | PERF_SAMPLE_CALLCHAIN)) == 0)
[ ... ]
> +	if (sample_type & PERF_SAMPLE_CALLCHAIN) {
> +		max_size +=
> +			sample->callchain->nr * (sizeof(struct perf_build_id) +
> +						 sizeof(u64) - sizeof(u64));
> +	}
> +
> +	if (max_size > PERF_SAMPLE_MAX_SIZE) {

[Severity: Critical]
If max_size wraps around, will this bounds check (against 65536) bypass the
protection, leading to a massive out-of-bounds write later in the loop when
writing the unvalidated payload?

> +		pr_debug("Insufficient space to copy event\n");
> +		thread__put(thread);
> +		return -E2BIG;
> +	}
[ ... ]
> +	in_array = &event->sample.array[0];
> +	out_array = &ev->sample.array[0];
> +
> +	if (sample_type & PERF_SAMPLE_IDENTIFIER) {
> +		if (i > max_i)
> +			goto err;

[Severity: High]
Does this boundary calculation allow reading past the event buffer? max_i
represents the total number of 64-bit words including the 8-byte header,
but in_array points to the array skipping the header. Checking against
max_i loosely allows index i to read out of bounds.

> +		out_array[j++] = in_array[i++];
> +	}
[ ... ]
> +	if (sample_type & PERF_SAMPLE_READ) {
> +		if ((evsel->core.attr.read_format & PERF_FORMAT_GROUP) == 0) {
> +			if (i > max_i)
> +				goto err;
> +			out_array[j++] = in_array[i++];
> +			if (evsel->core.attr.read_format &
> +			    PERF_FORMAT_TOTAL_TIME_ENABLED)
> +				if (i > max_i)
> +					goto err;
> +			out_array[j++] = in_array[i++];

[Severity: High]
Will this execute unconditionally? Because of the missing curly braces
around the condition check, it looks like only the if (i > max_i) goto
err; check is conditional on PERF_FORMAT_TOTAL_TIME_ENABLED, causing the
out_array assignment to always execute and misalign all subsequent fields
if the flag is absent.

> +			if (evsel->core.attr.read_format &
> +			    PERF_FORMAT_TOTAL_TIME_RUNNING)
> +				if (i > max_i)
> +					goto err;
> +			out_array[j++] = in_array[i++];
[ ... ]
> +		} else {
> +			u64 nr;
[ ... ]
> +			for (u64 cntr = 0; cntr < nr; cntr++) {
> +				if (i > max_i)
> +					goto err;
> +				out_array[j++] = in_array[i++];
> +				if (evsel->core.attr.read_format &
> +				    PERF_FORMAT_ID)
> +					if (i > max_i)
> +						goto err;
> +				out_array[j++] = in_array[i++];

[Severity: High]
Are there missing curly braces here as well? The array copy appears to
execute unconditionally, potentially corrupting the event if
PERF_FORMAT_ID is absent.

[ ... ]
> +	if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
> +		if (i > max_i)
> +			goto err;
> +		out_array[j++] = in_array[i++];
> +		if (sample_type & PERF_SAMPLE_BRANCH_HW_INDEX) {

[Severity: High]
Does this code check the wrong bitmask? PERF_SAMPLE_BRANCH_HW_INDEX belongs
to branch_sample_type, not sample_type. Checking it against sample_type
means it aliases with PERF_SAMPLE_TRANSACTION, which might incorrectly
consume fields and corrupt the payload for unrelated events.

> +			if (i > max_i)
> +				goto err;
> +			out_array[j++] = in_array[i++];
> +		}
> +		if (i + (sample->branch_stack->nr * 3) > max_i)
> +			goto err;
> +		memcpy(&out_array[j], &in_array[i],
> +		       sample->branch_stack->nr * 3 * sizeof(u64));
> +		i += sample->branch_stack->nr * 3;
> +		j += sample->branch_stack->nr * 3;
> +		if (sample_type & PERF_SAMPLE_BRANCH_COUNTERS) {

[Severity: High]
Similarly, does this alias with PERF_SAMPLE_PHYS_ADDR since
PERF_SAMPLE_BRANCH_COUNTERS is a branch_sample_type flag, rather than a
sample_type flag?

> +			if (i + sample->branch_stack->nr > max_i)
> +				goto err;
[ ... ]

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

  reply	other threads:[~2026-08-07  9:18 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-07  7:18 [RFC PATCH v1 0/8] perf/core, perf/tools: Add PERF_SAMPLE_BUILD_ID_OFFSET support Ian Rogers
2026-08-07  7:18 ` [RFC PATCH v1 1/8] perf event: Factor build_id out into its own top-level struct Ian Rogers
2026-08-07  7:33   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 2/8] perf/core: Add BUILD_ID_OFFSET to UAPI Ian Rogers
2026-08-07  7:42   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 3/8] perf/core: Implement BUILD_ID_OFFSET sample type Ian Rogers
2026-08-07  7:54   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 4/8] perf: Refactor thread map and symbol APIs to take perf_sample Ian Rogers
2026-08-07  8:20   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 5/8] perf tools: Internal support for BUILD_ID_OFFSET Ian Rogers
2026-08-07  8:41   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 6/8] perf inject: Extend perf inject to support bid_offset conversion Ian Rogers
2026-08-07  9:18   ` sashiko-bot [this message]
2026-08-07  7:18 ` [RFC PATCH v1 7/8] perf record: Add --buildid-offset option Ian Rogers
2026-08-07  9:47   ` sashiko-bot
2026-08-07  7:18 ` [RFC PATCH v1 8/8] perf tests: Add build_id_offset test coverage Ian Rogers
2026-08-07  9:58   ` sashiko-bot
2026-08-07 11:18 ` [RFC PATCH v1 0/8] perf/core, perf/tools: Add PERF_SAMPLE_BUILD_ID_OFFSET support Peter Zijlstra

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=20260807091852.EDDE61F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=irogers@google.com \
    --cc=linux-perf-users@vger.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