Re: [PATCH v9 27/29] perf evsel: Add bounds checking to trace point raw data accessors

sashiko-bot
2026-04-11T19:46:56Z

Sashiko AI review found 3 potential issue(s):
- [High] Signed integer overflow and negative values in bounds checks allow bypassing the validation.
- [High] Missing bounds check for dynamically calculated tracepoint field offsets.
- [Medium] Out-of-bounds read when reading 4-byte dynamic locator for fields with small size.
--

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

perf evsel: Add bounds checking to trace point raw data accessors

This commit adds bounds checking for tracepoint field access in perf's evsel
logic to avoid out-of-bounds reads. It checks that the field's offset and size
do not exceed the raw data size of the sample.

> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 3c10b840778e0..1e0bb4cb995d4 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -3727,6 +3727,11 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name)
> return NULL;
>
> offset = field->offset;
> + if ((u32)(offset + field->size) > sample->raw_size) {

Could this overflow or wrap around? Both offset and field->size are signed
integers. If offset is negative and field->size is positive, their sum might
be a small positive number that passes the sample->raw_size check, but would
result in an out-of-bounds pointer calculation.

Similarly, could very large positive values overflow the 32-bit addition and
bypass the check?

> + pr_warning("Invalid trace point field offset %d for field of length %d in sample raw data of size %u\n",
> + offset, field->size, sample->raw_size);
> + return NULL;
> + }
>
> if (field->flags & TEP_FIELD_IS_DYNAMIC) {
> offset = *(int *)(sample->raw_data + field->offset);

Can this lead to an out-of-bounds read if field->size is less than 4?
The initial bounds check validates field->size, but if the field is dynamic
and field->size is less than sizeof(int), this dereference will read past
the validated bounds.

> offset &= 0xffff;
> if (tep_field_is_relative(field->flags))
> offset += field->offset + field->size;
> }
>
> return sample->raw_data + offset;

Does this dynamically calculated offset need its own bounds check?
If the field is dynamic, offset is reassigned but never validated against
sample->raw_size before returning the pointer, which could allow a crafted
sample to return an out-of-bounds pointer.

[ ... ]

> @@ -3744,6 +3749,12 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam
> u64 value;
> void *ptr = sample->raw_data + field->offset;
>
> + if ((u32)(field->offset + field->size) > sample->raw_size) {

As above, can field->offset and field->size contain negative values or
overflow the 32-bit addition, potentially bypassing this bounds check?

> + pr_warning("Invalid trace point field offset %d for field of length %d in sample raw data of size %u\n",
> + field->offset, field->size, sample->raw_size);
> + return 0;
> + }

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