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 5/8] perf tools: Internal support for BUILD_ID_OFFSET
Date: Fri, 07 Aug 2026 08:41:42 +0000 [thread overview]
Message-ID: <20260807084143.0FE6B1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260807071818.718751-6-irogers@google.com>
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Synthesizing an event with PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET but without PERF_SAMPLE_CALLCHAIN causes a NULL pointer dereference.
- [High] Copying `callchain_bids` during event synthesis uses the potentially unrelated length `sample->callchain->nr`, leading to a heap buffer over-read.
- [High] Array access on `sample->callchain_bids` uses the unverified index `j` derived from `chain->nr`, leading to a heap buffer over-read.
- [High] `add_callchain_ip` ignores the `bid` and `offset` arguments when `cpumode` is set, breaking callchain resolution for `PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET`.
- [High] Missing `OVERFLOW_CHECK` when parsing `PERF_SAMPLE_BUILD_ID_OFFSET` allows out-of-bounds reads on malformed events.
- [Medium] `__evsel__parse_sample` fails to unswap the byte layout of `struct perf_build_id` when `swapped` is true, corrupting cross-endian perf.data analysis.
- [Medium] The test suite in `sample-parsing.c` is not updated for the new flags, causing immediate failure.
- [Medium] `thread__find_map` fails to resolve build IDs because `sample->ip` takes precedence over `sample->bid.bid`, misinterpreting the offset as a virtual address.
- [Medium] `leaf_frame_caller` incorrectly inherits the build ID and offset of its callee in `thread__resolve_callchain_sample`.
--
--- Patch [5]: [RFC PATCH v1 5/8] perf tools: Internal support for BUILD_ID_OFFSET ---
commit fbd06af754237e67a7a1661b582808d4407ddb3e
Author: Ian Rogers <irogers@google.com>
Subject: perf tools: Internal support for BUILD_ID_OFFSET
This patch implements user-space parsing for the new sample types in evsel.
It updates perf_event_attr_fprintf to display the new bits in 'perf report -D'
and updates synthetic event parameter names.
[Severity: Medium]
There appears to be an omission outside of the files modified by this patch:
Has test__sample_parsing() in tools/perf/tests/sample-parsing.c been
updated for the new flags? If PERF_SAMPLE_MAX was updated, the hardcoded
safety check:
if (PERF_SAMPLE_MAX > PERF_SAMPLE_WEIGHT_STRUCT << 1)
might cause the test suite to unconditionally abort.
> diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
> --- a/tools/perf/util/event.c
> +++ b/tools/perf/util/event.c
> @@ -740,15 +734,33 @@ struct map *thread__find_map(struct thread *thread, struct perf_sample *sample,
>
> return NULL;
> }
> - al->map = maps__find(maps, al->addr);
> - if (al->map != NULL) {
> - /*
> - * Kernel maps might be changed when loading symbols so loading
> - * must be done prior to using kernel maps.
> - */
> - if (load_map)
> - map__load(al->map);
> - al->addr = map__map_ip(al->map, al->addr);
> +
> + if (sample->ip) {
> + al->addr = sample->ip;
> + al->map = maps__find(maps, al->addr);
[Severity: Medium]
When resolving callchains, sample->ip is typically populated with the file
offset. Because sample->ip takes precedence in this if/else chain, will the
offset be incorrectly evaluated as a virtual address via maps__find(),
causing the resolution to skip maps__find_by_build_id() entirely?
> + if (al->map != NULL) {
[ ... ]
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -3778,6 +3778,30 @@ int __evsel__parse_sample(struct evsel *evsel, union perf_event *event,
> array = (void *)array + sz;
> }
>
> + if (type & PERF_SAMPLE_BUILD_ID_OFFSET) {
> + data->bid.bid = (struct perf_build_id *) array;
[Severity: Medium]
During cross-platform analysis of perf.data files from a different
endianness, the event array is 64-bit byte-swapped prior to parsing. Since
struct perf_build_id contains mixed-size fields (8-bit, 16-bit, 32-bit,
and a byte array), does this code need to unswap the layout similar to how
PERF_SAMPLE_AUX uses mem_bswap_64() to prevent data corruption?
> + array += sizeof(struct perf_build_id) / sizeof(u64);
> + data->bid.offset = *array;
> + array++;
[Severity: High]
Should there be an OVERFLOW_CHECK_u64(array) before dereferencing array
for the offset? Since PERF_SAMPLE_BUILD_ID_OFFSET is not part of
PERF_SAMPLE_MASK, its size isn't included in evsel->sample_size,
which could allow an out-of-bounds read on truncated events.
> + } else {
> + data->bid.bid = NULL;
> + data->bid.offset = 0;
> + }
[ ... ]
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -2216,7 +2216,9 @@ static int add_callchain_ip(struct thread *thread,
> struct branch_flags *flags,
> struct iterations *iter,
> u64 branch_from,
> - bool symbols)
> + bool symbols,
> + struct perf_build_id *bid,
> + u64 offset)
> {
> struct map_symbol ms = {};
> struct addr_location al;
> @@ -2230,7 +2232,9 @@ static int add_callchain_ip(struct thread *thread,
> al.srcline = NULL;
> if (!cpumode) {
> thread__find_cpumode_addr_location(thread,
> - &(struct perf_sample){.ip = ip},
> + &(struct perf_sample){.ip = ip,
> + .bid = { .bid = bid,
> + .offset = offset }},
> symbols, &al);
> } else {
[Severity: High]
In thread__resolve_callchain_sample(), cpumode is initialized locally and
its address (&cpumode) is passed to add_callchain_ip(), meaning cpumode is
never NULL. Doesn't this force execution into the else branch here?
The else branch constructs a temporary struct perf_sample that omits the
new bid and offset parameters, which silently drops the data before
map/symbol resolution.
[ ... ]
> @@ -2979,13 +3003,19 @@ static int thread__resolve_callchain_sample(struct thread *thread,
> continue;
> #endif
> ip = chain->ips[j];
> + if (sample->callchain_bids) {
> + bid = (struct perf_build_id *)&((u64 *)sample->callchain_bids)[j * 4];
> + offset = ((u64 *)sample->callchain_bids)[j * 4 + 3];
> + }
[Severity: High]
Since the loop index j is bounded by chain->nr rather than
sample->callchain_bids_nr, could a malformed event where chain->nr exceeds
the actual length of callchain_bids cause a heap buffer over-read here?
> if (ip < PERF_CONTEXT_MAX)
> ++nr_entries;
[ ... ]
> @@ -3011,21 +3041,28 @@ static int thread__resolve_callchain_sample(struct thread *thread,
>
> err = add_callchain_ip(thread, cursor, parent,
> root_al, &cpumode, leaf_frame_caller,
> - false, NULL, NULL, 0, symbols);
> - if (err)
> - return (err < 0) ? err : 0;
> + false, NULL, NULL, 0, symbols, bid, offset);
[Severity: Medium]
When synthesizing a missing caller frame (leaf_frame_caller), this passes
the bid and offset variables belonging to the current frame (j, the callee)
into add_callchain_ip(). Does this incorrectly associate the synthesized
caller's IP with the callee's build ID?
> + if (err) {
> + err = (err < 0) ? err : 0;
> + goto out;
> + }
[ ... ]
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -1701,6 +1701,13 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
> result += sample->aux_sample.size;
> }
>
> + if (type & PERF_SAMPLE_BUILD_ID_OFFSET)
> + result += sizeof(struct perf_build_id) + sizeof(u64);
> +
> + if (type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET)
> + result += sizeof(u64) + sample->callchain->nr *
> + (sizeof(struct perf_build_id) + sizeof(u64));
> +
> return result;
> }
[Severity: High]
If an event contains PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET but not
PERF_SAMPLE_CALLCHAIN, sample->callchain will be NULL. Does this sequence
unconditionally dereference sample->callchain->nr and cause a crash?
[ ... ]
> @@ -1933,6 +1940,19 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
> array = (void *)array + sz;
> }
>
> + if (type & PERF_SAMPLE_BUILD_ID_OFFSET) {
> + memcpy(array, sample->bid.bid, sizeof(struct perf_build_id));
> + array += sizeof(struct perf_build_id) / sizeof(u64);
> + *array++ = sample->bid.offset;
> + }
> +
> + if (type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) {
> + *array++ = sample->callchain->nr;
> + sz = sample->callchain->nr * (sizeof(struct perf_build_id) + sizeof(u64));
> + memcpy(array, sample->callchain_bids, sz);
[Severity: High]
Should this use sample->callchain_bids_nr instead of sample->callchain->nr
for the copy size calculation? If a malformed event provides a chain->nr
that is larger than the true bounds of callchain_bids, could this
copy out-of-bounds heap memory into the synthesized event stream?
> + array += sz / sizeof(u64);
> + }
> +
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260807071818.718751-1-irogers@google.com?part=5
next prev parent reply other threads:[~2026-08-07 8:41 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 [this message]
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
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=20260807084143.0FE6B1F000E9@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 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.