* [PATCHES 0/5 v1] perf tools auxtrace hardening series
@ 2026-07-27 16:17 Arnaldo Carvalho de Melo
2026-07-27 16:17 ` [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy Arnaldo Carvalho de Melo
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo
Hi,
Please consider applying,
- Arnaldo
Arnaldo Carvalho de Melo (5):
perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
perf auxtrace: Fix queue grow overflow and old array leak
perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero
tools/perf/util/arm-spe.c | 4 ++++
tools/perf/util/auxtrace.c | 15 ++++++++++-----
tools/perf/util/intel-bts.c | 2 +-
tools/perf/util/intel-pt.c | 2 +-
tools/perf/util/thread-stack.c | 2 +-
5 files changed, 17 insertions(+), 8 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
@ 2026-07-27 16:17 ` Arnaldo Carvalho de Melo
2026-07-27 16:32 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak Arnaldo Carvalho de Melo
` (4 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot
From: Arnaldo Carvalho de Melo <acme@redhat.com>
thread_stack__br_sample() copies the wrap-around portion of the branch
stack ring buffer with:
nr = min(ts->br_stack_pos, sz);
memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
'nr' is correctly bounded to min(br_stack_pos, sz) but the memcpy uses
the unbounded ts->br_stack_pos directly. When br_stack_pos exceeds
the remaining destination space 'sz', this writes past the destination
buffer.
Use 'nr' (the bounded value) in the memcpy size, matching the pattern
of the first memcpy in the same function.
Fixes: 86d67180b920 ("perf thread-stack: Add branch stack support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/thread-stack.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index c5ce741b07446482..1360f44421ef8bb8 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -642,7 +642,7 @@ void thread_stack__br_sample(struct thread *thread, int cpu,
sz -= nr;
be = &dst->entries[nr];
nr = min(ts->br_stack_pos, sz);
- memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
+ memcpy(be, &src->entries[0], bsz * nr);
}
}
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
2026-07-27 16:17 ` [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy Arnaldo Carvalho de Melo
@ 2026-07-27 16:17 ` Arnaldo Carvalho de Melo
2026-07-27 16:29 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check Arnaldo Carvalho de Melo
` (3 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot
From: Arnaldo Carvalho de Melo <acme@redhat.com>
auxtrace_queues__grow() has two bugs:
1. When idx is UINT_MAX, the caller passes new_nr_queues = idx + 1 = 0.
The function skips growing (since any nr_queues >= 0), returns
success, and the caller accesses queue_array[UINT_MAX] — an OOB
heap write. Fix by rejecting new_nr_queues == 0 up front.
2. The function allocates a new queue_array via calloc and copies
elements from the old array, but never frees the old array. Fix
by saving the old pointer and freeing it after the copy.
Fixes: e502789302a6ece9 ("perf auxtrace: Add helpers for queuing AUX area tracing data")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/auxtrace.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 0b851f32e98c8517..aa749e1c30365a02 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -251,8 +251,12 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
{
unsigned int nr_queues = queues->nr_queues;
struct auxtrace_queue *queue_array;
+ struct auxtrace_queue *old_array = queues->queue_array;
unsigned int i;
+ if (!new_nr_queues)
+ return -EINVAL;
+
if (!nr_queues)
nr_queues = AUXTRACE_INIT_NR_QUEUES;
@@ -267,16 +271,17 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
return -ENOMEM;
for (i = 0; i < queues->nr_queues; i++) {
- list_splice_tail(&queues->queue_array[i].head,
+ list_splice_tail(&old_array[i].head,
&queue_array[i].head);
- queue_array[i].tid = queues->queue_array[i].tid;
- queue_array[i].cpu = queues->queue_array[i].cpu;
- queue_array[i].set = queues->queue_array[i].set;
- queue_array[i].priv = queues->queue_array[i].priv;
+ queue_array[i].tid = old_array[i].tid;
+ queue_array[i].cpu = old_array[i].cpu;
+ queue_array[i].set = old_array[i].set;
+ queue_array[i].priv = old_array[i].priv;
}
queues->nr_queues = nr_queues;
queues->queue_array = queue_array;
+ free(old_array);
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
2026-07-27 16:17 ` [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy Arnaldo Carvalho de Melo
2026-07-27 16:17 ` [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak Arnaldo Carvalho de Melo
@ 2026-07-27 16:17 ` Arnaldo Carvalho de Melo
2026-07-27 16:35 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 4/5] perf intel-bts: " Arnaldo Carvalho de Melo
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot
From: Arnaldo Carvalho de Melo <acme@redhat.com>
min_sz is set to sizeof(u64) * INTEL_PT_PER_CPU_MMAPS, but the code
accesses auxtrace_info->priv[INTEL_PT_PER_CPU_MMAPS], which requires
at least INTEL_PT_PER_CPU_MMAPS + 1 elements. A file with exactly
min_sz bytes of priv data passes the size check but the access reads
one u64 past the validated region.
Use (INTEL_PT_PER_CPU_MMAPS + 1) to ensure the highest accessed index
is within bounds.
Fixes: 90e457f7be087005 ("perf tools: Add Intel PT support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/intel-pt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index d83439c8c7b0ab0f..9d6628169fd95772 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -4432,7 +4432,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
- size_t min_sz = sizeof(u64) * INTEL_PT_PER_CPU_MMAPS;
+ size_t min_sz = sizeof(u64) * (INTEL_PT_PER_CPU_MMAPS + 1);
struct intel_pt *pt;
void *info_end;
__u64 *info;
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/5] perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
` (2 preceding siblings ...)
2026-07-27 16:17 ` [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check Arnaldo Carvalho de Melo
@ 2026-07-27 16:17 ` Arnaldo Carvalho de Melo
2026-07-27 16:34 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero Arnaldo Carvalho de Melo
2026-07-27 16:31 ` [PATCHES 0/5 v1] perf tools auxtrace hardening series James Clark
5 siblings, 1 reply; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Same pattern as the Intel PT fix: min_sz is set to
sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE, but the code accesses
auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE], which requires at least
INTEL_BTS_SNAPSHOT_MODE + 1 elements.
Use (INTEL_BTS_SNAPSHOT_MODE + 1) to ensure the highest accessed index
is within bounds.
Fixes: d0170af7004dce9c ("perf tools: Add Intel BTS support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/intel-bts.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index 0b18ebd13f7c8456..02df3e46048912eb 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -830,7 +830,7 @@ int intel_bts_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
- size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE;
+ size_t min_sz = sizeof(u64) * (INTEL_BTS_SNAPSHOT_MODE + 1);
struct intel_bts *bts;
int err;
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
` (3 preceding siblings ...)
2026-07-27 16:17 ` [PATCH 4/5] perf intel-bts: " Arnaldo Carvalho de Melo
@ 2026-07-27 16:17 ` Arnaldo Carvalho de Melo
2026-07-27 16:32 ` sashiko-bot
2026-07-27 16:31 ` [PATCHES 0/5 v1] perf tools auxtrace hardening series James Clark
5 siblings, 1 reply; 12+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-07-27 16:17 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Leo Yan
From: Arnaldo Carvalho de Melo <acme@redhat.com>
arm_spe__alloc_metadata() reads nr_cpu from the auxtrace_info priv
array without validation. When a crafted perf.data provides nr_cpu=0,
the per_cpu_sz calculation divides by zero:
per_cpu_sz = (metadata_size - (hdr_sz * sizeof(u64))) / (*nr_cpu);
Reject nr_cpu <= 0 early, before the division. The caller already
treats NULL return with metadata_ver != 1 as a parse failure.
Fixes: e52abceb4b6c2723 ("perf arm-spe: Dump metadata with version 2")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/arm-spe.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index 552f063f126e6769..401aab529309cbd6 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -1605,6 +1605,10 @@ static u64 **arm_spe__alloc_metadata(struct perf_record_auxtrace_info *info,
hdr_sz = ptr[ARM_SPE_HEADER_SIZE];
*nr_cpu = ptr[ARM_SPE_CPUS_NUM];
+ /* nr_cpu is used as a divisor below */
+ if (*nr_cpu <= 0)
+ return NULL;
+
metadata = calloc(*nr_cpu, sizeof(*metadata));
if (!metadata)
return NULL;
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak
2026-07-27 16:17 ` [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak Arnaldo Carvalho de Melo
@ 2026-07-27 16:29 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-07-27 16:29 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] An infinite loop can be triggered in `auxtrace_heap__add()` when `queue_nr >= 0x80000000`. This is reachable via the CoreSight ETM decoder (`cs-etm.c`) which shifts `queue_nr` left by 16. An attacker can supply a malformed `perf.data` file with an AUXTRACE event `idx` of 32768 to trigger this.
--
--- Patch [2]: [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak ---
commit 6cc7c2090ef2457b5027b79136b869818ae856ee
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf auxtrace: Fix queue grow overflow and old array leak
auxtrace_queues__grow() has two bugs:
1. When idx is UINT_MAX, the caller passes new_nr_queues = idx + 1 = 0.
The function skips growing (since any nr_queues >= 0), returns
success, and the caller accesses queue_array[UINT_MAX] — an OOB
heap write. Fix by rejecting new_nr_queues == 0 up front.
2. The function allocates a new queue_array via calloc and copies
elements from the old array, but never frees the old array. Fix
by saving the old pointer and freeing it after the copy.
Fixes: e502789302a6ece9 ("perf auxtrace: Add helpers for queuing AUX area tracing data")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index 4cd2caf540152..171edddc982fc 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -251,8 +251,12 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
> {
> unsigned int nr_queues = queues->nr_queues;
> struct auxtrace_queue *queue_array;
> + struct auxtrace_queue *old_array = queues->queue_array;
> unsigned int i;
>
> + if (!new_nr_queues)
> + return -EINVAL;
> +
> if (!nr_queues)
> nr_queues = AUXTRACE_INIT_NR_QUEUES;
>
> @@ -267,16 +271,17 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
> return -ENOMEM;
>
> for (i = 0; i < queues->nr_queues; i++) {
> - list_splice_tail(&queues->queue_array[i].head,
> + list_splice_tail(&old_array[i].head,
> &queue_array[i].head);
> - queue_array[i].tid = queues->queue_array[i].tid;
> - queue_array[i].cpu = queues->queue_array[i].cpu;
> - queue_array[i].set = queues->queue_array[i].set;
> - queue_array[i].priv = queues->queue_array[i].priv;
> + queue_array[i].tid = old_array[i].tid;
> + queue_array[i].cpu = old_array[i].cpu;
> + queue_array[i].set = old_array[i].set;
> + queue_array[i].priv = old_array[i].priv;
> }
>
> queues->nr_queues = nr_queues;
> queues->queue_array = queue_array;
> + free(old_array);
>
> return 0;
> }
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the queue size
checks here, I noticed a similar unbounded shift loop in auxtrace_heap__add().
Could a malformed perf.data file with an AUXTRACE event idx of 32768 trigger
an infinite loop?
The CoreSight ETM decoder shifts the queue_nr left by 16:
tools/perf/util/cs-etm.c:TO_CS_QUEUE_NR() {
#define TO_CS_QUEUE_NR(queue_nr, trace_chan_id) \
(queue_nr << 16 | trace_chan_id)
}
If queue_nr is 32768, the macro evaluates to 0x80000000. When this value is
passed to auxtrace_heap__add(), it triggers this loop:
tools/perf/util/auxtrace.c:auxtrace_heap__add() {
if (queue_nr >= heap->heap_sz) {
unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES;
while (heap_sz <= queue_nr)
heap_sz <<= 1;
...
}
When heap_sz reaches 0x80000000, it satisfies 0x80000000 <= 0x80000000,
shifts left by 1 overflowing to 0, and then 0 <= 0x80000000 remains true
indefinitely, causing an infinite loop.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727161705.64807-1-acme@kernel.org?part=2
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCHES 0/5 v1] perf tools auxtrace hardening series
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
` (4 preceding siblings ...)
2026-07-27 16:17 ` [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero Arnaldo Carvalho de Melo
@ 2026-07-27 16:31 ` James Clark
5 siblings, 0 replies; 12+ messages in thread
From: James Clark @ 2026-07-27 16:31 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users
On 27/07/2026 5:17 pm, Arnaldo Carvalho de Melo wrote:
> Hi,
>
> Please consider applying,
>
> - Arnaldo
>
> Arnaldo Carvalho de Melo (5):
> perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
> perf auxtrace: Fix queue grow overflow and old array leak
> perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
> perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
> perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero
>
> tools/perf/util/arm-spe.c | 4 ++++
> tools/perf/util/auxtrace.c | 15 ++++++++++-----
> tools/perf/util/intel-bts.c | 2 +-
> tools/perf/util/intel-pt.c | 2 +-
> tools/perf/util/thread-stack.c | 2 +-
> 5 files changed, 17 insertions(+), 8 deletions(-)
>
Reviewed-by: James Clark <james.clark@linaro.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero
2026-07-27 16:17 ` [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero Arnaldo Carvalho de Melo
@ 2026-07-27 16:32 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-07-27 16:32 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Pre-existing issues:
- [Critical] `arm_spe_print_info` uses unvalidated, attacker-controlled fields to index into static format string arrays, leading to arbitrary memory dereferences and format string vulnerabilities.
- [High] Missing bounds check on user-controlled `hdr_sz` allows `ptr` to advance out of bounds and causes integer underflow in the `per_cpu_sz` calculation, leading to arbitrary heap out-of-bounds reads.
- [High] Missing minimum size validation on `per_cpu_sz` allows crafted inputs to cause heap out-of-bounds reads in downstream functions.
- [High] Missing payload size validation before accessing V2 metadata fields leads to an out-of-bounds read.
- [High] Bypassing the metadata allocation error check via a crafted V1 version flag causes an unhandled NULL pointer dereference in `arm_spe__is_homogeneous`.
--
--- Patch [5]: [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero ---
commit cdd9c13905fbd08524e5237d0ba280b139dcb3bc
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero
This patch adds a check to reject nr_cpu <= 0 in arm_spe__alloc_metadata()
before performing a division by nr_cpu. This prevents a division by zero
when a crafted perf.data file provides a zero value for the CPU count.
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> index 552f063f126e6..401aab529309c 100644
> --- a/tools/perf/util/arm-spe.c
> +++ b/tools/perf/util/arm-spe.c
> @@ -1604,8 +1604,12 @@ static u64 **arm_spe__alloc_metadata(struct perf_record_auxtrace_info *info,
> *ver = ptr[ARM_SPE_HEADER_VERSION];
> hdr_sz = ptr[ARM_SPE_HEADER_SIZE];
> *nr_cpu = ptr[ARM_SPE_CPUS_NUM];
[Severity: High]
This isn't a bug introduced by this patch, but does this read out of bounds
if the payload is exactly 24 bytes?
In arm_spe_process_auxtrace_info(), the payload is only validated against a
minimum size of 16 bytes for V1 metadata. If a crafted perf.data provides a
payload size of exactly 24 bytes (and is not V1), accessing ptr at index 3
(ARM_SPE_CPUS_NUM) attempts to read 32 bytes into the payload, which goes
beyond the verified payload bounds.
>
> + /* nr_cpu is used as a divisor below */
> + if (*nr_cpu <= 0)
> + return NULL;
[Severity: High]
This isn't a bug introduced by this patch, but does returning NULL here
trigger a NULL pointer dereference in arm_spe__is_homogeneous() if the
attacker sets the version to 1?
If a crafted file sets ARM_SPE_HEADER_VERSION to 1, and the
arm_spe__alloc_metadata() function returns NULL due to an allocation failure
or a negative nr_cpu, the error check in arm_spe_process_auxtrace_info() is
bypassed:
tools/perf/util/arm-spe.c:arm_spe_process_auxtrace_info() {
...
metadata = arm_spe__alloc_metadata(auxtrace_info, &metadata_ver,
&nr_cpu);
if (!metadata && metadata_ver != 1) {
pr_err("Failed to parse Arm SPE metadata.\n");
return -EINVAL;
}
...
spe->metadata_nr_cpu = nr_cpu;
spe->is_homogeneous = arm_spe__is_homogeneous(metadata, nr_cpu);
...
}
Because metadata_ver == 1, execution proceeds and passes the NULL metadata
pointer to arm_spe__is_homogeneous(), where it dereferences metadata[i]
without checking if metadata itself is NULL.
>
> metadata = calloc(*nr_cpu, sizeof(*metadata));
> if (!metadata)
> return NULL;
>
> /* Locate the start address of per CPU metadata */
> ptr += hdr_sz;
> per_cpu_sz = (metadata_size - (hdr_sz * sizeof(u64))) / (*nr_cpu);
[Severity: High]
This is a pre-existing issue, but does this allow ptr to advance out of
bounds if hdr_sz is larger than metadata_size?
Since hdr_sz is controlled by the input and lacks a bounds check against
metadata_size, a large hdr_sz could advance ptr past the payload bounds and
cause an integer underflow in the per_cpu_sz calculation.
[Severity: High]
This is a pre-existing issue, but is there a missing minimum size validation
on per_cpu_sz?
If per_cpu_sz is too small (e.g. 8 bytes), arm_spe__alloc_per_cpu_metadata()
allocates an undersized buffer. Later, arm_spe__is_homogeneous()
unconditionally accesses fields at fixed indices like ARM_SPE_CPU_MIDR,
which would result in out-of-bounds heap reads:
tools/perf/util/arm-spe.c:arm_spe__is_homogeneous() {
...
if (i == 0) {
midr = metadata[i][ARM_SPE_CPU_MIDR];
continue;
}
if (midr != metadata[i][ARM_SPE_CPU_MIDR])
return false;
...
}
[Severity: Critical]
This is a pre-existing issue, but does arm_spe_print_info() use the
unvalidated hdr_size to index into static format string arrays?
If a crafted file provides a large hdr_size or cpu_size, these unchecked
values are used as loop bounds, leading to out-of-bounds reads of format
string pointers which are then passed to fprintf():
tools/perf/util/arm-spe.c:arm_spe_print_info() {
...
for (i = 0; i < hdr_size; i++)
fprintf(stdout, hdr_fmts[i], arr[i]);
...
cpu_size = (ARM_SPE_CPU_NR_PARAMS + 1) + arr[ARM_SPE_CPU_NR_PARAMS];
for (i = 0; i < cpu_size; i++)
fprintf(stdout, metadata_per_cpu_fmts[i], arr[i]);
...
}
Could this lead to an arbitrary memory read or format string vulnerability
when running perf report with dump_trace?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727161705.64807-1-acme@kernel.org?part=5
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
2026-07-27 16:17 ` [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy Arnaldo Carvalho de Melo
@ 2026-07-27 16:32 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-07-27 16:32 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Medium] Missing NULL pointer checks for `ts->br_stack_rb` cause deterministic crashes when processing events on a thread stack that lacks an allocated branch stack.
--
--- Patch [1]: [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy ---
commit 15a96772c52a6e753408d6e7f8ded1a5bb10c331
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf thread-stack: Fix heap buffer overflow on branch stack wrap copy
This commit fixes a heap buffer overflow in thread_stack__br_sample() where
the memcpy size for the wrap-around portion used an unbounded ts->br_stack_pos
instead of the bounded nr variable.
> diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
> index c5ce741b07446..1360f44421ef8 100644
> --- a/tools/perf/util/thread-stack.c
> +++ b/tools/perf/util/thread-stack.c
> @@ -642,7 +642,7 @@ void thread_stack__br_sample(struct thread *thread, int cpu,
> sz -= nr;
> be = &dst->entries[nr];
> nr = min(ts->br_stack_pos, sz);
> - memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
> + memcpy(be, &src->entries[0], bsz * nr);
> }
> }
[Severity: Medium]
This is a pre-existing issue, but while looking at thread_stack__br_sample(),
is there a missing NULL pointer check for ts->br_stack_rb?
Earlier in this function, the code does:
src = ts->br_stack_rb;
if (!src->nr)
return;
If thread_stack__process() supersedes an existing thread stack and allocates a
new one with a 0 branch stack size, or if the allocation for ts->br_stack_rb
fails during thread_stack__init(), ts->br_stack_rb can be NULL.
When thread_stack__br_sample() or thread_stack__update_br_stack() is
subsequently called, will this unconditionally dereference the NULL pointer
and cause the perf tool to crash?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727161705.64807-1-acme@kernel.org?part=1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/5] perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
2026-07-27 16:17 ` [PATCH 4/5] perf intel-bts: " Arnaldo Carvalho de Melo
@ 2026-07-27 16:34 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-07-27 16:34 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Off-by-one minimum size check in powerpc_vpadtl_process_auxtrace_info allows out-of-bounds read.
- [High] Missing NULL pointer check before dereferencing session->itrace_synth_opts leads to deterministic crash.
- [High] Overwriting session->auxtrace unconditionally without cleanup causes memory leaks.
- [High] Out-of-bounds read in arm_spe__alloc_metadata when bypassing the version 1 size check.
--
--- Patch [4]: [PATCH 4/5] perf intel-bts: Fix off-by-one in auxtrace_info minimum size check ---
commit 0ac93f3d0cb5566f1e0f79a1c4a2f73b3281434a
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf intel-bts: Fix off-by-one in auxtrace_info minimum size check
Same pattern as the Intel PT fix: min_sz is set to
sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE, but the code accesses
auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE], which requires at least
INTEL_BTS_SNAPSHOT_MODE + 1 elements.
> diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
> index 0b18ebd13f7c8..02df3e4604891 100644
> --- a/tools/perf/util/intel-bts.c
> +++ b/tools/perf/util/intel-bts.c
> @@ -830,7 +830,7 @@ int intel_bts_process_auxtrace_info(union perf_event *event,
> struct perf_session *session)
> {
> struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
> - size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE;
> + size_t min_sz = sizeof(u64) * (INTEL_BTS_SNAPSHOT_MODE + 1);
[Severity: High]
This isn't a bug introduced by this patch, but the exact same pattern seems
to exist in tools/perf/util/powerpc-vpadtl.c.
In powerpc_vpadtl_process_auxtrace_info():
size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE;
...
vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE];
POWERPC_VPADTL_TYPE evaluates to 0, which makes min_sz = 0, failing to
protect the subsequent access to auxtrace_info->priv[0]. Should that be fixed
similarly to prevent an out-of-bounds read?
> struct intel_bts *bts;
> int err;
[Severity: High]
This is a pre-existing issue, but since we are looking at
intel_bts_process_auxtrace_info(), I noticed that session->auxtrace is
unconditionally overwritten later in this function without checking for or
freeing a previously active context:
session->auxtrace = &bts->auxtrace;
If a maliciously crafted perf.data file contains multiple
PERF_RECORD_AUXTRACE_INFO events, each event would sequentially overwrite
session->auxtrace without calling the appropriate .free() callback. Does this
lead to a memory leak of the dynamically allocated auxtrace context?
I noticed the same behavior in intel_pt_process_auxtrace_info() and
cs_etm__process_auxtrace_info_full().
[Severity: High]
This is another pre-existing issue, but further down in
intel_bts_process_auxtrace_info(), the code does:
if (session->itrace_synth_opts->set) {
Is it possible for session->itrace_synth_opts to be NULL? If a subcommand
like perf data convert --to-json processes PERF_RECORD_AUXTRACE_INFO
events but does not allocate session->itrace_synth_opts, could this lead to
a NULL pointer dereference?
This pattern is also present in intel_pt_process_auxtrace_info() and
cs_etm__process_auxtrace_info_full().
[Severity: High]
This is a pre-existing issue in another auxtrace file, but looking at how
auxtrace info is processed, I noticed a potential out-of-bounds read in
tools/perf/util/arm-spe.c:arm_spe__alloc_metadata().
If metadata_size is 24 bytes, the version 1 strict equality check
(metadata_size == 16) is bypassed, falling through to the version 2 parsing
which does:
*nr_cpu = ptr[ARM_SPE_CPUS_NUM];
Since ARM_SPE_CPUS_NUM is 3, this requires at least 32 bytes. If the payload
only has 24 bytes, does this read past the end of the event payload and use
a garbage value for the allocation size?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727161705.64807-1-acme@kernel.org?part=4
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
2026-07-27 16:17 ` [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check Arnaldo Carvalho de Melo
@ 2026-07-27 16:35 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-07-27 16:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing or off-by-one boundary checks in sibling auxtrace info processors lead to out-of-bounds reads.
- [High] Integer overflow when calculating the filter string length causes a 0-byte allocation and subsequent heap out-of-bounds read.
- [Medium] The function passes the raw, potentially endian-scrambled `filter` pointer to `addr_filters__parse_bare_filter()` instead of the corrected `pt->filter` buffer.
- [Medium] Missing cleanup for `pt->vmcs_info` and `pt->br_stack` on the error paths in `intel_pt_process_auxtrace_info`.
--
--- Patch [3]: [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check ---
commit d7842efbb6c00a1eec2b67aee65980fda65e6112
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf intel-pt: Fix off-by-one in auxtrace_info minimum size check
This commit fixes an off-by-one error in the intel_pt_process_auxtrace_info
minimum size check by ensuring the array is large enough to access the
INTEL_PT_PER_CPU_MMAPS element. A crafted perf.data file with exactly min_sz
bytes could previously pass the check and trigger an out-of-bounds read.
> diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
> index 56a9e439f5f8f..806cd173a0067 100644
> --- a/tools/perf/util/intel-pt.c
> +++ b/tools/perf/util/intel-pt.c
> @@ -4430,7 +4430,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
> struct perf_session *session)
> {
> struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
> - size_t min_sz = sizeof(u64) * INTEL_PT_PER_CPU_MMAPS;
> + size_t min_sz = sizeof(u64) * (INTEL_PT_PER_CPU_MMAPS + 1);
[Severity: High]
This isn't a bug introduced by this patch, but does this same vulnerability
exist in other auxtrace info processors?
In tools/perf/util/intel-bts.c:intel_bts_process_auxtrace_info(), is min_sz
undersized by calculating with INTEL_BTS_SNAPSHOT_MODE instead of
(INTEL_BTS_SNAPSHOT_MODE + 1)?
In tools/perf/util/powerpc-vpadtl.c:powerpc_vpadtl_process_auxtrace_info(),
POWERPC_VPADTL_TYPE is 0, which makes min_sz = 0, but the code later reads
index 0. Could this cause an out-of-bounds read on minimally sized payloads?
In tools/perf/util/arm-spe.c:arm_spe__alloc_metadata(), the v2 metadata path
unconditionally accesses index 3, even though min_sz is only enforced to be 16
bytes (2 elements). Are we risking an out-of-bounds read here?
In tools/perf/util/cs-etm.c:cs_etm__process_auxtrace_info_full(), the code reads
index 1 (CS_PMU_TYPE_CPUS) to calculate bounds before validating that the
event's priv_size is large enough to contain the global header. Is this safe?
[Severity: High]
This is a pre-existing issue, but further down in
intel_pt_process_auxtrace_info(), could an integer overflow lead to a 0-byte
allocation and out-of-bounds read?
When calculating the filter string length from user-controlled event data:
len = auxtrace_info->priv[INTEL_PT_FILTER_STR_LEN];
...
if (len) {
...
len = roundup(len + 1, 8);
info += len >> 3;
if ((void *)info > info_end) {
If a crafted perf.data file sets len to SIZE_MAX, would roundup(len + 1, 8)
overflow to 0?
This would prevent info from advancing, bypassing the info > info_end pointer
validation.
Then memdup(filter, len) would allocate 0 bytes, and the subsequent check:
if (pt->filter[len - 1]) {
would read pt->filter[SIZE_MAX] (offset -1), causing an out-of-bounds read into
the heap chunk's header.
[Severity: Medium]
This is a pre-existing issue, but in the same block handling the filter string,
are we passing the wrong buffer to addr_filters__parse_bare_filter()?
If session->header.needs_swap is true, the priv array payload is endian-swapped,
which scrambles string characters and relocates the null terminator.
The code copies the string and un-swaps it:
pt->filter = memdup(filter, len);
...
if (session->header.needs_swap)
mem_bswap_64(pt->filter, len);
However, it then passes the raw, un-swapped filter variable instead of the
corrected pt->filter buffer:
err = addr_filters__parse_bare_filter(&pt->filts, filter);
Since the scrambled filter string might not contain a null terminator where
expected, could the parsing function read out-of-bounds until it finds a random
null byte?
[Severity: Medium]
This isn't a bug introduced by this patch, but are there missing cleanups on the
error paths in intel_pt_process_auxtrace_info()?
If initialization fails and the code jumps to the error labels:
err_delete_thread:
thread__zput(pt->unknown_thread);
err_free_queues:
intel_pt_log_disable();
auxtrace_queues__free(&pt->queues);
It appears the RB tree pt->vmcs_info (allocated via
intel_pt_parse_vm_tm_corr_args()) and pt->br_stack (allocated dynamically
inside intel_pt_synth_events()) are not freed.
Unlike the successful teardown path (intel_pt_free()), these error paths lack
calls to intel_pt_free_vmcs_info(pt) and zfree(&pt->br_stack). Will this result
in a memory leak?
> struct intel_pt *pt;
> void *info_end;
> __u64 *info;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727161705.64807-1-acme@kernel.org?part=3
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-07-27 16:35 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-27 16:17 [PATCHES 0/5 v1] perf tools auxtrace hardening series Arnaldo Carvalho de Melo
2026-07-27 16:17 ` [PATCH 1/5] perf thread-stack: Fix heap buffer overflow on branch stack wrap copy Arnaldo Carvalho de Melo
2026-07-27 16:32 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 2/5] perf auxtrace: Fix queue grow overflow and old array leak Arnaldo Carvalho de Melo
2026-07-27 16:29 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 3/5] perf intel-pt: Fix off-by-one in auxtrace_info minimum size check Arnaldo Carvalho de Melo
2026-07-27 16:35 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 4/5] perf intel-bts: " Arnaldo Carvalho de Melo
2026-07-27 16:34 ` sashiko-bot
2026-07-27 16:17 ` [PATCH 5/5] perf arm-spe: Reject zero nr_cpu in metadata to prevent division by zero Arnaldo Carvalho de Melo
2026-07-27 16:32 ` sashiko-bot
2026-07-27 16:31 ` [PATCHES 0/5 v1] perf tools auxtrace hardening series James Clark
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.