+++ /dev/null
-From 7d6caf1ff6937044097543083be38383753541b8 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 8 Jun 2026 08:10:43 -0300
-Subject: perf bpf: Add NULL check for btf__type_by_id() in
- synthesize_bpf_prog_name()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 903b0526dcf86d030c5970b4b0a67f9c227368e2 ]
-
-synthesize_bpf_prog_name() calls btf__type_by_id() and immediately
-dereferences the result via t->name_off without checking for NULL.
-btf__type_by_id() returns NULL when the type_id is invalid or out
-of range. When processing perf.data files, finfo->type_id comes from
-untrusted input, so an invalid ID causes a NULL pointer dereference.
-
-Fix by checking t for NULL before dereferencing.
-
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Fixes: fc462ac75b36daaa ("perf bpf: Extract logic to create program names from perf_event__synthesize_one_bpf_prog()")
-Cc: Song Liu <songliubraving@fb.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/bpf-event.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
-index 2a9b90aa181fc7..dfebec3a6e71f5 100644
---- a/tools/perf/util/bpf-event.c
-+++ b/tools/perf/util/bpf-event.c
-@@ -137,7 +137,8 @@ static int synthesize_bpf_prog_name(char *buf, int size,
- if (btf) {
- finfo = func_infos + sub_id * info->func_info_rec_size;
- t = btf__type_by_id(btf, finfo->type_id);
-- short_name = btf__name_by_offset(btf, t->name_off);
-+ if (t)
-+ short_name = btf__name_by_offset(btf, t->name_off);
- } else if (sub_id == 0 && sub_prog_cnt == 1) {
- /* no subprog */
- if (info->name[0])
---
-2.53.0
-
+++ /dev/null
-From 605b77e2620e491be8423925ea582bd495a8a62b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 10 Jun 2026 21:03:16 -0300
-Subject: perf bpf: Bounds-check array offsets in bpil_offs_to_addr()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 033e85edfbf271f92979d2a39aeaf40f8472a795 ]
-
-bpil_offs_to_addr() converts offsets stored in perf.data's
-bpf_prog_info_linear structure into heap pointers by adding the offset
-to the data allocation base. The offsets come from untrusted file input
-and are not validated against data_len.
-
-If an offset exceeds data_len, the computed address points outside the
-allocated data buffer. Callers like synthesize_bpf_prog_name() then
-dereference prog_tags[sub_id] or func_info pointers, reading arbitrary
-heap memory.
-
-Add a bounds check: when an offset exceeds data_len, zero the field
-and skip the conversion. This prevents out-of-bounds pointer
-construction from crafted perf.data files.
-
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Fixes: 6ac22d036f86c4e2 ("perf bpf: Pull in bpf_program__get_prog_info_linear()")
-Cc: Dave Marchevsky <davemarchevsky@fb.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/bpf-utils.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
-diff --git a/tools/perf/util/bpf-utils.c b/tools/perf/util/bpf-utils.c
-index 80b1d2b3729ba4..a20ed281bcaf80 100644
---- a/tools/perf/util/bpf-utils.c
-+++ b/tools/perf/util/bpf-utils.c
-@@ -246,6 +246,7 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear)
- for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
- struct bpil_array_desc *desc;
- __u64 addr, offs;
-+ __u32 count, size;
-
- if ((info_linear->arrays & (1UL << i)) == 0)
- continue;
-@@ -253,6 +254,21 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear)
- desc = bpil_array_desc + i;
- offs = bpf_prog_info_read_offset_u64(&info_linear->info,
- desc->array_offset);
-+ count = bpf_prog_info_read_offset_u32(&info_linear->info,
-+ desc->count_offset);
-+ size = bpf_prog_info_read_offset_u32(&info_linear->info,
-+ desc->size_offset);
-+ /* offset and extent from perf.data are untrusted — keep within data[] */
-+ if (offs >= info_linear->data_len ||
-+ (u64)count * size > info_linear->data_len - offs) {
-+ bpf_prog_info_set_offset_u64(&info_linear->info,
-+ desc->array_offset, 0);
-+ bpf_prog_info_set_offset_u32(&info_linear->info,
-+ desc->count_offset, 0);
-+ /* clear the bit so bpil_addr_to_offs() won't reverse a zeroed address */
-+ info_linear->arrays &= ~(1UL << i);
-+ continue;
-+ }
- addr = offs + ptr_to_u64(info_linear->data);
- bpf_prog_info_set_offset_u64(&info_linear->info,
- desc->array_offset, addr);
---
-2.53.0
-
+++ /dev/null
-From e7baf646051162917349fadfcb36fa6d21f5d1d1 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 14:23:15 -0300
-Subject: perf bpf: Use scnprintf() in snprintf_hex() and
- synthesize_bpf_prog_name()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit cab3a9331ed0b3f884dd61c8a25b3cf123705982 ]
-
-Both functions accumulate formatted output via ret += snprintf(buf + ret,
-size - ret, ...). If the buffer is too small and snprintf() returns more
-than the remaining space, ret exceeds size and the next 'size - ret'
-underflows, causing snprintf() to write past the buffer end.
-
-Switch to scnprintf() which returns the actual number of bytes written,
-making the accumulation safe.
-
-Fixes: 7b612e291a5affb1 ("perf tools: Synthesize PERF_RECORD_* for loaded BPF programs")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Song Liu <song@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/bpf-event.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
-diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
-index 1573d6b6478d28..2a9b90aa181fc7 100644
---- a/tools/perf/util/bpf-event.c
-+++ b/tools/perf/util/bpf-event.c
-@@ -28,7 +28,7 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
- size_t i;
-
- for (i = 0; i < len; i++)
-- ret += snprintf(buf + ret, size - ret, "%02x", data[i]);
-+ ret += scnprintf(buf + ret, size - ret, "%02x", data[i]);
- return ret;
- }
-
-@@ -131,7 +131,7 @@ static int synthesize_bpf_prog_name(char *buf, int size,
- const struct btf_type *t;
- int name_len;
-
-- name_len = snprintf(buf, size, "bpf_prog_");
-+ name_len = scnprintf(buf, size, "bpf_prog_");
- name_len += snprintf_hex(buf + name_len, size - name_len,
- prog_tags[sub_id], BPF_TAG_SIZE);
- if (btf) {
-@@ -144,9 +144,10 @@ static int synthesize_bpf_prog_name(char *buf, int size,
- short_name = info->name;
- } else
- short_name = "F";
-- if (short_name)
-- name_len += snprintf(buf + name_len, size - name_len,
-- "_%s", short_name);
-+ if (short_name) {
-+ name_len += scnprintf(buf + name_len, size - name_len,
-+ "_%s", short_name);
-+ }
- return name_len;
- }
-
---
-2.53.0
-
+++ /dev/null
-From c065155cbbc4380b6f28c5eb82fec453c7a6d674 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 10 Jun 2026 21:01:15 -0300
-Subject: perf bpf: Validate func_info_rec_size and sub_id in
- synthesize_bpf_prog_name()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 10b3c3d63ecc17c6acb855bac5f40367f1115765 ]
-
-synthesize_bpf_prog_name() computes a pointer into the func_info array
-using sub_id * info->func_info_rec_size without validating either value.
-Both come from perf.data and are untrusted:
-
-- A func_info_rec_size smaller than sizeof(struct bpf_func_info) means
- the finfo pointer would reference a truncated entry, reading past it
- into adjacent data.
-
-- A sub_id >= nr_func_info computes an offset past the func_info buffer,
- causing an out-of-bounds read.
-
-Add bounds checks for both values before computing the pointer offset.
-When validation fails, fall through to the non-BTF name path instead
-of reading garbage.
-
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Fixes: 7b612e291a5affb1 ("perf tools: Synthesize PERF_RECORD_* for loaded BPF programs")
-Cc: Song Liu <songliubraving@fb.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/bpf-event.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
-index dfebec3a6e71f5..fb4eb16c7b5bae 100644
---- a/tools/perf/util/bpf-event.c
-+++ b/tools/perf/util/bpf-event.c
-@@ -134,7 +134,9 @@ static int synthesize_bpf_prog_name(char *buf, int size,
- name_len = scnprintf(buf, size, "bpf_prog_");
- name_len += snprintf_hex(buf + name_len, size - name_len,
- prog_tags[sub_id], BPF_TAG_SIZE);
-- if (btf) {
-+ if (btf &&
-+ info->func_info_rec_size >= sizeof(*finfo) &&
-+ sub_id < info->nr_func_info) {
- finfo = func_infos + sub_id * info->func_info_rec_size;
- t = btf__type_by_id(btf, finfo->type_id);
- if (t)
---
-2.53.0
-
+++ /dev/null
-From 622825444cd491f971326c84ac8bbf00a4c62d90 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 5 Jun 2026 11:05:13 -0300
-Subject: perf c2c: Bounds-check CPU and node IDs before bitmap and array
- access
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 65117c3da50f749f4c22eb7a7effc53453dff57f ]
-
-c2c_he__set_cpu() passes sample->cpu directly to __set_bit(cpu, cpuset)
-after only checking for the (u32)-1 sentinel. The cpuset bitmap is
-allocated with c2c.cpus_cnt bits (from env->nr_cpus_avail), so a crafted
-perf.data with CPU IDs exceeding that count causes out-of-bounds heap
-writes.
-
-c2c_he__set_node() similarly passes the node ID from mem2node__node()
-to __set_bit(node, nodeset) after only checking for negative values.
-The nodeset bitmap is sized to c2c.nodes_cnt (from env->nr_numa_nodes),
-so a node ID exceeding that causes OOB writes.
-
-process_sample_event() indexes c2c.cpu2node[cpu] and
-c2c_he->node_stats[node] without bounds checking. Both arrays are
-sized to c2c.cpus_cnt and c2c.nodes_cnt respectively.
-
-Add bounds checks in all three paths:
- - c2c_he__set_cpu(): return if sample->cpu >= c2c.cpus_cnt
- - c2c_he__set_node(): return if node >= c2c.nodes_cnt
- - process_sample_event(): clamp cpu to 0 if >= cpus_cnt,
- guard node_stats access with bounds check
-
-Fixes: 1e181b92a2da ("perf c2c report: Add 'node' sort key")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-c2c.c | 19 +++++++++++++++++--
- 1 file changed, 17 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
-index a4cf9de7a7b5a9..207b9c863aeea5 100644
---- a/tools/perf/builtin-c2c.c
-+++ b/tools/perf/builtin-c2c.c
-@@ -229,6 +229,10 @@ static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he,
- "WARNING: no sample cpu value"))
- return;
-
-+ /* cpuset bitmap has c2c.cpus_cnt bits from env->nr_cpus_avail */
-+ if (sample->cpu >= (unsigned int)c2c.cpus_cnt)
-+ return;
-+
- __set_bit(sample->cpu, c2c_he->cpuset);
- }
-
-@@ -246,6 +250,10 @@ static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
- if (WARN_ONCE(node < 0, "WARNING: failed to find node\n"))
- return;
-
-+ /* nodeset bitmap has c2c.nodes_cnt bits from env->nr_numa_nodes */
-+ if (node >= c2c.nodes_cnt)
-+ return;
-+
- __set_bit(node, c2c_he->nodeset);
-
- if (c2c_he->paddr != sample->phys_addr) {
-@@ -345,7 +353,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
- * Doing node stats only for single callchain data.
- */
- int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu;
-- int node = c2c.cpu2node[cpu];
-+ int node;
-+
-+ /* cpu2node[] has c2c.cpus_cnt entries; large u32 wraps signed negative */
-+ if (cpu < 0 || cpu >= c2c.cpus_cnt)
-+ cpu = 0;
-+ node = c2c.cpu2node[cpu];
-
- mi = mi_dup;
-
-@@ -362,7 +375,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
- c2c_he = container_of(he, struct c2c_hist_entry, he);
- c2c_add_stats(&c2c_he->stats, &stats);
- c2c_add_stats(&c2c_hists->stats, &stats);
-- c2c_add_stats(&c2c_he->node_stats[node], &stats);
-+ /* node_stats[] has c2c.nodes_cnt entries */
-+ if (node >= 0 && node < c2c.nodes_cnt)
-+ c2c_add_stats(&c2c_he->node_stats[node], &stats);
-
- compute_stats(c2c_he, &stats, sample->weight);
-
---
-2.53.0
-
+++ /dev/null
-From baadde6e6db8689ad107050bbc1372f89c3a3398 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 11:19:10 -0300
-Subject: perf c2c: Fix use-after-free in he__get_c2c_hists() error path
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 5e5e6196d737c5be03d20647428316b36621608d ]
-
-he__get_c2c_hists() assigns c2c_he->hists before calling
-c2c_hists__init(). If init fails, the error path calls free(hists)
-but leaves c2c_he->hists pointing to freed memory. On teardown,
-c2c_he_free() finds the non-NULL pointer and calls
-hists__delete_entries() on it, causing a use-after-free.
-
-Set c2c_he->hists to NULL before freeing so teardown skips the
-already-freed allocation.
-
-Fixes: b2252ae67b687d2b ("perf c2c report: Decode c2c_stats for hist entries")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-c2c.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
-index 207b9c863aeea5..96ca35c4f3062c 100644
---- a/tools/perf/builtin-c2c.c
-+++ b/tools/perf/builtin-c2c.c
-@@ -215,6 +215,7 @@ he__get_c2c_hists(struct hist_entry *he,
-
- ret = c2c_hists__init(hists, sort, nr_header_lines);
- if (ret) {
-+ c2c_he->hists = NULL;
- free(hists);
- return NULL;
- }
---
-2.53.0
-
+++ /dev/null
-From a4bb4c43b7536bcb0c71edd33966b85e47453fac Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 22 Jul 2024 11:11:43 +0100
-Subject: perf cs-etm: Create decoders after both AUX and HW_ID search passes
-
-From: James Clark <james.clark@arm.com>
-
-[ Upstream commit b6aa0de9a53a231eb068ce1e62b5e7ec9e30e627 ]
-
-Both of these passes gather information about how to create the
-decoders. AUX records determine formatted/unformatted, and the HW_IDs
-determine the traceID/metadata mappings.
-
-Therefore it makes sense to cache the information and wait until both
-passes are over until creating the decoders, rather than creating them
-at the first HW_ID found.
-
-This will allow a simplification of the creation process where
-cs_etm_queue->traceid_list will exclusively used to create the decoders,
-rather than the current two methods depending on whether the trace is
-formatted or not.
-
-Previously the sample CPU from the AUX record was used to initialize
-the decoder CPU, but actually sample CPU == AUX queue index in per-CPU
-mode, so saving the sample CPU isn't required.
-
-Similarly formatted/unformatted was used upfront to create the decoders,
-but now it's cached until later.
-
-Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
-Reviewed-by: Mike Leach <mike.leach@linaro.org>
-Signed-off-by: James Clark <james.clark@arm.com>
-Signed-off-by: James Clark <james.clark@linaro.org>
-Tested-by: Ganapatrao Kulkarni <gankulkarni@os.amperecomputing.com>
-Tested-by: Leo Yan <leo.yan@arm.com>
-Acked-by: Suzuki Poulouse <suzuki.poulose@arm.com>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
-Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
-Cc: Ian Rogers <irogers@google.com>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: John Garry <john.g.garry@oracle.com>
-Cc: Kan Liang <kan.liang@linux.intel.com>
-Cc: Leo Yan <leo.yan@linux.dev>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Cc: Peter Zijlstra <peterz@infradead.org>
-Cc: Will Deacon <will@kernel.org>
-Link: https://lore.kernel.org/r/20240722101202.26915-2-james.clark@linaro.org
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Stable-dep-of: 68ca50bc0fa6 ("perf cs-etm: Queue context packets for frontend")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cs-etm.c | 182 ++++++++++++++++++++++++---------------
- 1 file changed, 113 insertions(+), 69 deletions(-)
-
-diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
-index 1fb104357eebb8..9077072994b23b 100644
---- a/tools/perf/util/cs-etm.c
-+++ b/tools/perf/util/cs-etm.c
-@@ -97,12 +97,19 @@ struct cs_etm_traceid_queue {
- struct cs_etm_packet_queue packet_queue;
- };
-
-+enum cs_etm_format {
-+ UNSET,
-+ FORMATTED,
-+ UNFORMATTED
-+};
-+
- struct cs_etm_queue {
- struct cs_etm_auxtrace *etm;
- struct cs_etm_decoder *decoder;
- struct auxtrace_buffer *buffer;
- unsigned int queue_nr;
- u8 pending_timestamp_chan_id;
-+ enum cs_etm_format format;
- u64 offset;
- const unsigned char *buf;
- size_t buf_len, buf_used;
-@@ -693,7 +700,7 @@ static void cs_etm__set_trace_param_ete(struct cs_etm_trace_params *t_params,
-
- static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,
- struct cs_etm_auxtrace *etm,
-- bool formatted,
-+ enum cs_etm_format format,
- int sample_cpu,
- int decoders)
- {
-@@ -702,7 +709,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,
- u64 architecture;
-
- for (t_idx = 0; t_idx < decoders; t_idx++) {
-- if (formatted)
-+ if (format == FORMATTED)
- m_idx = t_idx;
- else {
- m_idx = get_cpu_data_idx(etm, sample_cpu);
-@@ -735,8 +742,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,
-
- static int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params,
- struct cs_etm_queue *etmq,
-- enum cs_etm_decoder_operation mode,
-- bool formatted)
-+ enum cs_etm_decoder_operation mode)
- {
- int ret = -EINVAL;
-
-@@ -746,7 +752,7 @@ static int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params,
- d_params->packet_printer = cs_etm__packet_dump;
- d_params->operation = mode;
- d_params->data = etmq;
-- d_params->formatted = formatted;
-+ d_params->formatted = etmq->format == FORMATTED;
- d_params->fsyncs = false;
- d_params->hsyncs = false;
- d_params->frame_aligned = true;
-@@ -1038,81 +1044,34 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
- return ret;
- }
-
--static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
-- bool formatted, int sample_cpu)
-+static struct cs_etm_queue *cs_etm__alloc_queue(void)
- {
-- struct cs_etm_decoder_params d_params;
-- struct cs_etm_trace_params *t_params = NULL;
-- struct cs_etm_queue *etmq;
-- /*
-- * Each queue can only contain data from one CPU when unformatted, so only one decoder is
-- * needed.
-- */
-- int decoders = formatted ? etm->num_cpu : 1;
--
-- etmq = zalloc(sizeof(*etmq));
-+ struct cs_etm_queue *etmq = zalloc(sizeof(*etmq));
- if (!etmq)
- return NULL;
-
- etmq->traceid_queues_list = intlist__new(NULL);
- if (!etmq->traceid_queues_list)
-- goto out_free;
--
-- /* Use metadata to fill in trace parameters for trace decoder */
-- t_params = zalloc(sizeof(*t_params) * decoders);
--
-- if (!t_params)
-- goto out_free;
--
-- if (cs_etm__init_trace_params(t_params, etm, formatted, sample_cpu, decoders))
-- goto out_free;
--
-- /* Set decoder parameters to decode trace packets */
-- if (cs_etm__init_decoder_params(&d_params, etmq,
-- dump_trace ? CS_ETM_OPERATION_PRINT :
-- CS_ETM_OPERATION_DECODE,
-- formatted))
-- goto out_free;
--
-- etmq->decoder = cs_etm_decoder__new(decoders, &d_params,
-- t_params);
--
-- if (!etmq->decoder)
-- goto out_free;
--
-- /*
-- * Register a function to handle all memory accesses required by
-- * the trace decoder library.
-- */
-- if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
-- 0x0L, ((u64) -1L),
-- cs_etm__mem_access))
-- goto out_free_decoder;
-+ free(etmq);
-
-- zfree(&t_params);
- return etmq;
--
--out_free_decoder:
-- cs_etm_decoder__free(etmq->decoder);
--out_free:
-- intlist__delete(etmq->traceid_queues_list);
-- free(etmq);
--
-- return NULL;
- }
-
- static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
- struct auxtrace_queue *queue,
-- unsigned int queue_nr,
-- bool formatted,
-- int sample_cpu)
-+ unsigned int queue_nr, enum cs_etm_format format)
- {
- struct cs_etm_queue *etmq = queue->priv;
-
-+ if (etmq && format != etmq->format) {
-+ pr_err("CS_ETM: mixed formatted and unformatted trace not supported\n");
-+ return -EINVAL;
-+ }
-+
- if (list_empty(&queue->head) || etmq)
- return 0;
-
-- etmq = cs_etm__alloc_queue(etm, formatted, sample_cpu);
-+ etmq = cs_etm__alloc_queue();
-
- if (!etmq)
- return -ENOMEM;
-@@ -1120,7 +1079,9 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
- queue->priv = etmq;
- etmq->etm = etm;
- etmq->queue_nr = queue_nr;
-+ queue->cpu = queue_nr; /* Placeholder, may be reset to -1 in per-thread mode */
- etmq->offset = 0;
-+ etmq->format = format;
-
- return 0;
- }
-@@ -2851,7 +2812,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,
- * formatted in piped mode (true).
- */
- err = cs_etm__setup_queue(etm, &etm->queues.queue_array[idx],
-- idx, true, -1);
-+ idx, FORMATTED);
- if (err)
- return err;
-
-@@ -2972,7 +2933,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
- union perf_event auxtrace_fragment;
- __u64 aux_offset, aux_size;
- __u32 idx;
-- bool formatted;
-+ enum cs_etm_format format;
-
- struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
- struct cs_etm_auxtrace,
-@@ -3055,9 +3016,10 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
- return err;
-
- idx = auxtrace_event->idx;
-- formatted = !(aux_event->flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW);
-- return cs_etm__setup_queue(etm, &etm->queues.queue_array[idx],
-- idx, formatted, sample->cpu);
-+ format = (aux_event->flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW) ?
-+ UNFORMATTED : FORMATTED;
-+
-+ return cs_etm__setup_queue(etm, &etm->queues.queue_array[idx], idx, format);
- }
-
- /* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
-@@ -3241,6 +3203,84 @@ static int cs_etm__clear_unused_trace_ids_metadata(int num_cpu, u64 **metadata)
- return 0;
- }
-
-+/*
-+ * Use the data gathered by the peeks for HW_ID (trace ID mappings) and AUX
-+ * (formatted or not) packets to create the decoders.
-+ */
-+static int cs_etm__create_queue_decoders(struct cs_etm_queue *etmq)
-+{
-+ struct cs_etm_decoder_params d_params;
-+
-+ /*
-+ * Each queue can only contain data from one CPU when unformatted, so only one decoder is
-+ * needed.
-+ */
-+ int decoders = etmq->format == FORMATTED ? etmq->etm->num_cpu : 1;
-+
-+ /* Use metadata to fill in trace parameters for trace decoder */
-+ struct cs_etm_trace_params *t_params = zalloc(sizeof(*t_params) * decoders);
-+
-+ if (!t_params)
-+ goto out_free;
-+
-+ if (cs_etm__init_trace_params(t_params, etmq->etm, etmq->format,
-+ etmq->queue_nr, decoders))
-+ goto out_free;
-+
-+ /* Set decoder parameters to decode trace packets */
-+ if (cs_etm__init_decoder_params(&d_params, etmq,
-+ dump_trace ? CS_ETM_OPERATION_PRINT :
-+ CS_ETM_OPERATION_DECODE))
-+ goto out_free;
-+
-+ etmq->decoder = cs_etm_decoder__new(decoders, &d_params,
-+ t_params);
-+
-+ if (!etmq->decoder)
-+ goto out_free;
-+
-+ /*
-+ * Register a function to handle all memory accesses required by
-+ * the trace decoder library.
-+ */
-+ if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
-+ 0x0L, ((u64) -1L),
-+ cs_etm__mem_access))
-+ goto out_free_decoder;
-+
-+ zfree(&t_params);
-+ return 0;
-+
-+out_free_decoder:
-+ cs_etm_decoder__free(etmq->decoder);
-+out_free:
-+ zfree(&t_params);
-+ return -EINVAL;
-+}
-+
-+static int cs_etm__create_decoders(struct cs_etm_auxtrace *etm)
-+{
-+ struct auxtrace_queues *queues = &etm->queues;
-+
-+ for (unsigned int i = 0; i < queues->nr_queues; i++) {
-+ bool empty = list_empty(&queues->queue_array[i].head);
-+ struct cs_etm_queue *etmq = queues->queue_array[i].priv;
-+ int ret;
-+
-+ /*
-+ * Don't create decoders for empty queues, mainly because
-+ * etmq->format is unknown for empty queues.
-+ */
-+ if (empty)
-+ continue;
-+
-+ ret = cs_etm__create_queue_decoders(etmq);
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
- int cs_etm__process_auxtrace_info_full(union perf_event *event,
- struct perf_session *session)
- {
-@@ -3389,6 +3429,10 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
- if (err)
- goto err_free_queues;
-
-+ err = cs_etm__queue_aux_records(session);
-+ if (err)
-+ goto err_free_queues;
-+
- /*
- * Map Trace ID values to CPU metadata.
- *
-@@ -3411,7 +3455,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
- * flags if present.
- */
-
-- /* first scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */
-+ /* Scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */
- aux_hw_id_found = 0;
- err = perf_session__peek_events(session, session->header.data_offset,
- session->header.data_size,
-@@ -3429,7 +3473,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
- if (err)
- goto err_free_queues;
-
-- err = cs_etm__queue_aux_records(session);
-+ err = cs_etm__create_decoders(etm);
- if (err)
- goto err_free_queues;
-
---
-2.53.0
-
+++ /dev/null
-From 332046fd6952b00536a2f5d92d8a0e36b299f362 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 10 Oct 2023 18:48:03 -0500
-Subject: perf cs-etm: Fix incorrect or missing decoder for raw trace
-
-From: Besar Wicaksono <bwicaksono@nvidia.com>
-
-[ Upstream commit a16afcc58a8c5ebc65c852faf001f8f61f05e4ef ]
-
-The decoder creation for raw trace uses metadata from the first CPU.
-On per-cpu mode, this metadata is incorrectly used for every decoder.
-On per-process/per-thread traces, the first CPU is CPU0. If CPU0 trace
-is not enabled, its metadata will be marked unused and the decoder is
-not created. Perf report dump skips the decoding part because the
-decoder is missing.
-
-To fix this, use metadata of the CPU associated with sample object.
-
-Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
-Reviewed-by: James Clark <james.clark@arm.com>
-Cc: suzuki.poulose@arm.com
-Cc: mike.leach@linaro.org
-Cc: jonathanh@nvidia.com
-Cc: rwiley@nvidia.com
-Cc: treding@nvidia.com
-Cc: vsethi@nvidia.com
-Cc: ywan@nvidia.com
-Cc: linux-arm-kernel@lists.infradead.org
-Cc: coresight@lists.linaro.org
-Cc: linux-tegra@vger.kernel.org
-Link: https://lore.kernel.org/r/20231010234803.5419-1-bwicaksono@nvidia.com
-Signed-off-by: Namhyung Kim <namhyung@kernel.org>
-Stable-dep-of: 68ca50bc0fa6 ("perf cs-etm: Queue context packets for frontend")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cs-etm.c | 106 ++++++++++++++++++++++++---------------
- 1 file changed, 65 insertions(+), 41 deletions(-)
-
-diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
-index 799c104901b4ff..1fb104357eebb8 100644
---- a/tools/perf/util/cs-etm.c
-+++ b/tools/perf/util/cs-etm.c
-@@ -283,22 +283,31 @@ static int cs_etm__metadata_set_trace_id(u8 trace_chan_id, u64 *cpu_metadata)
- }
-
- /*
-- * Get a metadata for a specific cpu from an array.
-+ * Get a metadata index for a specific cpu from an array.
- *
- */
--static u64 *get_cpu_data(struct cs_etm_auxtrace *etm, int cpu)
-+static int get_cpu_data_idx(struct cs_etm_auxtrace *etm, int cpu)
- {
- int i;
-- u64 *metadata = NULL;
-
- for (i = 0; i < etm->num_cpu; i++) {
- if (etm->metadata[i][CS_ETM_CPU] == (u64)cpu) {
-- metadata = etm->metadata[i];
-- break;
-+ return i;
- }
- }
-
-- return metadata;
-+ return -1;
-+}
-+
-+/*
-+ * Get a metadata for a specific cpu from an array.
-+ *
-+ */
-+static u64 *get_cpu_data(struct cs_etm_auxtrace *etm, int cpu)
-+{
-+ int idx = get_cpu_data_idx(etm, cpu);
-+
-+ return (idx != -1) ? etm->metadata[idx] : NULL;
- }
-
- /*
-@@ -641,66 +650,80 @@ static void cs_etm__packet_dump(const char *pkt_string)
- }
-
- static void cs_etm__set_trace_param_etmv3(struct cs_etm_trace_params *t_params,
-- struct cs_etm_auxtrace *etm, int idx,
-- u32 etmidr)
-+ struct cs_etm_auxtrace *etm, int t_idx,
-+ int m_idx, u32 etmidr)
- {
- u64 **metadata = etm->metadata;
-
-- t_params[idx].protocol = cs_etm__get_v7_protocol_version(etmidr);
-- t_params[idx].etmv3.reg_ctrl = metadata[idx][CS_ETM_ETMCR];
-- t_params[idx].etmv3.reg_trc_id = metadata[idx][CS_ETM_ETMTRACEIDR];
-+ t_params[t_idx].protocol = cs_etm__get_v7_protocol_version(etmidr);
-+ t_params[t_idx].etmv3.reg_ctrl = metadata[m_idx][CS_ETM_ETMCR];
-+ t_params[t_idx].etmv3.reg_trc_id = metadata[m_idx][CS_ETM_ETMTRACEIDR];
- }
-
- static void cs_etm__set_trace_param_etmv4(struct cs_etm_trace_params *t_params,
-- struct cs_etm_auxtrace *etm, int idx)
-+ struct cs_etm_auxtrace *etm, int t_idx,
-+ int m_idx)
- {
- u64 **metadata = etm->metadata;
-
-- t_params[idx].protocol = CS_ETM_PROTO_ETMV4i;
-- t_params[idx].etmv4.reg_idr0 = metadata[idx][CS_ETMV4_TRCIDR0];
-- t_params[idx].etmv4.reg_idr1 = metadata[idx][CS_ETMV4_TRCIDR1];
-- t_params[idx].etmv4.reg_idr2 = metadata[idx][CS_ETMV4_TRCIDR2];
-- t_params[idx].etmv4.reg_idr8 = metadata[idx][CS_ETMV4_TRCIDR8];
-- t_params[idx].etmv4.reg_configr = metadata[idx][CS_ETMV4_TRCCONFIGR];
-- t_params[idx].etmv4.reg_traceidr = metadata[idx][CS_ETMV4_TRCTRACEIDR];
-+ t_params[t_idx].protocol = CS_ETM_PROTO_ETMV4i;
-+ t_params[t_idx].etmv4.reg_idr0 = metadata[m_idx][CS_ETMV4_TRCIDR0];
-+ t_params[t_idx].etmv4.reg_idr1 = metadata[m_idx][CS_ETMV4_TRCIDR1];
-+ t_params[t_idx].etmv4.reg_idr2 = metadata[m_idx][CS_ETMV4_TRCIDR2];
-+ t_params[t_idx].etmv4.reg_idr8 = metadata[m_idx][CS_ETMV4_TRCIDR8];
-+ t_params[t_idx].etmv4.reg_configr = metadata[m_idx][CS_ETMV4_TRCCONFIGR];
-+ t_params[t_idx].etmv4.reg_traceidr = metadata[m_idx][CS_ETMV4_TRCTRACEIDR];
- }
-
- static void cs_etm__set_trace_param_ete(struct cs_etm_trace_params *t_params,
-- struct cs_etm_auxtrace *etm, int idx)
-+ struct cs_etm_auxtrace *etm, int t_idx,
-+ int m_idx)
- {
- u64 **metadata = etm->metadata;
-
-- t_params[idx].protocol = CS_ETM_PROTO_ETE;
-- t_params[idx].ete.reg_idr0 = metadata[idx][CS_ETE_TRCIDR0];
-- t_params[idx].ete.reg_idr1 = metadata[idx][CS_ETE_TRCIDR1];
-- t_params[idx].ete.reg_idr2 = metadata[idx][CS_ETE_TRCIDR2];
-- t_params[idx].ete.reg_idr8 = metadata[idx][CS_ETE_TRCIDR8];
-- t_params[idx].ete.reg_configr = metadata[idx][CS_ETE_TRCCONFIGR];
-- t_params[idx].ete.reg_traceidr = metadata[idx][CS_ETE_TRCTRACEIDR];
-- t_params[idx].ete.reg_devarch = metadata[idx][CS_ETE_TRCDEVARCH];
-+ t_params[t_idx].protocol = CS_ETM_PROTO_ETE;
-+ t_params[t_idx].ete.reg_idr0 = metadata[m_idx][CS_ETE_TRCIDR0];
-+ t_params[t_idx].ete.reg_idr1 = metadata[m_idx][CS_ETE_TRCIDR1];
-+ t_params[t_idx].ete.reg_idr2 = metadata[m_idx][CS_ETE_TRCIDR2];
-+ t_params[t_idx].ete.reg_idr8 = metadata[m_idx][CS_ETE_TRCIDR8];
-+ t_params[t_idx].ete.reg_configr = metadata[m_idx][CS_ETE_TRCCONFIGR];
-+ t_params[t_idx].ete.reg_traceidr = metadata[m_idx][CS_ETE_TRCTRACEIDR];
-+ t_params[t_idx].ete.reg_devarch = metadata[m_idx][CS_ETE_TRCDEVARCH];
- }
-
- static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,
- struct cs_etm_auxtrace *etm,
-+ bool formatted,
-+ int sample_cpu,
- int decoders)
- {
-- int i;
-+ int t_idx, m_idx;
- u32 etmidr;
- u64 architecture;
-
-- for (i = 0; i < decoders; i++) {
-- architecture = etm->metadata[i][CS_ETM_MAGIC];
-+ for (t_idx = 0; t_idx < decoders; t_idx++) {
-+ if (formatted)
-+ m_idx = t_idx;
-+ else {
-+ m_idx = get_cpu_data_idx(etm, sample_cpu);
-+ if (m_idx == -1) {
-+ pr_warning("CS_ETM: unknown CPU, falling back to first metadata\n");
-+ m_idx = 0;
-+ }
-+ }
-+
-+ architecture = etm->metadata[m_idx][CS_ETM_MAGIC];
-
- switch (architecture) {
- case __perf_cs_etmv3_magic:
-- etmidr = etm->metadata[i][CS_ETM_ETMIDR];
-- cs_etm__set_trace_param_etmv3(t_params, etm, i, etmidr);
-+ etmidr = etm->metadata[m_idx][CS_ETM_ETMIDR];
-+ cs_etm__set_trace_param_etmv3(t_params, etm, t_idx, m_idx, etmidr);
- break;
- case __perf_cs_etmv4_magic:
-- cs_etm__set_trace_param_etmv4(t_params, etm, i);
-+ cs_etm__set_trace_param_etmv4(t_params, etm, t_idx, m_idx);
- break;
- case __perf_cs_ete_magic:
-- cs_etm__set_trace_param_ete(t_params, etm, i);
-+ cs_etm__set_trace_param_ete(t_params, etm, t_idx, m_idx);
- break;
- default:
- return -EINVAL;
-@@ -1016,7 +1039,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
- }
-
- static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
-- bool formatted)
-+ bool formatted, int sample_cpu)
- {
- struct cs_etm_decoder_params d_params;
- struct cs_etm_trace_params *t_params = NULL;
-@@ -1041,7 +1064,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
- if (!t_params)
- goto out_free;
-
-- if (cs_etm__init_trace_params(t_params, etm, decoders))
-+ if (cs_etm__init_trace_params(t_params, etm, formatted, sample_cpu, decoders))
- goto out_free;
-
- /* Set decoder parameters to decode trace packets */
-@@ -1081,14 +1104,15 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
- static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
- struct auxtrace_queue *queue,
- unsigned int queue_nr,
-- bool formatted)
-+ bool formatted,
-+ int sample_cpu)
- {
- struct cs_etm_queue *etmq = queue->priv;
-
- if (list_empty(&queue->head) || etmq)
- return 0;
-
-- etmq = cs_etm__alloc_queue(etm, formatted);
-+ etmq = cs_etm__alloc_queue(etm, formatted, sample_cpu);
-
- if (!etmq)
- return -ENOMEM;
-@@ -2827,7 +2851,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,
- * formatted in piped mode (true).
- */
- err = cs_etm__setup_queue(etm, &etm->queues.queue_array[idx],
-- idx, true);
-+ idx, true, -1);
- if (err)
- return err;
-
-@@ -3033,7 +3057,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
- idx = auxtrace_event->idx;
- formatted = !(aux_event->flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW);
- return cs_etm__setup_queue(etm, &etm->queues.queue_array[idx],
-- idx, formatted);
-+ idx, formatted, sample->cpu);
- }
-
- /* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
---
-2.53.0
-
+++ /dev/null
-From cc0a6a0ef31195c19d891da55f7266ae0075fb0e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 9 Jun 2026 15:40:06 +0100
-Subject: perf cs-etm: Queue context packets for frontend
-
-From: James Clark <james.clark@linaro.org>
-
-[ Upstream commit 68ca50bc0fa64841cd73b8a1538df1d7f7eb4108 ]
-
-PE_CONTEXT elements update the context ID and exception level, but the
-decoder may still have prior packets cached for frontend processing.
-Updating the context immediately in the decoder backend can make those
-cached packets get consumed with the wrong thread or EL state.
-
-Add a CS_ETM_CONTEXT packet carrying the TID and EL to the frontend,
-this keeps context changes ordered with the rest of the packet stream
-and avoids mismatches when synthesizing samples from cached packets.
-
-Separate the memory access function into one for the frontend and one
-for decoding. The frontend also needs memory access to attach the
-instruction to samples. Because the frontend does memory access for
-both previous and current packets, change all the frontend memory access
-function signatures to take both a tidq and packet. But backend always
-uses the current backend EL and thread from the tidq.
-
-Treat context packets as a boundary for branch sample generation and
-remove tidq->prev_packet_thread because it's not possible to branch to a
-different thread, so only tracking the current thread is required for
-sample generation.
-
-Fixes: e573e978fb12e160 ("perf cs-etm: Inject capabilitity for CoreSight traces")
-Reported-by: Amir Ayupov <aaupov@meta.com>
-Closes: https://lore.kernel.org/linux-perf-users/20260515021135.1729028-1-aaupov@meta.com/
-Co-authored-by: James Clark <james.clark@linaro.org>
-Signed-off-by: Leo Yan <leo.yan@arm.com>
-Cc: Ian Rogers <irogers@google.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Jonathan Corbet <corbet@lwn.net>
-Cc: linux-doc@vger.kernel.org
-Cc: Mike Leach <mike.leach@arm.com>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Cc: Paschalis Mpeis <Paschalis.Mpeis@arm.com>
-Cc: Robert Walker <robert.walker@arm.com>
-Cc: Shuah Khan <skhan@linuxfoundation.org>
-Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
-Signed-off-by: James Clark <james.clark@linaro.org>
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 +-
- tools/perf/util/cs-etm.c | 236 +++++++++++-------
- tools/perf/util/cs-etm.h | 8 +-
- 3 files changed, 163 insertions(+), 102 deletions(-)
-
-diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
-index 640e383cef441c..277da9f767b9d2 100644
---- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
-+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
-@@ -398,6 +398,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue,
- packet_queue->packet_buffer[et].flags = 0;
- packet_queue->packet_buffer[et].exception_number = UINT32_MAX;
- packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id;
-+ packet_queue->packet_buffer[et].el = ocsd_EL_unknown;
-+ packet_queue->packet_buffer[et].tid = -1;
-
- if (packet_queue->packet_count == CS_ETM_PACKET_MAX_BUFFER - 1)
- return OCSD_RESP_WAIT;
-@@ -445,6 +447,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_queue *etmq,
- packet->last_instr_type = elem->last_i_type;
- packet->last_instr_subtype = elem->last_i_subtype;
- packet->last_instr_cond = elem->last_instr_cond;
-+ packet->el = elem->context.exception_level;
-
- if (elem->last_i_type == OCSD_INSTR_BR || elem->last_i_type == OCSD_INSTR_BR_INDIRECT)
- packet->last_instr_taken_branch = elem->last_instr_exec;
-@@ -518,7 +521,9 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
- const ocsd_generic_trace_elem *elem,
- const uint8_t trace_chan_id)
- {
-+ struct cs_etm_packet *packet;
- pid_t tid = -1;
-+ int ret;
-
- /*
- * Process the PE_CONTEXT packets if we have a valid contextID or VMID.
-@@ -539,12 +544,18 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
- break;
- }
-
-- if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
-- elem->context.exception_level))
-+ if (cs_etm__etmq_update_decode_context(etmq, trace_chan_id,
-+ elem->context.exception_level, tid))
- return OCSD_RESP_FATAL_SYS_ERR;
-
-- if (tid == -1)
-- return OCSD_RESP_CONT;
-+ ret = cs_etm_decoder__buffer_packet(etmq, packet_queue, trace_chan_id,
-+ CS_ETM_CONTEXT);
-+ if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
-+ return ret;
-+
-+ packet = &packet_queue->packet_buffer[packet_queue->tail];
-+ packet->tid = tid;
-+ packet->el = elem->context.exception_level;
-
- /*
- * A timestamp is generated after a PE_CONTEXT element so make sure
-@@ -552,7 +563,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
- */
- cs_etm_decoder__reset_timestamp(packet_queue);
-
-- return OCSD_RESP_CONT;
-+ return ret;
- }
-
- static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
-diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
-index 9077072994b23b..8dc12759ee62f4 100644
---- a/tools/perf/util/cs-etm.c
-+++ b/tools/perf/util/cs-etm.c
-@@ -86,15 +86,22 @@ struct cs_etm_traceid_queue {
- u64 period_instructions;
- size_t last_branch_pos;
- union perf_event *event_buf;
-- struct thread *thread;
-- struct thread *prev_packet_thread;
-- ocsd_ex_level prev_packet_el;
-- ocsd_ex_level el;
- struct branch_stack *last_branch;
- struct branch_stack *last_branch_rb;
- struct cs_etm_packet *prev_packet;
- struct cs_etm_packet *packet;
- struct cs_etm_packet_queue packet_queue;
-+
-+ struct thread *decode_thread;
-+ ocsd_ex_level decode_el;
-+
-+ /*
-+ * The frontend accesses the EL from '[prev_]packet' because it needs
-+ * previous EL for branch and current EL for instruction samples. It's
-+ * not possible to change thread in a single branch sample so no need to
-+ * store or access the thread through the packet.
-+ */
-+ struct thread *frontend_thread;
- };
-
- enum cs_etm_format {
-@@ -489,10 +496,11 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
-
- queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
- tidq->trace_chan_id = trace_chan_id;
-- tidq->el = tidq->prev_packet_el = ocsd_EL_unknown;
-- tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
-+ tidq->decode_el = ocsd_EL_unknown;
-+ tidq->frontend_thread = machine__findnew_thread(&etm->session->machines.host, -1,
-+ queue->tid);
-+ tidq->decode_thread = machine__findnew_thread(&etm->session->machines.host, -1,
- queue->tid);
-- tidq->prev_packet_thread = machine__idle_thread(&etm->session->machines.host);
-
- tidq->packet = zalloc(sizeof(struct cs_etm_packet));
- if (!tidq->packet)
-@@ -625,21 +633,10 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
- /*
- * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
- * the next incoming packet.
-- *
-- * Threads and exception levels are also tracked for both the
-- * previous and current packets. This is because the previous
-- * packet is used for the 'from' IP for branch samples, so the
-- * thread at that time must also be assigned to that sample.
-- * Across discontinuity packets the thread can change, so by
-- * tracking the thread for the previous packet the branch sample
-- * will have the correct info.
- */
- tmp = tidq->packet;
- tidq->packet = tidq->prev_packet;
- tidq->prev_packet = tmp;
-- tidq->prev_packet_el = tidq->el;
-- thread__put(tidq->prev_packet_thread);
-- tidq->prev_packet_thread = thread__get(tidq->thread);
- }
- }
-
-@@ -827,8 +824,8 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
-
- /* Free this traceid_queue from the array */
- tidq = etmq->traceid_queues[idx];
-- thread__zput(tidq->thread);
-- thread__zput(tidq->prev_packet_thread);
-+ thread__zput(tidq->frontend_thread);
-+ thread__zput(tidq->decode_thread);
- zfree(&tidq->event_buf);
- zfree(&tidq->last_branch);
- zfree(&tidq->last_branch_rb);
-@@ -969,47 +966,43 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
- }
- }
-
--static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
-- u64 address, size_t size, u8 *buffer,
-- const ocsd_mem_space_acc_t mem_space)
-+static u32 __cs_etm__mem_access(struct cs_etm_queue *etmq,
-+ u64 address, size_t size, u8 *buffer,
-+ const ocsd_mem_space_acc_t mem_space,
-+ ocsd_ex_level el, struct thread *thread)
- {
- u8 cpumode;
- u64 offset;
- int len;
- struct addr_location al;
- struct dso *dso;
-- struct cs_etm_traceid_queue *tidq;
- int ret = 0;
-
- if (!etmq)
- return 0;
-
- addr_location__init(&al);
-- tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
-- if (!tidq)
-- goto out;
-
- /*
-- * We've already tracked EL along side the PID in cs_etm__set_thread()
-- * so double check that it matches what OpenCSD thinks as well. It
-- * doesn't distinguish between EL0 and EL1 for this mem access callback
-- * so we had to do the extra tracking. Skip validation if it's any of
-- * the 'any' values.
-+ * We track EL for the frontend and the backend when receiving context
-+ * and range packets. OpenCSD doesn't distinguish between EL0 and EL1
-+ * for this mem access callback so we had to do the extra tracking. Skip
-+ * validation if it's any of the 'any' values.
- */
- if (!(mem_space == OCSD_MEM_SPACE_ANY ||
- mem_space == OCSD_MEM_SPACE_N || mem_space == OCSD_MEM_SPACE_S)) {
- if (mem_space & OCSD_MEM_SPACE_EL1N) {
- /* Includes both non secure EL1 and EL0 */
-- assert(tidq->el == ocsd_EL1 || tidq->el == ocsd_EL0);
-+ assert(el == ocsd_EL1 || el == ocsd_EL0);
- } else if (mem_space & OCSD_MEM_SPACE_EL2)
-- assert(tidq->el == ocsd_EL2);
-+ assert(el == ocsd_EL2);
- else if (mem_space & OCSD_MEM_SPACE_EL3)
-- assert(tidq->el == ocsd_EL3);
-+ assert(el == ocsd_EL3);
- }
-
-- cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
-+ cpumode = cs_etm__cpu_mode(etmq, address, el);
-
-- if (!thread__find_map(tidq->thread, cpumode, address, &al))
-+ if (!thread__find_map(thread, cpumode, address, &al))
- goto out;
-
- dso = map__dso(al.map);
-@@ -1024,7 +1017,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
-
- map__load(al.map);
-
-- len = dso__data_read_offset(dso, maps__machine(thread__maps(tidq->thread)),
-+ len = dso__data_read_offset(dso, maps__machine(thread__maps(thread)),
- offset, buffer, size);
-
- if (len <= 0) {
-@@ -1044,6 +1037,30 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
- return ret;
- }
-
-+static u32 cs_etm__frontend_mem_access(struct cs_etm_queue *etmq,
-+ struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet,
-+ u64 address, size_t size, u8 *buffer)
-+{
-+ return __cs_etm__mem_access(etmq, address, size, buffer, 0, packet->el,
-+ tidq->frontend_thread);
-+}
-+
-+static u32 cs_etm__decoder_mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
-+ u64 address, size_t size, u8 *buffer,
-+ const ocsd_mem_space_acc_t mem_space)
-+{
-+ struct cs_etm_traceid_queue *tidq;
-+
-+ tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
-+ if (!tidq)
-+ return 0;
-+
-+ return __cs_etm__mem_access(etmq, address, size, buffer,
-+ mem_space, tidq->decode_el,
-+ tidq->decode_thread);
-+}
-+
- static struct cs_etm_queue *cs_etm__alloc_queue(void)
- {
- struct cs_etm_queue *etmq = zalloc(sizeof(*etmq));
-@@ -1209,12 +1226,13 @@ void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
- }
-
- static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
-- u8 trace_chan_id, u64 addr)
-+ struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet, u64 addr)
- {
- u8 instrBytes[2];
-
-- cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes),
-- instrBytes, 0);
-+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
-+ ARRAY_SIZE(instrBytes), instrBytes);
- /*
- * T32 instruction size is indicated by bits[15:11] of the first
- * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111
-@@ -1243,16 +1261,16 @@ u64 cs_etm__last_executed_instr(const struct cs_etm_packet *packet)
- }
-
- static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
-- u64 trace_chan_id,
-- const struct cs_etm_packet *packet,
-+ struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet,
- u64 offset)
- {
- if (packet->isa == CS_ETM_ISA_T32) {
- u64 addr = packet->start_addr;
-
- while (offset) {
-- addr += cs_etm__t32_instr_size(etmq,
-- trace_chan_id, addr);
-+ addr += cs_etm__t32_instr_size(etmq, tidq, packet,
-+ addr);
- offset--;
- }
- return addr;
-@@ -1344,34 +1362,51 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
- return etmq->buf_len;
- }
-
--static void cs_etm__set_thread(struct cs_etm_queue *etmq,
-- struct cs_etm_traceid_queue *tidq, pid_t tid,
-- ocsd_ex_level el)
-+/*
-+ * Convert a raw thread number to a thread struct and assign it to **thread.
-+ */
-+static int cs_etm__etmq_update_thread(struct cs_etm_queue *etmq,
-+ ocsd_ex_level el, pid_t tid,
-+ struct thread **thread)
- {
- struct machine *machine = cs_etm__get_machine(etmq, el);
-
-+ if (!machine || !*thread)
-+ return -EINVAL;
-+
- if (tid != -1) {
-- thread__zput(tidq->thread);
-- tidq->thread = machine__find_thread(machine, -1, tid);
-+ thread__zput(*thread);
-+ *thread = machine__find_thread(machine, -1, tid);
- }
-
- /* Couldn't find a known thread */
-- if (!tidq->thread)
-- tidq->thread = machine__idle_thread(machine);
-+ if (!*thread)
-+ *thread = machine__idle_thread(machine);
-
-- tidq->el = el;
-+ return 0;
- }
-
--int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
-- u8 trace_chan_id, ocsd_ex_level el)
-+/*
-+ * Set the thread and EL of the decode context which is ahead in time of the
-+ * frontend context.
-+ */
-+int cs_etm__etmq_update_decode_context(struct cs_etm_queue *etmq,
-+ u8 trace_chan_id,
-+ ocsd_ex_level el, pid_t tid)
- {
- struct cs_etm_traceid_queue *tidq;
-+ int ret;
-
- tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
- if (!tidq)
- return -EINVAL;
-
-- cs_etm__set_thread(etmq, tidq, tid, el);
-+ ret = cs_etm__etmq_update_thread(etmq, el, tid,
-+ &tidq->decode_thread);
-+ if (ret)
-+ return ret;
-+
-+ tidq->decode_el = el;
- return 0;
- }
-
-@@ -1381,8 +1416,8 @@ bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq)
- }
-
- static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
-- u64 trace_chan_id,
-- const struct cs_etm_packet *packet,
-+ struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet,
- struct perf_sample *sample)
- {
- /*
-@@ -1399,14 +1434,14 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
- * cs_etm__t32_instr_size().
- */
- if (packet->isa == CS_ETM_ISA_T32)
-- sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id,
-+ sample->insn_len = cs_etm__t32_instr_size(etmq, tidq, packet,
- sample->ip);
- /* Otherwise, A64 and A32 instruction size are always 32-bit. */
- else
- sample->insn_len = 4;
-
-- cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len,
-- (void *)sample->insn, 0);
-+ cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip,
-+ sample->insn_len, (void *)sample->insn);
- }
-
- u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp)
-@@ -1433,6 +1468,7 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq,
-
- static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet,
- u64 addr, u64 period)
- {
- int ret = 0;
-@@ -1441,23 +1477,23 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
- struct perf_sample sample = {.ip = 0,};
-
- event->sample.header.type = PERF_RECORD_SAMPLE;
-- event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el);
-+ event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, packet->el);
- event->sample.header.size = sizeof(struct perf_event_header);
-
- /* Set time field based on etm auxtrace config. */
- sample.time = cs_etm__resolve_sample_time(etmq, tidq);
-
- sample.ip = addr;
-- sample.pid = thread__pid(tidq->thread);
-- sample.tid = thread__tid(tidq->thread);
-+ sample.pid = thread__pid(tidq->frontend_thread);
-+ sample.tid = thread__tid(tidq->frontend_thread);
- sample.id = etmq->etm->instructions_id;
- sample.stream_id = etmq->etm->instructions_id;
- sample.period = period;
-- sample.cpu = tidq->packet->cpu;
-+ sample.cpu = packet->cpu;
- sample.flags = tidq->prev_packet->flags;
- sample.cpumode = event->sample.header.misc;
-
-- cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample);
-+ cs_etm__copy_insn(etmq, tidq, packet, &sample);
-
- if (etm->synth_opts.last_branch)
- sample.branch_stack = tidq->last_branch;
-@@ -1501,15 +1537,15 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
-
- event->sample.header.type = PERF_RECORD_SAMPLE;
- event->sample.header.misc = cs_etm__cpu_mode(etmq, ip,
-- tidq->prev_packet_el);
-+ tidq->prev_packet->el);
- event->sample.header.size = sizeof(struct perf_event_header);
-
- /* Set time field based on etm auxtrace config. */
- sample.time = cs_etm__resolve_sample_time(etmq, tidq);
-
- sample.ip = ip;
-- sample.pid = thread__pid(tidq->prev_packet_thread);
-- sample.tid = thread__tid(tidq->prev_packet_thread);
-+ sample.pid = thread__pid(tidq->frontend_thread);
-+ sample.tid = thread__tid(tidq->frontend_thread);
- sample.addr = cs_etm__first_executed_instr(tidq->packet);
- sample.id = etmq->etm->branches_id;
- sample.stream_id = etmq->etm->branches_id;
-@@ -1518,8 +1554,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
- sample.flags = tidq->prev_packet->flags;
- sample.cpumode = event->sample.header.misc;
-
-- cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet,
-- &sample);
-+ cs_etm__copy_insn(etmq, tidq, tidq->prev_packet, &sample);
-
- /*
- * perf report cannot handle events without a branch stack
-@@ -1672,7 +1707,6 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
- {
- struct cs_etm_auxtrace *etm = etmq->etm;
- int ret;
-- u8 trace_chan_id = tidq->trace_chan_id;
- u64 instrs_prev;
-
- /* Get instructions remainder from previous packet */
-@@ -1758,10 +1792,10 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
- * been executed, but PC has not advanced to next
- * instruction)
- */
-- addr = cs_etm__instr_addr(etmq, trace_chan_id,
-- tidq->packet, offset - 1);
-+ addr = cs_etm__instr_addr(etmq, tidq, tidq->packet,
-+ offset - 1);
- ret = cs_etm__synth_instruction_sample(
-- etmq, tidq, addr,
-+ etmq, tidq, tidq->packet, addr,
- etm->instructions_sample_period);
- if (ret)
- return ret;
-@@ -1843,7 +1877,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
- addr = cs_etm__last_executed_instr(tidq->prev_packet);
-
- err = cs_etm__synth_instruction_sample(
-- etmq, tidq, addr,
-+ etmq, tidq, tidq->prev_packet, addr,
- tidq->period_instructions);
- if (err)
- return err;
-@@ -1898,7 +1932,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
- addr = cs_etm__last_executed_instr(tidq->prev_packet);
-
- err = cs_etm__synth_instruction_sample(
-- etmq, tidq, addr,
-+ etmq, tidq, tidq->prev_packet, addr,
- tidq->period_instructions);
- if (err)
- return err;
-@@ -1935,9 +1969,9 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq)
- return etmq->buf_len;
- }
-
--static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
-- struct cs_etm_packet *packet,
-- u64 end_addr)
-+static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
-+ struct cs_etm_traceid_queue *tidq,
-+ struct cs_etm_packet *packet, u64 end_addr)
- {
- /* Initialise to keep compiler happy */
- u16 instr16 = 0;
-@@ -1959,8 +1993,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
- * so below only read 2 bytes as instruction size for T32.
- */
- addr = end_addr - 2;
-- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16),
-- (u8 *)&instr16, 0);
-+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
-+ sizeof(instr16), (u8 *)&instr16);
- if ((instr16 & 0xFF00) == 0xDF00)
- return true;
-
-@@ -1975,8 +2009,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
- * +---------+---------+-------------------------+
- */
- addr = end_addr - 4;
-- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
-- (u8 *)&instr32, 0);
-+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
-+ sizeof(instr32), (u8 *)&instr32);
- if ((instr32 & 0x0F000000) == 0x0F000000 &&
- (instr32 & 0xF0000000) != 0xF0000000)
- return true;
-@@ -1992,8 +2026,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
- * +-----------------------+---------+-----------+
- */
- addr = end_addr - 4;
-- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
-- (u8 *)&instr32, 0);
-+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
-+ sizeof(instr32), (u8 *)&instr32);
- if ((instr32 & 0xFFE0001F) == 0xd4000001)
- return true;
-
-@@ -2009,7 +2043,6 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
- static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq, u64 magic)
- {
-- u8 trace_chan_id = tidq->trace_chan_id;
- struct cs_etm_packet *packet = tidq->packet;
- struct cs_etm_packet *prev_packet = tidq->prev_packet;
-
-@@ -2024,7 +2057,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
- */
- if (magic == __perf_cs_etmv4_magic) {
- if (packet->exception_number == CS_ETMV4_EXC_CALL &&
-- cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
-+ cs_etm__is_svc_instr(etmq, tidq, prev_packet,
- prev_packet->end_addr))
- return true;
- }
-@@ -2062,7 +2095,6 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq,
- u64 magic)
- {
-- u8 trace_chan_id = tidq->trace_chan_id;
- struct cs_etm_packet *packet = tidq->packet;
- struct cs_etm_packet *prev_packet = tidq->prev_packet;
-
-@@ -2088,7 +2120,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
- * (SMC, HVC) are taken as sync exceptions.
- */
- if (packet->exception_number == CS_ETMV4_EXC_CALL &&
-- !cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
-+ !cs_etm__is_svc_instr(etmq, tidq, prev_packet,
- prev_packet->end_addr))
- return true;
-
-@@ -2112,7 +2144,6 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
- {
- struct cs_etm_packet *packet = tidq->packet;
- struct cs_etm_packet *prev_packet = tidq->prev_packet;
-- u8 trace_chan_id = tidq->trace_chan_id;
- u64 magic;
- int ret;
-
-@@ -2193,11 +2224,11 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
- if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
- PERF_IP_FLAG_RETURN |
- PERF_IP_FLAG_INTERRUPT) &&
-- cs_etm__is_svc_instr(etmq, trace_chan_id,
-- packet, packet->start_addr))
-+ cs_etm__is_svc_instr(etmq, tidq, packet, packet->start_addr)) {
- prev_packet->flags = PERF_IP_FLAG_BRANCH |
- PERF_IP_FLAG_RETURN |
- PERF_IP_FLAG_SYSCALLRET;
-+ }
- break;
- case CS_ETM_DISCONTINUITY:
- /*
-@@ -2278,6 +2309,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
- PERF_IP_FLAG_RETURN |
- PERF_IP_FLAG_INTERRUPT;
- break;
-+ case CS_ETM_CONTEXT:
- case CS_ETM_EMPTY:
- default:
- break;
-@@ -2353,6 +2385,19 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
- */
- cs_etm__sample(etmq, tidq);
- break;
-+ case CS_ETM_CONTEXT:
-+ /*
-+ * Update context but don't swap packet. Keep the
-+ * previous one for branch source address info, if
-+ * tracing the kernel the context packet will be emitted
-+ * between two ranges.
-+ */
-+ ret = cs_etm__etmq_update_thread(etmq, tidq->packet->el,
-+ tidq->packet->tid,
-+ &tidq->frontend_thread);
-+ if (ret)
-+ goto out;
-+ break;
- case CS_ETM_EXCEPTION:
- case CS_ETM_EXCEPTION_RET:
- /*
-@@ -2381,6 +2426,7 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
- }
- }
-
-+out:
- return ret;
- }
-
-@@ -2504,7 +2550,7 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
- if (!tidq)
- continue;
-
-- if (tid == -1 || thread__tid(tidq->thread) == tid)
-+ if (tid == -1 || thread__tid(tidq->frontend_thread) == tid)
- cs_etm__run_per_thread_timeless_decoder(etmq);
- } else
- cs_etm__run_per_cpu_timeless_decoder(etmq);
-@@ -3245,7 +3291,7 @@ static int cs_etm__create_queue_decoders(struct cs_etm_queue *etmq)
- */
- if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
- 0x0L, ((u64) -1L),
-- cs_etm__mem_access))
-+ cs_etm__decoder_mem_access))
- goto out_free_decoder;
-
- zfree(&t_params);
-diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
-index 7cca3788791760..f7b4903d9ef726 100644
---- a/tools/perf/util/cs-etm.h
-+++ b/tools/perf/util/cs-etm.h
-@@ -158,6 +158,7 @@ enum cs_etm_sample_type {
- CS_ETM_DISCONTINUITY,
- CS_ETM_EXCEPTION,
- CS_ETM_EXCEPTION_RET,
-+ CS_ETM_CONTEXT,
- };
-
- enum cs_etm_isa {
-@@ -184,6 +185,8 @@ struct cs_etm_packet {
- u8 last_instr_size;
- u8 trace_chan_id;
- int cpu;
-+ int el;
-+ pid_t tid;
- };
-
- #define CS_ETM_PACKET_MAX_BUFFER 1024
-@@ -254,8 +257,9 @@ enum cs_etm_pid_fmt {
- #include <opencsd/ocsd_if_types.h>
- int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
- enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
--int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
-- u8 trace_chan_id, ocsd_ex_level el);
-+int cs_etm__etmq_update_decode_context(struct cs_etm_queue *etmq,
-+ u8 trace_chan_id, ocsd_ex_level el,
-+ pid_t tid);
- bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
- void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
- u8 trace_chan_id);
---
-2.53.0
-
+++ /dev/null
-From 98883f6635158ab03af655b28574d19b6fa40078 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 13 Jun 2026 14:40:36 -0300
-Subject: perf cs-etm: Require full global header in auxtrace_info size check
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 78d8ba680126f3545e8d0fba667e12d79fd4353b ]
-
-cs_etm__process_auxtrace_info() checks that header.size covers
-event_header_size + INFO_HEADER_SIZE (16 bytes total), but then
-accesses ptr[CS_PMU_TYPE_CPUS] at offset 24 from the start of the
-event. A crafted 16-byte auxtrace_info event passes the size check
-but reads out-of-bounds.
-
-Include CS_ETM_HEADER_SIZE in the minimum size check so that the
-global header entries (version, pmu_type_cpus, snapshot) are
-guaranteed to fit within the event.
-
-Fixes: 55c1de9973d66516 ("perf cs-etm: Print auxtrace info even if OpenCSD isn't linked")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: James Clark <james.clark@arm.com>
-Cc: Leo Yan <leo.yan@linaro.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cs-etm-base.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/cs-etm-base.c b/tools/perf/util/cs-etm-base.c
-index 4abe416e3febd2..aebef71d3a0a1d 100644
---- a/tools/perf/util/cs-etm-base.c
-+++ b/tools/perf/util/cs-etm-base.c
-@@ -170,7 +170,9 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
- u64 *ptr = NULL;
- u64 hdr_version;
-
-- if (auxtrace_info->header.size < (event_header_size + INFO_HEADER_SIZE))
-+ /* Ensure priv[] is large enough for the global header entries */
-+ if (auxtrace_info->header.size < (event_header_size + INFO_HEADER_SIZE +
-+ CS_ETM_HEADER_SIZE))
- return -EINVAL;
-
- /* First the global part */
---
-2.53.0
-
+++ /dev/null
-From c87c6ffb8c6f2a98fd5e116e612202a349664ad4 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 13 Jun 2026 14:16:45 -0300
-Subject: perf cs-etm: Validate num_cpu before metadata allocation
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 312d91329b8fc6989a916a3f9a12d0674167b7e4 ]
-
-cs_etm__process_auxtrace_info_full() reads num_cpu from untrusted
-perf.data and uses it to allocate the metadata pointer array:
-
- metadata = zalloc(sizeof(*metadata) * num_cpu);
-
-On 32-bit, sizeof(*metadata) is 4, so num_cpu = 0x40000000 overflows
-the multiplication to 0, causing zalloc(0) to return a valid zero-sized
-allocation followed by out-of-bounds writes in the population loop.
-
-Fix by computing priv_size early and using it to bound num_cpu: each
-CPU needs at least one u64 metadata entry, so num_cpu cannot exceed
-the total number of u64 entries in the event's private data area.
-
-Fixes: cd8bfd8c973eaff8 ("perf tools: Add processing of coresight metadata")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: James Clark <james.clark@arm.com>
-Cc: Leo Yan <leo.yan@linaro.org>
-Cc: Tor Jeremiassen <tor@ti.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cs-etm.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
-index 8dc12759ee62f4..10ea1e3254fe21 100644
---- a/tools/perf/util/cs-etm.c
-+++ b/tools/perf/util/cs-etm.c
-@@ -3355,6 +3355,18 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
- /* First the global part */
- ptr = (u64 *) auxtrace_info->priv;
- num_cpu = ptr[CS_PMU_TYPE_CPUS] & 0xffffffff;
-+
-+ /*
-+ * Bound num_cpu by the event size: the global header consumes
-+ * CS_ETM_HEADER_SIZE bytes, and each CPU needs at least one u64
-+ * metadata entry after that.
-+ */
-+ priv_size = total_size - event_header_size - INFO_HEADER_SIZE -
-+ CS_ETM_HEADER_SIZE;
-+ if (num_cpu <= 0 || priv_size <= 0 ||
-+ num_cpu > priv_size / (int)sizeof(u64))
-+ return -EINVAL;
-+
- metadata = zalloc(sizeof(*metadata) * num_cpu);
- if (!metadata) {
- err = -ENOMEM;
---
-2.53.0
-
+++ /dev/null
-From 405e9041717f0756841c6f187edeb46c8e2f5451 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 2 May 2026 14:37:39 -0300
-Subject: perf header: Sanity check HEADER_EVENT_DESC attr.size before swap
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 944f65c8b8231d26d4db6be67bcb641142603cb4 ]
-
-read_event_desc() reads nre (event count), sz (attr size), and nr
-(IDs per event) from the file and uses them to control allocations
-and loops without validating them against the section size.
-
-A crafted perf.data could trigger large allocations or many loop
-iterations before __do_read() eventually rejects the reads.
-
-Add bounds checks in read_event_desc():
-- Reject sz smaller than PERF_ATTR_SIZE_VER0.
-- Require at least one event (nre > 0).
-- Check that nre events fit in the remaining section, using the
- minimum per-event footprint of sz + sizeof(u32).
-- Pre-swap attr->size to native byte order, then reject values
- below PERF_ATTR_SIZE_VER0 or above sz before calling
- perf_event__attr_swap() to prevent heap out-of-bounds access.
-- Handle ABI0 (attr.size == 0): substitute PERF_ATTR_SIZE_VER0,
- and on native-endian files write the value back so
- free_event_desc() does not treat the zero as its end-of-array
- sentinel (it iterates while attr.size != 0). The swap path
- skips the write-back — perf_event__attr_swap() has its own
- ABI0 fallback that sets VER0 after swapping.
-- Check that nr IDs fit in the remaining section before allocating.
-
-Fixes: b30b61729246 ("perf tools: Fix a problem when opening old perf.data with different byte order")
-Reported-by: sashiko-bot@kernel.org # Running on a local machine
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Cc: Wang Nan <wangnan0@huawei.com>
-Assisted-by: Claude:claude-opus-4.6-1m
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/header.c | 54 ++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 54 insertions(+)
-
-diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
-index 0b44176826bfd9..50b0c98f44b87a 100644
---- a/tools/perf/util/header.c
-+++ b/tools/perf/util/header.c
-@@ -1940,9 +1940,28 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
- if (do_read_u32(ff, &nre))
- goto error;
-
-+ /* Size of each of the nre attributes. */
- if (do_read_u32(ff, &sz))
- goto error;
-
-+ /*
-+ * Require at least one event with an attr no smaller than the
-+ * first published struct, and reject sz values where
-+ * sz + sizeof(u32) would overflow size_t (possible on 32-bit)
-+ * or nre == UINT32_MAX where nre + 1 wraps to 0 in the calloc.
-+ *
-+ * The minimum section footprint per event is sz bytes for the
-+ * attr plus a u32 for the id count, check that nre events fit.
-+ */
-+ if (!nre || sz < PERF_ATTR_SIZE_VER0 ||
-+ sz > ff->size || (size_t)sz > SIZE_MAX - sizeof(u32) ||
-+ nre == UINT32_MAX ||
-+ nre > (ff->size - ff->offset) / (sz + sizeof(u32))) {
-+ pr_err("Invalid HEADER_EVENT_DESC: nre=%u sz=%u (min %d)\n",
-+ nre, sz, PERF_ATTR_SIZE_VER0);
-+ goto error;
-+ }
-+
- /* buffer to hold on file attr struct */
- buf = malloc(sz);
- if (!buf)
-@@ -1958,6 +1977,9 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
- msz = sz;
-
- for (i = 0, evsel = events; i < nre; evsel++, i++) {
-+ struct perf_event_attr *attr = buf;
-+ u32 attr_size;
-+
- evsel->core.idx = i;
-
- /*
-@@ -1967,6 +1989,32 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
- if (__do_read(ff, buf, sz))
- goto error;
-
-+ /* Reject before attr_swap to prevent OOB via bswap_safe() */
-+ attr_size = ff->ph->needs_swap ? bswap_32(attr->size) : attr->size;
-+ /* ABI0: size == 0 means the producer didn't set it */
-+ if (!attr_size) {
-+ attr_size = PERF_ATTR_SIZE_VER0;
-+ /*
-+ * Write back so free_event_desc() doesn't
-+ * treat this event as the end-of-array sentinel
-+ * (it iterates while attr.size != 0).
-+ *
-+ * Only for native — the swap path must NOT
-+ * write native-endian VER0 here because
-+ * perf_event__attr_swap() would re-swap it
-+ * to 0x40000000, defeating bswap_safe() bounds.
-+ * perf_event__attr_swap() has its own ABI0
-+ * fallback that sets VER0 after swapping.
-+ */
-+ if (!ff->ph->needs_swap)
-+ attr->size = attr_size;
-+ }
-+ if (attr_size < PERF_ATTR_SIZE_VER0 || attr_size > sz) {
-+ pr_err("Event %d attr.size (%u) invalid (min: %d, max: %u)\n",
-+ i, attr_size, PERF_ATTR_SIZE_VER0, sz);
-+ goto error;
-+ }
-+
- if (ff->ph->needs_swap)
- perf_event__attr_swap(buf);
-
-@@ -1988,6 +2036,12 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
- if (!nr)
- continue;
-
-+ /* Prevent oversized allocation from crafted nr */
-+ if (nr > (ff->size - ff->offset) / sizeof(*id)) {
-+ pr_err("Event %d: id count %u exceeds remaining section\n", i, nr);
-+ goto error;
-+ }
-+
- id = calloc(nr, sizeof(*id));
- if (!id)
- goto error;
---
-2.53.0
-
+++ /dev/null
-From 08cedb9ea84e58efed17378c804283198b50d135 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 14:35:28 -0300
-Subject: perf hists: Fix snprintf() in hists__scnprintf_title() UID filter
- path
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 227a8748742f0263f1fe3131449b44563b77a209 ]
-
-hists__scnprintf_title() accumulates formatted output into a buffer
-using scnprintf() for all filter clauses except the UID filter, which
-uses snprintf(). If the buffer fills up and snprintf() returns more
-than the remaining space, printed exceeds size and the next 'size -
-printed' underflows, causing later scnprintf() calls to write past
-the buffer.
-
-Switch the UID filter clause to scnprintf() to match the rest of the
-function.
-
-Fixes: 25c312dbf88ca402 ("perf hists: Move hists__scnprintf_title() away from the TUI code")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/hist.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
-index aa450cc2648aa5..2f2a8302b796fe 100644
---- a/tools/perf/util/hist.c
-+++ b/tools/perf/util/hist.c
-@@ -2800,9 +2800,10 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh
- ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
-
-
-- if (hists->uid_filter_str)
-- printed += snprintf(bf + printed, size - printed,
-- ", UID: %s", hists->uid_filter_str);
-+ if (hists->uid_filter_str) {
-+ printed += scnprintf(bf + printed, size - printed,
-+ ", UID: %s", hists->uid_filter_str);
-+ }
- if (thread) {
- if (hists__has(hists, thread)) {
- printed += scnprintf(bf + printed, size - printed,
---
-2.53.0
-
+++ /dev/null
-From dfb1e8789172d87b584d7cd3b6684bfff753578e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 21:06:54 -0300
-Subject: perf intel-pt: Fix snprintf size tracking bug in insn decoder
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit b6bb3b005dcdd960b8e0b7f9d6869132b3de08d5 ]
-
-dump_insn() tracks remaining buffer space with a 'left' variable,
-but the loop subtracts the cumulative offset 'n' each iteration
-instead of just the per-iteration delta:
-
- n += snprintf(x->out + n, left, "%02x ", inbuf[i]);
- left -= n; /* BUG: n is cumulative, not the delta */
-
-After two iterations left goes massively negative, wrapping to a
-huge value when passed as size_t to snprintf(), disabling all bounds
-checking for the rest of the loop.
-
-Switch to scnprintf() accumulation using sizeof(x->out) - n as the
-remaining space, which is always correct and eliminates the separate
-'left' variable entirely.
-
-Fixes: 48d02a1d5c137d36 ("perf script: Add 'brstackinsn' for branch stacks")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: Andi Kleen <ak@linux.intel.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- .../util/intel-pt-decoder/intel-pt-insn-decoder.c | 11 +++--------
- 1 file changed, 3 insertions(+), 8 deletions(-)
-
-diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
-index c5d57027ec23d3..03a143a02d40db 100644
---- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
-+++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
-@@ -213,7 +213,6 @@ const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
- {
- struct insn insn;
- int n, i, ret;
-- int left;
-
- ret = insn_decode(&insn, inbuf, inlen,
- x->is64bit ? INSN_MODE_64 : INSN_MODE_32);
-@@ -222,13 +221,9 @@ const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
- return "<bad>";
- if (lenp)
- *lenp = insn.length;
-- left = sizeof(x->out);
-- n = snprintf(x->out, left, "insn: ");
-- left -= n;
-- for (i = 0; i < insn.length; i++) {
-- n += snprintf(x->out + n, left, "%02x ", inbuf[i]);
-- left -= n;
-- }
-+ n = scnprintf(x->out, sizeof(x->out), "insn: ");
-+ for (i = 0; i < insn.length; i++)
-+ n += scnprintf(x->out + n, sizeof(x->out) - n, "%02x ", inbuf[i]);
- return x->out;
- }
-
---
-2.53.0
-
+++ /dev/null
-From 5e004479a0318cbcb9b517a02efb76acf8b8f9ee Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 13 Jun 2026 13:59:39 -0300
-Subject: perf machine: Use snprintf() for guestmount path construction
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit fe63d3bca288c5bb983304efd5fc3a5ff3183403 ]
-
-machines__findnew() and machines__create_guest_kernel_maps() use
-sprintf() to build paths by prepending symbol_conf.guestmount.
-Both write into PATH_MAX stack buffers, but guestmount comes from
-user configuration and is not length-checked. A guestmount path
-at or near PATH_MAX causes a stack buffer overflow.
-
-Switch to snprintf() with sizeof() to prevent overflow. The
-subsequent access()/fopen() calls will fail on a truncated path.
-
-Fixes: a1645ce12adb6c9c ("perf: 'perf kvm' tool for monitoring guest performance from host")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Zhang, Yanmin <yanmin_zhang@linux.intel.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/machine.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
-index 2f5a5245483ede..9e462ebdaca686 100644
---- a/tools/perf/util/machine.c
-+++ b/tools/perf/util/machine.c
-@@ -369,7 +369,7 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)
- if ((pid != HOST_KERNEL_ID) &&
- (pid != DEFAULT_GUEST_KERNEL_ID) &&
- (symbol_conf.guestmount)) {
-- sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
-+ snprintf(path, sizeof(path), "%s/%d", symbol_conf.guestmount, pid);
- if (access(path, R_OK)) {
- static struct strlist *seen;
-
-@@ -1415,9 +1415,9 @@ int machines__create_guest_kernel_maps(struct machines *machines)
- namelist[i]->d_name);
- continue;
- }
-- sprintf(path, "%s/%s/proc/kallsyms",
-- symbol_conf.guestmount,
-- namelist[i]->d_name);
-+ snprintf(path, sizeof(path), "%s/%s/proc/kallsyms",
-+ symbol_conf.guestmount,
-+ namelist[i]->d_name);
- ret = access(path, R_OK);
- if (ret) {
- pr_debug("Can't access file %s\n", path);
---
-2.53.0
-
+++ /dev/null
-From 4a699e34d9fcf171390869dc8f7b8abe2a969c74 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 11:03:29 -0300
-Subject: perf mmap: Fix NULL deref in aio cleanup on alloc failure
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 25627346b10e6a564610ea2c49dc6dd54812226d ]
-
-perf_mmap__aio_mmap() sets map->aio.nr_cblocks before allocating the
-data array. If calloc() for aiocb or cblocks fails before the data
-array is allocated, the return -1 path leads to perf_mmap__aio_munmap()
-which loops nr_cblocks times calling perf_mmap__aio_free(). Both
-versions of perf_mmap__aio_free() (NUMA and non-NUMA) dereference
-map->aio.data[idx] without checking if data is NULL, causing a NULL
-pointer dereference.
-
-Add NULL checks for map->aio.data at the top of both
-perf_mmap__aio_free() variants so the cleanup path is safe when
-allocation fails partway through perf_mmap__aio_mmap().
-
-Fixes: d3d1af6f011a553a ("perf record: Enable asynchronous trace writing")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/mmap.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
-index 99f6235dd16afd..79178528af10e4 100644
---- a/tools/perf/util/mmap.c
-+++ b/tools/perf/util/mmap.c
-@@ -88,10 +88,10 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)
-
- static void perf_mmap__aio_free(struct mmap *map, int idx)
- {
-- if (map->aio.data[idx]) {
-- munmap(map->aio.data[idx], mmap__mmap_len(map));
-- map->aio.data[idx] = NULL;
-- }
-+ if (!map->aio.data || !map->aio.data[idx])
-+ return;
-+ munmap(map->aio.data[idx], mmap__mmap_len(map));
-+ map->aio.data[idx] = NULL;
- }
-
- static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, int affinity)
-@@ -140,6 +140,8 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)
-
- static void perf_mmap__aio_free(struct mmap *map, int idx)
- {
-+ if (!map->aio.data)
-+ return;
- zfree(&(map->aio.data[idx]));
- }
-
---
-2.53.0
-
+++ /dev/null
-From 6d0ce80e9933ccde329905e4f16b009131014385 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 5 Jun 2026 10:56:33 -0300
-Subject: perf mmap: Guard cpu__get_node() return in aio_bind()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit f32dc302a090f48893477ef297a888db109ec0bd ]
-
-perf_mmap__aio_bind() passes the cpu__get_node() return value directly
-to an unsigned long variable (node_index). When cpu__get_node() returns
--1 for an unknown CPU, the implicit int-to-unsigned-long conversion
-sign-extends it to ULONG_MAX.
-
-This causes bitmap_zalloc(ULONG_MAX + 1) which wraps to
-bitmap_zalloc(0), returning a zero-sized allocation. The subsequent
-__set_bit(ULONG_MAX, node_mask) then writes massively out of bounds.
-
-Check the return value in a signed temporary before assigning to
-node_index, and skip the NUMA binding when the node is unknown.
-
-Fixes: c44a8b44ca9f ("perf record: Bind the AIO user space buffers to nodes")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/mmap.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
-index 49093b21ee2da0..99f6235dd16afd 100644
---- a/tools/perf/util/mmap.c
-+++ b/tools/perf/util/mmap.c
-@@ -103,9 +103,15 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, i
- int err = 0;
-
- if (affinity != PERF_AFFINITY_SYS && cpu__max_node() > 1) {
-+ int node;
-+
- data = map->aio.data[idx];
- mmap_len = mmap__mmap_len(map);
-- node_index = cpu__get_node(cpu);
-+ node = cpu__get_node(cpu);
-+ /* -1 sign-extends to ULONG_MAX, wrapping bitmap_zalloc(0) and OOB __set_bit */
-+ if (node < 0)
-+ return 0;
-+ node_index = node;
- node_mask = bitmap_zalloc(node_index + 1);
- if (!node_mask) {
- pr_err("Failed to allocate node mask for mbind: error %m\n");
---
-2.53.0
-
+++ /dev/null
-From 8b69cba01ceb9555fd9b71f2d41c1035e34c71ad Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 21:03:13 -0300
-Subject: perf pmu: Fix perf_pmu__parse_scale/unit() OOB access on empty sysfs
- file
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 33035f7dd4e49f3f117e70c5e36c8c1ae88d37f2 ]
-
-perf_pmu__parse_scale() reads a PMU scale file then accesses
-scale[sret - 1] to strip a trailing newline. Only sret < 0 is
-guarded, so an empty file (sret == 0) causes scale[-1] — a stack
-buffer underflow that reads and potentially writes out of bounds.
-
-perf_pmu__parse_unit() has the same pattern: alias->unit[sret - 1]
-with sret == 0 accesses the byte before the struct member, which
-may corrupt the adjacent pmu_name pointer field.
-
-Change both guards from sret < 0 to sret <= 0 so that empty files
-are treated as read errors.
-
-Fixes: 410136f5dd96b601 ("tools/perf/stat: Add event unit and scale support")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Stephane Eranian <eranian@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/pmu.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
-index e05dff925aa069..d5daa6e43522db 100644
---- a/tools/perf/util/pmu.c
-+++ b/tools/perf/util/pmu.c
-@@ -318,7 +318,7 @@ static int perf_pmu__parse_scale(struct perf_pmu *pmu, struct perf_pmu_alias *al
- goto error;
-
- sret = read(fd, scale, sizeof(scale)-1);
-- if (sret < 0)
-+ if (sret <= 0)
- goto error;
-
- if (scale[sret - 1] == '\n')
-@@ -350,7 +350,7 @@ static int perf_pmu__parse_unit(struct perf_pmu *pmu, struct perf_pmu_alias *ali
- return -1;
-
- sret = read(fd, alias->unit, UNIT_MAX_LEN);
-- if (sret < 0)
-+ if (sret <= 0)
- goto error;
-
- close(fd);
---
-2.53.0
-
+++ /dev/null
-From f7d2d8790880c73216204ac635db9567f1fc2a45 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 21:01:43 -0300
-Subject: perf pmu: Fix pmu_id() heap underwrite on empty identifier file
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 836455e6dbd34eb3d12eeab5e2d2b9a7f1512459 ]
-
-pmu_id() calls filename__read_str() then strips the trailing newline
-via str[len - 1] = 0. If the PMU identifier file is empty,
-filename__read_str() succeeds with len = 0. len - 1 underflows
-size_t to SIZE_MAX, writing a null byte before the heap allocation.
-
-Add a len == 0 check before the newline stripping.
-
-Fixes: 51d548471510843e ("perf pmu: Add pmu_id()")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: John Garry <john.g.garry@oracle.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/pmu.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
-index 2587c4b463fa88..e05dff925aa069 100644
---- a/tools/perf/util/pmu.c
-+++ b/tools/perf/util/pmu.c
-@@ -774,6 +774,12 @@ static char *pmu_id(const char *name)
- if (filename__read_str(path, &str, &len) < 0)
- return NULL;
-
-+ /* empty identifier file — nothing useful */
-+ if (len == 0) {
-+ free(str);
-+ return NULL;
-+ }
-+
- str[len - 1] = 0; /* remove line feed */
-
- return str;
---
-2.53.0
-
+++ /dev/null
-From f96965422da026a3ffc8ca7b2b3621f65a29c330 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 10 Apr 2026 12:13:44 +0100
-Subject: perf pmu: Skip test on Arm64 when #slots is zero
-
-From: Leo Yan <leo.yan@arm.com>
-
-[ Upstream commit 2e2ba7d1ea554ee6e9e751a53eebf3e9270b0670 ]
-
-Some Arm64 PMUs expose 'caps/slots' as 0 when the slot count is not
-implemented, tool_pmu__read_event() currently returns false for this,
-so metrics that reference #slots are reported as syntax error.
-
-Since the commit 3a61fd866ef9 ("perf expr: Return -EINVAL for syntax
-error in expr__find_ids()"), these syntax errors are populated as
-failures and make the PMU metric test fail:
-
- 9.3: Parsing of PMU event table metrics:
- --- start ---
- ...
-
- Found metric 'backend_bound'
- metric expr 100 * (stall_slot_backend / (#slots * cpu_cycles)) for backend_bound
- parsing metric: 100 * (stall_slot_backend / (#slots * cpu_cycles))
- Failure to read '#slots'
- literal: #slots = nan
- syntax error
- Fail to parse metric or group `backend_bound'
-
- ...
- ---- end(-1) ----
- 9.3: Parsing of PMU event table metrics : FAILED!
-
-This commit introduces a new function is_expected_broken_metric() to
-identify broken metrics, and treats metrics containing "#slots" as
-expected broken when #slots == 0 on Arm64 platforms.
-
-Fixes: 3a61fd866ef9aaa1 ("perf expr: Return -EINVAL for syntax error in expr__find_ids()")
-Reviewed-by: Ian Rogers <irogers@google.com>
-Reviewed-by: James Clark <james.clark@linaro.org>
-Signed-off-by: Leo Yan <leo.yan@arm.com>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/tests/pmu-events.c | 24 ++++++++++++++++++++++--
- 1 file changed, 22 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
-index f5321fbdee79d1..2ed9d2ad792e2b 100644
---- a/tools/perf/tests/pmu-events.c
-+++ b/tools/perf/tests/pmu-events.c
-@@ -15,6 +15,7 @@
- #include "util/expr.h"
- #include "util/hashmap.h"
- #include "util/parse-events.h"
-+#include "util/tool_pmu.h"
- #include "metricgroup.h"
- #include "stat.h"
-
-@@ -804,6 +805,26 @@ struct metric {
- struct metric_ref metric_ref;
- };
-
-+static bool is_expected_broken_metric(const struct pmu_metric *pm)
-+{
-+ if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
-+ !strcmp(pm->metric_name, "M3"))
-+ return true;
-+
-+#if defined(__aarch64__)
-+ /*
-+ * Arm64 platforms may return "#slots == 0", which is treated as a
-+ * syntax error by the parser. Don't test these metrics when running
-+ * on such platforms.
-+ */
-+ if (strstr(pm->metric_expr, "#slots") &&
-+ !tool_pmu__cpu_slots_per_cycle())
-+ return true;
-+#endif
-+
-+ return false;
-+}
-+
- static int test__parsing_callback(const struct pmu_metric *pm,
- const struct pmu_metrics_table *table,
- void *data)
-@@ -842,8 +863,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
-
- err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events);
- if (err) {
-- if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
-- !strcmp(pm->metric_name, "M3")) {
-+ if (is_expected_broken_metric(pm)) {
- (*failures)--;
- pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
- err = 0;
---
-2.53.0
-
+++ /dev/null
-From 15c0fbdbfccdfca66a34ebfb32e653be30457a46 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 5 May 2026 17:45:42 -0700
-Subject: perf sched: Add missing mmap2 handler in timehist
-
-From: Ian Rogers <irogers@google.com>
-
-[ Upstream commit 91182741369b261c441e63e6678893032a6d7e4c ]
-
-perf_sched__timehist() registers event handlers for options using the
-sched->tool struct. It registers handlers for MMAP, COMM, EXIT, FORK, etc.
-but completely omits registering a handler for MMAP2 events.
-
-Failing to register both MMAP and MMAP2 handlers causes modern systems
-(which primarily output MMAP2 records) to silently drop VMA map mappings.
-This results in uninitialized machine/thread mapping structures, making it
-impossible to resolve shared library instruction pointers (IPs) to dynamic
-symbols/DSOs during timehist callchain analysis.
-
-Fix this by correctly registering perf_event__process_mmap2 in
-sched->tool inside perf_sched__timehist().
-
-Fixes: 49394a2a24c78ce0 ("perf sched timehist: Introduce timehist command")
-Assisted-by: Gemini-CLI:Google Gemini 3
-Signed-off-by: Ian Rogers <irogers@google.com>
-Cc: Adrian Hunter <adrian.hunter@intel.com>
-Cc: David Ahern <dsahern@gmail.com>
-Cc: Gabriel Marin <gmx@google.com>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: James Clark <james.clark@linaro.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Cc: Peter Zijlstra <peterz@infradead.org>
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 16cb7278fabaf7..1a22314094e6ad 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -3067,6 +3067,7 @@ static int perf_sched__timehist(struct perf_sched *sched)
- */
- sched->tool.sample = perf_timehist__process_sample;
- sched->tool.mmap = perf_event__process_mmap;
-+ sched->tool.mmap2 = perf_event__process_mmap2;
- sched->tool.comm = perf_event__process_comm;
- sched->tool.exit = perf_event__process_exit;
- sched->tool.fork = perf_event__process_fork;
---
-2.53.0
-
+++ /dev/null
-From eb274c7daa284d4f5057eac6aff1679a33634f96 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 5 Jun 2026 11:12:08 -0300
-Subject: perf sched: Clean up idle_threads entry on init failure
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit cda5a94ad9181cd60cbf04be11d524201bf489a2 ]
-
-get_idle_thread() allocates a thread via thread__new() and stores it in
-idle_threads[cpu], then calls init_idle_thread() to set up the private
-data. If init_idle_thread() fails (e.g. OOM for the idle_thread_runtime
-struct), the function returns NULL but leaves the partially initialized
-thread in idle_threads[cpu].
-
-On subsequent calls for the same CPU, get_idle_thread() finds a non-NULL
-idle_threads[cpu], skips allocation, and returns thread__get() on a
-thread that has no priv data. Callers then get a thread whose
-thread__priv() returns NULL, leading to unexpected behavior.
-
-Release the thread and reset the slot to NULL on init failure so the
-entry doesn't persist in a corrupted state.
-
-Fixes: 49394a2a24c7 ("perf sched timehist: Introduce timehist command")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: David Ahern <dsahern@gmail.com>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 6df0d1252f197f..0a1a58f33ae651 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -2372,8 +2372,11 @@ static struct thread *get_idle_thread(int cpu)
- idle_threads[cpu] = thread__new(0, 0);
-
- if (idle_threads[cpu]) {
-- if (init_idle_thread(idle_threads[cpu]) < 0)
-+ if (init_idle_thread(idle_threads[cpu]) < 0) {
-+ /* clean up so next call doesn't find a half-initialized thread */
-+ thread__zput(idle_threads[cpu]);
- return NULL;
-+ }
- }
- }
-
---
-2.53.0
-
+++ /dev/null
-From 2ed9224a2868664155d190aa076b40e504e95880 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 21:49:16 -0300
-Subject: perf sched: Fix idle-hist callchain display using wrong rb_first
- variant
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit d9b99dc8148e0c1f5da3942131b47e0d21187a32 ]
-
-timehist_print_idlehist_callchain() calls rb_first_cached() on
-sorted_root, but the sort function (callchain_param.sort) populates it
-via rb_insert_color() on the plain rb_root member — not the cached
-variant. This means rb_leftmost is never set, so rb_first_cached()
-always returns NULL and the entire callchain summary is silently
-dropped from --idle-hist output.
-
-The original code in ba957ebb54893aca ("perf sched timehist: Show
-callchains for idle stat") was correct — it used struct rb_root and
-rb_first(). The bug was introduced when sorted_root was converted to
-rb_root_cached without converting the sort insertion path to use
-rb_insert_color_cached().
-
-Use rb_first(&root->rb_root) to match how the tree was populated.
-
-Fixes: cb4c13a5137766c3 ("perf sched: Use cached rbtrees")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Davidlohr Bueso <dave@stgolabs.net>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Acked-by: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 8b1573515c5781..db4ceebab8d8ad 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -2906,7 +2906,8 @@ static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)
- size_t ret = 0;
- FILE *fp = stdout;
- struct callchain_node *chain;
-- struct rb_node *rb_node = rb_first_cached(root);
-+ /* sort() uses rb_insert_color() on rb_root, not rb_root_cached */
-+ struct rb_node *rb_node = rb_first(&root->rb_root);
-
- printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains");
- printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line,
---
-2.53.0
-
+++ /dev/null
-From 818a0ffd8e4cad58cd96571c01ed1f2231622ec3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 4 Jun 2026 12:56:02 -0300
-Subject: perf sched: Fix NULL dereference in latency_runtime_event
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 8cbca8a480e15f6326ce94287570993f27a4b2d5 ]
-
-latency_runtime_event() passes the return value of
-machine__findnew_thread() directly to thread_atoms_search() at line
-1216, before checking for NULL at line 1220. thread_atoms_search()
-calls pid_cmp() which dereferences the thread pointer via
-thread__tid(), causing a NULL pointer dereference if the allocation
-fails.
-
-All other callers of thread_atoms_search() in this file
-(latency_switch_event, latency_wakeup_event,
-latency_migrate_task_event) correctly check for NULL first.
-
-Move the atoms assignment after the NULL check to match the pattern
-used by the other callers.
-
-Fixes: b91fc39f4ad7 ("perf machine: Protect the machine->threads with a rwlock")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 9e9bb19f0bc98b..6df0d1252f197f 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -1223,13 +1223,15 @@ static int latency_runtime_event(struct perf_sched *sched,
- const u32 pid = evsel__intval(evsel, sample, "pid");
- const u64 runtime = evsel__intval(evsel, sample, "runtime");
- struct thread *thread = machine__findnew_thread(machine, -1, pid);
-- struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
-+ struct work_atoms *atoms;
- u64 timestamp = sample->time;
- int cpu = sample->cpu, err = -1;
-
- if (thread == NULL)
- return -1;
-
-+ atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
-+
- /* perf.data is untrusted input — CPU may be absent or corrupted */
- if (cpu >= MAX_CPUS || cpu < 0) {
- pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
---
-2.53.0
-
+++ /dev/null
-From b7d7eb3eded41a994946681cb2fd8536052a9181 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 5 Jun 2026 11:26:28 -0300
-Subject: perf sched: Replace BUG_ON and add NULL checks in replay event
- helpers
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 75eafe4a3a93a0143a20c0cc286bfb9008ac1478 ]
-
-get_new_event() has three issues:
-
-1. The zalloc() result is dereferenced without a NULL check, crashing
- on allocation failure.
-
-2. BUG_ON(!task->atoms) kills the process when realloc() fails.
- Since perf.data is untrusted input, this should be a graceful error.
-
-3. The realloc pattern assigns directly to task->atoms, losing the old
- pointer on failure. task->nr_events is also incremented before the
- realloc, leaving corrupted state on failure.
-
-Fix get_new_event() to:
- - Check the zalloc() result before dereferencing
- - Use a temporary for realloc() to avoid losing the old pointer
- - Increment nr_events only after successful realloc
- - Return NULL instead of calling BUG_ON on failure
-
-Also fix add_sched_event_wakeup() where zalloc() for wait_sem is
-passed to sem_init() without a NULL check.
-
-Update all callers (add_sched_event_run, add_sched_event_wakeup,
-add_sched_event_sleep) to handle NULL returns by returning early.
-The replay may produce incomplete output on OOM but will not crash.
-
-Fixes: ec156764d424 ("perf sched: Import schedbench.c")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Ingo Molnar <mingo@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 28 +++++++++++++++++++++++++---
- 1 file changed, 25 insertions(+), 3 deletions(-)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 0a1a58f33ae651..8b1573515c5781 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -363,14 +363,25 @@ get_new_event(struct task_desc *task, u64 timestamp)
- struct sched_atom *event = zalloc(sizeof(*event));
- unsigned long idx = task->nr_events;
- size_t size;
-+ struct sched_atom **atoms_p;
-+
-+ if (event == NULL) {
-+ pr_err("ERROR: sched: failed to allocate event\n");
-+ return NULL;
-+ }
-
- event->timestamp = timestamp;
- event->nr = idx;
-
-+ size = sizeof(struct sched_atom *) * (task->nr_events + 1);
-+ atoms_p = realloc(task->atoms, size);
-+ if (!atoms_p) {
-+ pr_err("ERROR: sched: failed to grow atoms array\n");
-+ free(event);
-+ return NULL;
-+ }
-+ task->atoms = atoms_p;
- task->nr_events++;
-- size = sizeof(struct sched_atom *) * task->nr_events;
-- task->atoms = realloc(task->atoms, size);
-- BUG_ON(!task->atoms);
-
- task->atoms[idx] = event;
-
-@@ -401,6 +412,8 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task
- }
-
- event = get_new_event(task, timestamp);
-+ if (event == NULL)
-+ return;
-
- event->type = SCHED_EVENT_RUN;
- event->duration = duration;
-@@ -414,6 +427,8 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
- struct sched_atom *event, *wakee_event;
-
- event = get_new_event(task, timestamp);
-+ if (event == NULL)
-+ return;
- event->type = SCHED_EVENT_WAKEUP;
- event->wakee = wakee;
-
-@@ -428,6 +443,10 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
- }
-
- wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
-+ if (!wakee_event->wait_sem) {
-+ pr_err("ERROR: sched: failed to allocate semaphore\n");
-+ return;
-+ }
- sem_init(wakee_event->wait_sem, 0, 0);
- wakee_event->specific_wait = 1;
- event->wait_sem = wakee_event->wait_sem;
-@@ -440,6 +459,9 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *ta
- {
- struct sched_atom *event = get_new_event(task, timestamp);
-
-+ if (event == NULL)
-+ return;
-+
- event->type = SCHED_EVENT_SLEEP;
-
- sched->nr_sleep_events++;
---
-2.53.0
-
+++ /dev/null
-From d30ea1fda9f30ebeaa3443bc478dcbcc522574fa Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 1 Jun 2026 19:53:41 -0300
-Subject: perf sched: Replace BUG_ON on invalid CPU with graceful skip
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 1e2c83f732deb329ebce23e26cbc482f4c4bf194 ]
-
-latency_switch_event(), latency_runtime_event(), and map_switch_event()
-use BUG_ON(cpu >= MAX_CPUS || cpu < 0) to validate the sample CPU.
-When PERF_SAMPLE_CPU is absent from the sample type,
-evsel__parse_sample() initializes sample->cpu to (u32)-1. Casting
-this to int yields -1, which triggers the BUG_ON and aborts perf sched.
-
-The central CPU validation in perf_session__deliver_event() intentionally
-preserves the (u32)-1 sentinel for downstream tools like perf script
-and perf inject, so leaf callbacks must handle it themselves.
-
-Replace the three BUG_ON calls with graceful skips using pr_warning(),
-matching the existing pattern in process_sched_switch_event() and
-process_sched_runtime_event() earlier in the same file. Include the
-file offset for cross-referencing with perf report -D.
-
-Reported-by: sashiko-bot@kernel.org # Running on a local machine
-Reviewed-by: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Stable-dep-of: 8cbca8a480e1 ("perf sched: Fix NULL dereference in latency_runtime_event")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-sched.c | 22 +++++++++++++++++++---
- 1 file changed, 19 insertions(+), 3 deletions(-)
-
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 942fde8a1d52e3..9e9bb19f0bc98b 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -1154,7 +1154,12 @@ static int latency_switch_event(struct perf_sched *sched,
- int cpu = sample->cpu, err = -1;
- s64 delta;
-
-- BUG_ON(cpu >= MAX_CPUS || cpu < 0);
-+ /* perf.data is untrusted input — CPU may be absent or corrupted */
-+ if (cpu >= MAX_CPUS || cpu < 0) {
-+ pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
-+ sample->file_offset, cpu);
-+ return 0;
-+ }
-
- timestamp0 = sched->cpu_last_switched[cpu];
- sched->cpu_last_switched[cpu] = timestamp;
-@@ -1225,7 +1230,13 @@ static int latency_runtime_event(struct perf_sched *sched,
- if (thread == NULL)
- return -1;
-
-- BUG_ON(cpu >= MAX_CPUS || cpu < 0);
-+ /* perf.data is untrusted input — CPU may be absent or corrupted */
-+ if (cpu >= MAX_CPUS || cpu < 0) {
-+ pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
-+ sample->file_offset, cpu);
-+ err = 0;
-+ goto out_put;
-+ }
- if (!atoms) {
- if (thread_atoms_insert(sched, thread))
- goto out_put;
-@@ -1596,7 +1607,12 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel,
- const char *color = PERF_COLOR_NORMAL;
- char stimestamp[32];
-
-- BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0);
-+ /* perf.data is untrusted input — CPU may be absent or corrupted */
-+ if (this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0) {
-+ pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
-+ sample->file_offset, this_cpu.cpu);
-+ return 0;
-+ }
-
- if (this_cpu.cpu > sched->max_cpu.cpu)
- sched->max_cpu = this_cpu;
---
-2.53.0
-
+++ /dev/null
-From 52eeb75748cfc35e88befa4cc321282444177e23 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 8 Jun 2026 08:12:34 -0300
-Subject: perf symbols: Add bounds checks to elf_read_build_id() note iteration
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit acc56d3941fc2997a5a21ea9233a8ac3d87c4f2f ]
-
-elf_read_build_id() iterates ELF notes using pointer arithmetic
-driven by n_namesz and n_descsz from the note headers. Neither
-the note header read nor the subsequent name/desc advances are
-checked against the section boundary. A malformed ELF file with
-oversized note sizes causes out-of-bounds reads past the section
-data buffer.
-
-Add two bounds checks: verify the note header fits within the
-remaining section data, and verify that namesz + descsz (after
-alignment) fits before advancing the pointer.
-
-Fixes: fd7a346ea292074e ("perf symbols: Filename__read_build_id should look at .notes section too")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-elf.c | 18 ++++++++++++++++--
- 1 file changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 4a2fb6e3d4ef38..96bb84a8c5c2ed 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -908,10 +908,24 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
- ptr = data->d_buf;
- while (ptr < (data->d_buf + data->d_size)) {
- GElf_Nhdr *nhdr = ptr;
-- size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
-- descsz = NOTE_ALIGN(nhdr->n_descsz);
-+ size_t namesz, descsz, remaining;
- const char *name;
-
-+ /* ensure the note header fits within the section */
-+ if (ptr + sizeof(*nhdr) > data->d_buf + data->d_size)
-+ break;
-+
-+ namesz = NOTE_ALIGN(nhdr->n_namesz);
-+ descsz = NOTE_ALIGN(nhdr->n_descsz);
-+
-+ /* validate individually to avoid size_t overflow on 32-bit */
-+ remaining = data->d_buf + data->d_size - ptr - sizeof(*nhdr);
-+ if (namesz > remaining || descsz > remaining - namesz) {
-+ pr_warning("%s: oversized note: n_namesz=%u, n_descsz=%u\n",
-+ __func__, nhdr->n_namesz, nhdr->n_descsz);
-+ break;
-+ }
-+
- ptr += sizeof(*nhdr);
- name = ptr;
- ptr += namesz;
---
-2.53.0
-
+++ /dev/null
-From 0e8d1d780638640ede4da8b5d720f2c40fa0ba2e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 10 Jun 2026 16:09:45 -0300
-Subject: perf symbols: Add bounds checks to read_build_id() note iteration in
- minimal build
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 52e582e316c48c53bb3082c29f7862ebc554087e ]
-
-symbol-minimal.c's read_build_id() iterates ELF notes with the same
-pattern as symbol-elf.c's elf_read_build_id(): pointer arithmetic
-driven by n_namesz and n_descsz from 32-bit note header fields,
-without validating that the name and desc fit within the note section
-data. A malformed ELF file with oversized note sizes causes
-out-of-bounds reads past the section data buffer.
-
-Add the same bounds check as the libelf path: validate namesz and
-descsz individually against remaining data before advancing the
-pointer, avoiding size_t overflow on 32-bit.
-
-Fixes: b691f64360ecec49 ("perf symbols: Implement poor man's ELF parser")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-minimal.c | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
-index a81a14769bd101..b95dd77239e835 100644
---- a/tools/perf/util/symbol-minimal.c
-+++ b/tools/perf/util/symbol-minimal.c
-@@ -1,3 +1,4 @@
-+#include "debug.h"
- #include "dso.h"
- #include "symbol.h"
- #include "symsrc.h"
-@@ -45,7 +46,7 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid,
- ptr = note_data;
- while (ptr < (note_data + note_len)) {
- const char *name;
-- size_t namesz, descsz;
-+ size_t namesz, descsz, remaining;
-
- nhdr = ptr;
- if (need_swap) {
-@@ -57,6 +58,14 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid,
- namesz = NOTE_ALIGN(nhdr->n_namesz);
- descsz = NOTE_ALIGN(nhdr->n_descsz);
-
-+ /* validate individually to avoid size_t overflow on 32-bit */
-+ remaining = note_data + note_len - ptr - sizeof(*nhdr);
-+ if (namesz > remaining || descsz > remaining - namesz) {
-+ pr_warning("%s: oversized note: n_namesz=%u, n_descsz=%u\n",
-+ __func__, nhdr->n_namesz, nhdr->n_descsz);
-+ break;
-+ }
-+
- ptr += sizeof(*nhdr);
- name = ptr;
- ptr += namesz;
---
-2.53.0
-
+++ /dev/null
-From 2e8b595348d5a0910489c1ee6e5cf62ff691f1cb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 21:05:15 -0300
-Subject: perf symbols: Bounds-check .gnu_debuglink section data
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 9c74f0aab398cb32ab250401f323c0fdc9a3a496 ]
-
-filename__read_debuglink() copies .gnu_debuglink section data into a
-caller-provided buffer via:
-
- strncpy(debuglink, data->d_buf, size);
-
-where size is PATH_MAX. If the ELF section is smaller than size and
-lacks a null terminator, strncpy reads past data->d_buf into adjacent
-memory. A malformed ELF file can trigger this, potentially causing a
-segfault or leaking heap data.
-
-Additionally, strncpy does not guarantee null termination when the
-source fills the buffer.
-
-Replace with an explicit memcpy bounded by both the output buffer
-size and the actual section data size (data->d_size), followed by
-explicit null termination.
-
-Fixes: e5a1845fc0aeca85 ("perf symbols: Split out util/symbol-elf.c")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-elf.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 0f5f60bc4180bf..83b76e88ed603e 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -1159,7 +1159,14 @@ int filename__read_debuglink(const char *filename, char *debuglink,
- goto out_elf_end;
-
- /* the start of this section is a zero-terminated string */
-- strncpy(debuglink, data->d_buf, size);
-+ if (data->d_size > 0) {
-+ size_t len = min(size - 1, data->d_size);
-+
-+ memcpy(debuglink, data->d_buf, len);
-+ debuglink[len] = '\0';
-+ } else {
-+ debuglink[0] = '\0';
-+ }
-
- err = 0;
-
---
-2.53.0
-
+++ /dev/null
-From aca2e8e0042cae7687e3ebe3129ad75899266c23 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 22:40:20 -0300
-Subject: perf symbols: Bounds-check descsz in sysfs__read_build_id() GNU
- fallback
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 1b4e9fbdeabc549965e70ac0cd8095d57ff6df06 ]
-
-When sysfs__read_build_id() matches NT_GNU_BUILD_ID with the right
-namesz but the name content is not "GNU", it falls back to reading
-descsz bytes into the stack buffer bf[BUFSIZ]:
-
- } else if (read(fd, bf, descsz) != (ssize_t)descsz)
-
-Unlike the else branch which validates namesz + descsz against
-sizeof(bf), this path passes descsz directly to read() without any
-bounds check. A crafted sysfs file with a large n_descsz overflows
-the 8192-byte stack buffer.
-
-Add a descsz > sizeof(bf) check before the read, breaking out of
-the loop on oversized values.
-
-Fixes: e5a1845fc0aeca85 ("perf symbols: Split out util/symbol-elf.c")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-elf.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 83b76e88ed603e..4a2fb6e3d4ef38 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -1059,8 +1059,13 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid)
- err = 0;
- break;
- }
-- } else if (read(fd, bf, descsz) != (ssize_t)descsz)
-- break;
-+ } else {
-+ /* descsz from untrusted file — clamp to buffer */
-+ if (descsz > sizeof(bf))
-+ break;
-+ if (read(fd, bf, descsz) != (ssize_t)descsz)
-+ break;
-+ }
- } else {
- size_t n;
-
---
-2.53.0
-
+++ /dev/null
-From f0252d4dce87893a824cc3d8fcbdaa13a5570cb1 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 10 Jun 2026 19:32:22 -0300
-Subject: perf symbols: Break infinite loop on zero-filled notes in
- sysfs__read_build_id()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 063c647b24f640657d6d9e2e90d620ea3ee19ae6 ]
-
-sysfs__read_build_id() iterates ELF note headers from sysfs files in a
-while(1) loop. If the file contains a zero-filled note header (both
-n_namesz and n_descsz are 0), the code computes n = namesz + descsz = 0
-and calls read(fd, bf, 0). read() with count 0 returns 0, which
-matches the expected (ssize_t)n value, so the error check passes and
-the loop repeats — reading the same zero bytes and spinning forever.
-
-This can happen with corrupted or zero-padded sysfs pseudo-files.
-
-Add a check for n == 0 before the read, since no valid ELF note has
-both name and description of zero length.
-
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Fixes: f1617b40596cb341 ("perf symbols: Record the build_ids of kernel modules too")
-Reviewed-by: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-elf.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 96bb84a8c5c2ed..1729efd11ac5cf 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -1091,6 +1091,9 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid)
- } else {
- n = namesz + descsz;
- }
-+ /* no valid note has both namesz and descsz zero */
-+ if (n == 0)
-+ break;
- if (read(fd, bf, n) != (ssize_t)n)
- break;
- }
---
-2.53.0
-
+++ /dev/null
-From add92f3070796b2154eef6d8e2abdfce2b7e7359 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 21:04:50 -0300
-Subject: perf symbols: Fix signed overflow in sysfs__read_build_id() size
- check
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 6eaa8ee3e2abe5112e80e94c27196bb175689469 ]
-
-sysfs__read_build_id() reads ELF note headers from sysfs files. The
-note's namesz and descsz fields are used to compute the skip size:
-
- int n = namesz + descsz;
- if (n > (int)sizeof(bf))
-
-Both namesz and descsz are size_t from NOTE_ALIGN() of 32-bit note
-header fields. Their sum can exceed INT_MAX, overflowing the signed
-int n to a negative value. The check n > sizeof(bf) then evaluates
-false (negative < positive in signed comparison), and read(fd, bf, n)
-reinterprets the negative n as a huge size_t count — the kernel writes
-up to MAX_RW_COUNT bytes into the 8192-byte stack buffer.
-
-In practice the overflow is bounded by the sysfs file's actual size,
-so a real sysfs notes file won't trigger it organically. But crafted
-input (e.g. via a mounted debugfs/sysfs image) could.
-
-Fix by validating namesz and descsz individually against the buffer
-size before summing, and change n to size_t to avoid the signed
-overflow entirely.
-
-Fixes: f1617b40596cb341 ("perf symbols: Record the build_ids of kernel modules too")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Namhyung Kim <namhyung@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/symbol-elf.c | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 95e99c332d7e3f..0f5f60bc4180bf 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -1062,14 +1062,17 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid)
- } else if (read(fd, bf, descsz) != (ssize_t)descsz)
- break;
- } else {
-- int n = namesz + descsz;
-+ size_t n;
-
-- if (n > (int)sizeof(bf)) {
-+ /* int sum of namesz+descsz can overflow negative, bypassing size check */
-+ if (namesz > sizeof(bf) || descsz > sizeof(bf) - namesz) {
- n = sizeof(bf);
- pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n",
- __func__, filename, nhdr.n_namesz, nhdr.n_descsz);
-+ } else {
-+ n = namesz + descsz;
- }
-- if (read(fd, bf, n) != n)
-+ if (read(fd, bf, n) != (ssize_t)n)
- break;
- }
- }
---
-2.53.0
-
+++ /dev/null
-From 75449cc73298968a3b3696c9615af953121838ae Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 4 Jun 2026 18:14:23 -0300
-Subject: perf tools: Add bounds check to cpu__get_node()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 1e7921d7227de5da0dfc167943092c823ec7e49b ]
-
-cpu__get_node() accesses cpunode_map[cpu.cpu] without checking against
-max_cpu_num, the allocation size of cpunode_map. Callers such as
-builtin-kmem.c:evsel__process_alloc_event() pass sample->cpu from
-perf.data events, which may exceed the host's CPU count when analyzing
-cross-machine recordings.
-
-Add a bounds check against max_cpu_num before indexing, returning -1
-for out-of-range values. This is a central fix that protects all
-callers.
-
-Fixes: 86895b480a2f ("perf stat: Add --per-node agregation support")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cpumap.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
-index 0e090e8bc33491..75d9f5d6d185d1 100644
---- a/tools/perf/util/cpumap.c
-+++ b/tools/perf/util/cpumap.c
-@@ -498,6 +498,10 @@ int cpu__get_node(struct perf_cpu cpu)
- return -1;
- }
-
-+ /* cpunode_map allocated for max_cpu_num entries; input may be untrusted */
-+ if (cpu.cpu < 0 || cpu.cpu >= max_cpu_num.cpu)
-+ return -1;
-+
- return cpunode_map[cpu.cpu];
- }
-
---
-2.53.0
-
+++ /dev/null
-From e70f080e4a12e41419addb6cb097cd2b5974c87b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 20:37:52 -0300
-Subject: perf tools: Fix get_max_num() size_t underflow on empty sysfs file
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 0a012113bb3a44482c163f16f4db03ccaa37a339 ]
-
-get_max_num() reads a sysfs file (cpu/possible, cpu/present, or
-node/possible) and scans backward from the end to find the last
-number. If the file is empty, filename__read_str() returns num == 0.
-The loop `while (--num)` decrements the size_t from 0 to SIZE_MAX,
-reading backward across the heap until a comma or hyphen is found
-or unmapped memory is hit.
-
-Add an early return for empty files before the backward scan.
-
-Fixes: 7780c25bae59fd04 ("perf tools: Allow ability to map cpus to nodes easily")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Don Zickus <dzickus@redhat.com>
-Cc: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cpumap.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
-index 75d9f5d6d185d1..de4a710e242146 100644
---- a/tools/perf/util/cpumap.c
-+++ b/tools/perf/util/cpumap.c
-@@ -378,6 +378,12 @@ static int get_max_num(char *path, int *max)
-
- buf[num] = '\0';
-
-+ /* empty file — nothing to parse */
-+ if (num == 0) {
-+ err = -1;
-+ goto out;
-+ }
-+
- /* start on the right, to find highest node num */
- while (--num) {
- if ((buf[num] == ',') || (buf[num] == '-')) {
---
-2.53.0
-
+++ /dev/null
-From 394597a7925a95e0a6a0096b50e67b908afe33f7 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 7 Jun 2026 22:37:55 -0300
-Subject: perf tools: Fix thread__set_comm_from_proc() on empty comm file
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 31d596054550f793508abe7dd593853ece47d428 ]
-
-thread__set_comm_from_proc() calls procfs__read_str() then strips
-the trailing newline via comm[sz - 1] = '\0'. procfs__read_str()
-allocates the buffer before reading, so on an empty /proc/pid/comm
-(reachable during late exit teardown) it returns success with sz = 0
-and an unterminated heap buffer.
-
-The sz - 1 underflow was the original sashiko finding: it writes a
-null byte before the allocation. But even with a sz > 0 guard on
-the newline strip, the unterminated buffer would still be passed to
-thread__set_comm() which calls strlen() — an unbounded heap read.
-
-Fix by treating sz == 0 as failure: free the buffer and return -1.
-This is consistent with pmu.c's perf_pmu__parse_scale/unit which
-already treat len == 0 from filename__read_str as an error.
-
-Fixes: 2f3027ac28bf6bc3 ("perf thread: Introduce method to set comm from /proc/pid/self")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/thread.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
-index 61e9f449c72581..ec0ccc310cdad8 100644
---- a/tools/perf/util/thread.c
-+++ b/tools/perf/util/thread.c
-@@ -273,6 +273,11 @@ int thread__set_comm_from_proc(struct thread *thread)
- if (!(snprintf(path, sizeof(path), "%d/task/%d/comm",
- thread__pid(thread), thread__tid(thread)) >= (int)sizeof(path)) &&
- procfs__read_str(path, &comm, &sz) == 0) {
-+ /* sz==0: read got nothing, e.g. race during exit teardown */
-+ if (sz == 0) {
-+ free(comm);
-+ return -1;
-+ }
- comm[sz - 1] = '\0';
- err = thread__set_comm(thread, comm, 0);
- }
---
-2.53.0
-
+++ /dev/null
-From 9990eeee66cad1541a119a76b837f1498421f0a6 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 4 Jun 2026 12:55:06 -0300
-Subject: perf tools: Guard test_bit from out-of-bounds sample CPU
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit a5498ccf8079fc91c938f122ff9697b0c526b2fd ]
-
-When PERF_SAMPLE_CPU is absent from a perf.data file, sample->cpu is
-initialized to (u32)-1 by evsel__parse_sample(). Five call sites pass
-this value directly to test_bit(sample->cpu, cpu_bitmap), reading
-massively out of bounds past the DECLARE_BITMAP(..., MAX_NR_CPUS)
-allocation of 4096 bits.
-
-Add a sample->cpu >= MAX_NR_CPUS guard before each test_bit() call,
-matching the existing safe pattern in builtin-kwork.c. This catches
-both the (u32)-1 sentinel and any corrupted CPU value exceeding the
-bitmap size.
-
-Fixes: 5d67be97f890 ("perf report/annotate/script: Add option to specify a CPU range")
-Cc: Anton Blanchard <anton@samba.org>
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/builtin-annotate.c | 3 ++-
- tools/perf/builtin-diff.c | 3 ++-
- tools/perf/builtin-report.c | 3 ++-
- tools/perf/builtin-sched.c | 6 ++++--
- 4 files changed, 10 insertions(+), 5 deletions(-)
-
-diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
-index 0f1e5787b4edac..e572043be2dbb8 100644
---- a/tools/perf/builtin-annotate.c
-+++ b/tools/perf/builtin-annotate.c
-@@ -287,7 +287,8 @@ static int process_sample_event(struct perf_tool *tool,
- goto out_put;
- }
-
-- if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
-+ if (ann->cpu_list && (sample->cpu >= MAX_NR_CPUS ||
-+ !test_bit(sample->cpu, ann->cpu_bitmap)))
- goto out_put;
-
- if (!al.filtered &&
-diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
-index 57d300d8e5700c..41f557fcc5567f 100644
---- a/tools/perf/builtin-diff.c
-+++ b/tools/perf/builtin-diff.c
-@@ -417,7 +417,8 @@ static int diff__process_sample_event(struct perf_tool *tool,
- goto out;
- }
-
-- if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
-+ if (cpu_list && (sample->cpu >= MAX_NR_CPUS ||
-+ !test_bit(sample->cpu, cpu_bitmap))) {
- ret = 0;
- goto out;
- }
-diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
-index 54b06db597862f..eed8a2621d01f7 100644
---- a/tools/perf/builtin-report.c
-+++ b/tools/perf/builtin-report.c
-@@ -298,7 +298,8 @@ static int process_sample_event(struct perf_tool *tool,
- if (symbol_conf.hide_unresolved && al.sym == NULL)
- goto out_put;
-
-- if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
-+ if (rep->cpu_list && (sample->cpu >= MAX_NR_CPUS ||
-+ !test_bit(sample->cpu, rep->cpu_bitmap)))
- goto out_put;
-
- if (sort__mode == SORT_MODE__BRANCH) {
-diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
-index 1a22314094e6ad..942fde8a1d52e3 100644
---- a/tools/perf/builtin-sched.c
-+++ b/tools/perf/builtin-sched.c
-@@ -2085,7 +2085,8 @@ static void timehist_print_sample(struct perf_sched *sched,
- char nstr[30];
- u64 wait_time;
-
-- if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
-+ if (cpu_list && (sample->cpu >= MAX_NR_CPUS ||
-+ !test_bit(sample->cpu, cpu_bitmap)))
- return;
-
- timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
-@@ -2671,7 +2672,8 @@ static int timehist_sched_change_event(struct perf_tool *tool,
- }
-
- if (!sched->idle_hist || thread__tid(thread) == 0) {
-- if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
-+ if (!cpu_list || (sample->cpu < MAX_NR_CPUS &&
-+ test_bit(sample->cpu, cpu_bitmap)))
- timehist_update_runtime_stats(tr, t, tprev);
-
- if (sched->idle_hist) {
---
-2.53.0
-
+++ /dev/null
-From 4704847c5f05a24205fde0902af7ad5b6efee5bd Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 20:57:49 -0300
-Subject: perf tools: Use perf_env__get_cpu_topology() in machine__resolve()
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 5484b43a0ec8231c36fba6ead654cb72dbba8b8f ]
-
-machine__resolve() accesses env->cpu[al->cpu].socket_id after checking
-al->cpu >= 0 and env->cpu != NULL, but without validating al->cpu
-against env->nr_cpus_avail. Since al->cpu comes from the untrusted
-perf.data sample, a crafted file with a large CPU index causes an
-out-of-bounds heap read.
-
-Use perf_env__get_cpu_topology() which validates both NULL and bounds.
-Also bounds-check al->cpu before the cast to struct perf_cpu (int16_t):
-without this, values like 65536 silently truncate to 0, bypassing the
-accessor's internal check and returning CPU 0's topology.
-
-Fixes: 0c4c4debb0adda4c ("perf tools: Add processor socket info to hist_entry and addr_location")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Kan Liang <kan.liang@intel.com>
-Cc: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/event.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
-index 68f45e9e63b6e4..b118766c16e657 100644
---- a/tools/perf/util/event.c
-+++ b/tools/perf/util/event.c
-@@ -12,6 +12,7 @@
- #include <linux/zalloc.h>
- #include "cpumap.h"
- #include "dso.h"
-+#include "env.h"
- #include "event.h"
- #include "debug.h"
- #include "hist.h"
-@@ -743,8 +744,18 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
- if (al->cpu >= 0) {
- struct perf_env *env = machine->env;
-
-- if (env && env->cpu)
-- al->socket = env->cpu[al->cpu].socket_id;
-+ /*
-+ * Bounds-check al->cpu (s32) before casting to struct perf_cpu
-+ * (int16_t): without this, e.g. 65536 truncates to 0 and silently
-+ * returns CPU 0's topology. Can go once perf_cpu.cpu is widened.
-+ */
-+ if (env && al->cpu < env->nr_cpus_avail) {
-+ struct cpu_topology_map *topo;
-+
-+ topo = perf_env__get_cpu_topology(env, (struct perf_cpu){ al->cpu });
-+ if (topo)
-+ al->socket = topo->socket_id;
-+ }
- }
-
- if (al->map) {
---
-2.53.0
-
+++ /dev/null
-From e3d42442ed88cbd352962b1cfb068577d420637e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 6 Jun 2026 20:43:52 -0300
-Subject: perf tools: Use scnprintf() in cpu_map__snprint() to prevent overflow
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 7953a3a9b8e02e98c6e6958f291d0ae22393e46a ]
-
-cpu_map__snprint() accumulates snprintf() return values in ret.
-snprintf() returns the number of characters that *would have been
-written* on truncation, not the actual count. When a fragmented CPU
-list exceeds the buffer, ret grows past size, causing `size - ret` to
-underflow (both are size_t), and subsequent snprintf() calls write
-past the end of the caller's stack buffer.
-
-Switch to scnprintf() which returns the actual number of characters
-written, making ret accumulation safe by construction.
-
-Fixes: a24020e6b7cf6eb8 ("perf tools: Change cpu_map__fprintf output")
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Reviewed-by: Ian Rogers <irogers@google.com>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Ian Rogers <irogers@google.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/cpumap.c | 18 +++++++++---------
- 1 file changed, 9 insertions(+), 9 deletions(-)
-
-diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
-index de4a710e242146..c5126cdbd7dd70 100644
---- a/tools/perf/util/cpumap.c
-+++ b/tools/perf/util/cpumap.c
-@@ -601,21 +601,21 @@ size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size)
- if (start == -1) {
- start = i;
- if (last) {
-- ret += snprintf(buf + ret, size - ret,
-- "%s%d", COMMA,
-- perf_cpu_map__cpu(map, i).cpu);
-+ ret += scnprintf(buf + ret, size - ret,
-+ "%s%d", COMMA,
-+ perf_cpu_map__cpu(map, i).cpu);
- }
- } else if (((i - start) != (cpu.cpu - perf_cpu_map__cpu(map, start).cpu)) || last) {
- int end = i - 1;
-
- if (start == end) {
-- ret += snprintf(buf + ret, size - ret,
-- "%s%d", COMMA,
-- perf_cpu_map__cpu(map, start).cpu);
-+ ret += scnprintf(buf + ret, size - ret,
-+ "%s%d", COMMA,
-+ perf_cpu_map__cpu(map, start).cpu);
- } else {
-- ret += snprintf(buf + ret, size - ret,
-- "%s%d-%d", COMMA,
-- perf_cpu_map__cpu(map, start).cpu, perf_cpu_map__cpu(map, end).cpu);
-+ ret += scnprintf(buf + ret, size - ret,
-+ "%s%d-%d", COMMA,
-+ perf_cpu_map__cpu(map, start).cpu, perf_cpu_map__cpu(map, end).cpu);
- }
- first = false;
- start = i;
---
-2.53.0
-
+++ /dev/null
-From be21a8a08626870984d3c5ed3fe1fb98d658dbb9 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 10 Jun 2026 20:34:38 -0300
-Subject: perf tools: Use snprintf() for root_dir path construction
-
-From: Arnaldo Carvalho de Melo <acme@redhat.com>
-
-[ Upstream commit 7b0df6f4d498b1608afccfd6dffb264e6da91693 ]
-
-get_kernel_version() in machine.c and dso__load_guest_kernel_sym() in
-symbol.c use sprintf() to construct paths by prepending root_dir to
-"/proc/version" and "/proc/kallsyms" respectively. Both write into
-PATH_MAX stack buffers, but root_dir comes from --guestmount or KVM
-configuration and is not length-checked. A root_dir at or near
-PATH_MAX causes a stack buffer overflow.
-
-Switch to snprintf() with sizeof(path) to prevent overflow.
-
-Reported-by: sashiko-bot <sashiko-bot@kernel.org>
-Fixes: a1645ce12adb6c9c ("perf: 'perf kvm' tool for monitoring guest performance from host")
-Cc: Zhang Yanmin <yanmin_zhang@linux.intel.com>
-Assisted-by: Claude:claude-opus-4.6
-Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- tools/perf/util/machine.c | 2 +-
- tools/perf/util/symbol.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
-index e2a6facd1c4e2a..2f5a5245483ede 100644
---- a/tools/perf/util/machine.c
-+++ b/tools/perf/util/machine.c
-@@ -1495,7 +1495,7 @@ static char *get_kernel_version(const char *root_dir)
- char *name, *tmp;
- const char *prefix = "Linux version ";
-
-- sprintf(version, "%s/proc/version", root_dir);
-+ snprintf(version, sizeof(version), "%s/proc/version", root_dir);
- file = fopen(version, "r");
- if (!file)
- return NULL;
-diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
-index 18556b7a765630..8618e4175e20fd 100644
---- a/tools/perf/util/symbol.c
-+++ b/tools/perf/util/symbol.c
-@@ -2215,7 +2215,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)
- if (!kallsyms_filename)
- return -1;
- } else {
-- sprintf(path, "%s/proc/kallsyms", machine->root_dir);
-+ snprintf(path, sizeof(path), "%s/proc/kallsyms", machine->root_dir);
- kallsyms_filename = path;
- }
-
---
-2.53.0
-
pci-check-rom-header-and-data-structure-addr-before-.patch
x86-platform-olpc-xo15-drop-wakeup-source-on-driver-.patch
platform-x86-xo15-ebook-fix-wakeup-source-and-gpe-ha.patch
-perf-sched-add-missing-mmap2-handler-in-timehist.patch
pci-loongson-do-not-ignore-downstream-devices-on-ext.patch
bus-mhi-ep-fix-potential-deadlock-in-mhi_ep_reset_wo.patch
phy-phy-can-transceiver-check-driver-match-and-drive.patch
-perf-pmu-skip-test-on-arm64-when-slots-is-zero.patch
mailbox-mtk-adsp-fix-uaf-during-device-teardown.patch
staging-most-video-avoid-double-free-on-video-regist.patch
usb-host-max3421-fix-shift-out-of-bounds-in-max3421_.patch
usb-host-max3421-reject-hub-port-requests-for-non-ex.patch
char-tlclk-fix-use-after-free-in-tlclk_cleanup.patch
-perf-header-sanity-check-header_event_desc-attr.size.patch
iio-light-si1133-reset-counter-to-prevent-race-condi.patch
iio-light-si1133-prevent-race-condition-on-timeout.patch
iio-magnetometer-ak8975-fix-potential-kernel-stack-m.patch
drm-amd-display-add-missing-kdoc-for-allm-parameters.patch
dmaengine-imx-sdma-refine-spba-bus-searching-in-prob.patch
perf-fix-off-by-one-stack-buffer-overflow-in-kallsym.patch
-perf-tools-guard-test_bit-from-out-of-bounds-sample-.patch
-perf-sched-replace-bug_on-on-invalid-cpu-with-gracef.patch
-perf-sched-fix-null-dereference-in-latency_runtime_e.patch
-perf-tools-add-bounds-check-to-cpu__get_node.patch
-perf-mmap-guard-cpu__get_node-return-in-aio_bind.patch
-perf-c2c-bounds-check-cpu-and-node-ids-before-bitmap.patch
-perf-sched-clean-up-idle_threads-entry-on-init-failu.patch
-perf-sched-replace-bug_on-and-add-null-checks-in-rep.patch
-perf-mmap-fix-null-deref-in-aio-cleanup-on-alloc-fai.patch
-perf-c2c-fix-use-after-free-in-he__get_c2c_hists-err.patch
dmaengine-qcom-gpi-set-dma_private-capability.patch
dmaengine-fix-possible-use-after-free.patch
clk-qcom-a53-corrected-frequency-multiplier-for-1152.patch
pci-mediatek-fix-operator-precedence-in-pcie_fts_num.patch
pci-meson-propagate-devm_add_action_or_reset-failure.patch
fs-ntfs3-resize-log-one_page_buf-when-adopting-on-di.patch
-perf-tools-fix-get_max_num-size_t-underflow-on-empty.patch
-perf-tools-use-scnprintf-in-cpu_map__snprint-to-prev.patch
-perf-tools-use-perf_env__get_cpu_topology-in-machine.patch
pci-rcar-host-remove-unused-list_head-res.patch
-perf-sched-fix-idle-hist-callchain-display-using-wro.patch
-perf-bpf-use-scnprintf-in-snprintf_hex-and-synthesiz.patch
-perf-hists-fix-snprintf-in-hists__scnprintf_title-ui.patch
xprtrdma-check-frwr_wp_create-during-connect.patch
xprtrdma-document-and-assert-reply-handler-invariant.patch
xprtrdma-resize-reply-buffers-before-reposting-recei.patch
xprtrdma-sanitize-the-reply-credit-grant-after-parsi.patch
xprtrdma-repost-receive-buffers-for-malformed-replie.patch
xprtrdma-return-sendctx-slot-after-send-preparation-.patch
-perf-cs-etm-fix-incorrect-or-missing-decoder-for-raw.patch
-perf-cs-etm-create-decoders-after-both-aux-and-hw_id.patch
-perf-cs-etm-queue-context-packets-for-frontend.patch
-perf-pmu-fix-pmu_id-heap-underwrite-on-empty-identif.patch
-perf-pmu-fix-perf_pmu__parse_scale-unit-oob-access-o.patch
tools-lib-api-fix-missing-null-termination-in-filena.patch
-perf-symbols-fix-signed-overflow-in-sysfs__read_buil.patch
-perf-symbols-bounds-check-.gnu_debuglink-section-dat.patch
-perf-intel-pt-fix-snprintf-size-tracking-bug-in-insn.patch
-perf-tools-fix-thread__set_comm_from_proc-on-empty-c.patch
-perf-symbols-bounds-check-descsz-in-sysfs__read_buil.patch
tools-lib-api-fix-filename__write_int-writing-uninit.patch
tools-lib-api-fix-mount_overload-snprintf-truncation.patch
-perf-bpf-add-null-check-for-btf__type_by_id-in-synth.patch
-perf-symbols-add-bounds-checks-to-elf_read_build_id-.patch
-perf-symbols-add-bounds-checks-to-read_build_id-note.patch
pci-mediatek-fix-possible-truncation-in-mtk_pcie_par.patch
pci-mediatek-use-actual-physical-address-instead-of-.patch
revert-pci-msi-unmap-msi-x-region-on-error.patch
i3c-master-prevent-reuse-of-dynamic-address-on-devic.patch
apparmor-fix-label-can-not-be-immediately-before-a-d.patch
sparc-led-avoid-trimming-a-newline-from-empty-writes.patch
-perf-symbols-break-infinite-loop-on-zero-filled-note.patch
-perf-tools-use-snprintf-for-root_dir-path-constructi.patch
-perf-bpf-validate-func_info_rec_size-and-sub_id-in-s.patch
-perf-bpf-bounds-check-array-offsets-in-bpil_offs_to_.patch
gpio-mlxbf3-fail-probe-if-gpiochip-registration-fail.patch
spi-dw-fix-wrong-baudr-setting-after-resume.patch
xfrm-use-the-xfrm_gro-to-indicate-a-gro-call-on-inpu.patch
xfrm-support-crypto-offload-for-inbound-ipv6-esp-pac.patch
xfrm-annotate-data-races-around-xfrm_policy_count-an.patch
xfrm-validate-selector-family-and-prefixlen-during-m.patch
-perf-machine-use-snprintf-for-guestmount-path-constr.patch
-perf-cs-etm-validate-num_cpu-before-metadata-allocat.patch
-perf-cs-etm-require-full-global-header-in-auxtrace_i.patch
asoc-tlv320aic3x-restrict-clkdiv-bypass-q-values-in-.patch
drm-amdkfd-avoid-double-unpin-of-doorbell-mmio-bos-o.patch
drm-amdkfd-fix-list_del-corruption-in-kfd_criu_resum.patch