summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2026-09-29 15:23:32 -0700
committerPeter Zijlstra <peterz@infradead.org>2026-10-01 14:02:06 +0200
commitb9d1fdc6f4ac1b6e49f9deafaf137da1407d9af1 (patch)
tree3136fb2d281dcbcbd878310c6fee5644ac283526 /arch
parentffb684f2aa141eeb0caa6308422e7e05d1ded7c4 (diff)
downloadlinux-stable-b9d1fdc6f4ac1b6e49f9deafaf137da1407d9af1.tar.gz
linux-stable-b9d1fdc6f4ac1b6e49f9deafaf137da1407d9af1.zip
perf: Replace perf_event_header__init_id with full header init
perf_iterate_sb() invokes its callback for each matching perf_event on the CPU and task context, passing a shared caller-allocated event structure. perf_event_header__init_id() mutated header->size in place by adding event->id_header_size, requiring sideband output callbacks to save and restore header fields across iterations. Three sideband callbacks failed to save and restore header.size around perf_event_header__init_id(): - perf_event_ksymbol_output() - perf_event_bpf_output() - perf_event_text_poke_output() When multiple events with attr.ksymbol, attr.bpf_event, or attr.text_poke and sample_id_all are active on the same CPU, each subsequent event receives a record whose header.size is inflated by all preceding events' id_header_size values while only a single id_sample is written, leaving uninitialized ring-buffer bytes at the end of the record and causing userspace perf to fail with -EFAULT ("Bad address") when parsing the sample_id trailer. Similarly, perf_event_mmap_output() set PERF_RECORD_MISC_MMAP_BUILD_ID in mmap_event->event_id.header.misc when event->attr.build_id was enabled, but only saved and restored header.size and header.type. If an event with attr.build_id was followed by an event with attr.mmap2 and !attr.build_id, the second event received PERF_RECORD_MISC_MMAP_BUILD_ID in header.misc while its payload contained maj/min/ino/ino_generation instead of a build ID. Rather than splitting header initialization between callers and output callbacks and saving/restoring mutated header fields, replace perf_event_header__init_id() with perf_event_header__init(), which initializes header->type, header->misc, and header->size alongside the sample_id fields on each invocation. Fixes: 76193a94522f ("perf, bpf: Introduce PERF_RECORD_KSYMBOL") Fixes: 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT") Fixes: e17d43b93e54 ("perf: Add perf text poke event") Fixes: 88a16a130933 ("perf: Add build id data in mmap2 event") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers <irogers@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260929222332.973435-1-irogers@google.com Cc: stable@vger.kernel.org
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/perf/imc-pmu.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c
index f401181d8..a9f846499 100644
--- a/arch/powerpc/perf/imc-pmu.c
+++ b/arch/powerpc/perf/imc-pmu.c
@@ -1275,6 +1275,8 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
struct perf_event_header *header,
struct perf_event *event)
{
+ u16 misc = 0;
+
/* Sanity checks for a valid record */
if (be64_to_cpu(READ_ONCE(mem->tb1)) > *prev_tb)
*prev_tb = be64_to_cpu(READ_ONCE(mem->tb1));
@@ -1289,23 +1291,19 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
data->ip = be64_to_cpu(READ_ONCE(mem->ip));
data->period = event->hw.last_period;
- header->type = PERF_RECORD_SAMPLE;
- header->size = sizeof(*header) + event->header_size;
- header->misc = 0;
-
if (cpu_has_feature(CPU_FTR_ARCH_31)) {
switch (IMC_TRACE_RECORD_VAL_HVPR(be64_to_cpu(READ_ONCE(mem->val)))) {
case 0:/* when MSR HV and PR not set in the trace-record */
- header->misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+ misc |= PERF_RECORD_MISC_GUEST_KERNEL;
break;
case 1: /* MSR HV is 0 and PR is 1 */
- header->misc |= PERF_RECORD_MISC_GUEST_USER;
+ misc |= PERF_RECORD_MISC_GUEST_USER;
break;
case 2: /* MSR HV is 1 and PR is 0 */
- header->misc |= PERF_RECORD_MISC_KERNEL;
+ misc |= PERF_RECORD_MISC_KERNEL;
break;
case 3: /* MSR HV is 1 and PR is 1 */
- header->misc |= PERF_RECORD_MISC_USER;
+ misc |= PERF_RECORD_MISC_USER;
break;
default:
pr_info("IMC: Unable to set the flag based on MSR bits\n");
@@ -1313,11 +1311,14 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
}
} else {
if (is_kernel_addr(data->ip))
- header->misc |= PERF_RECORD_MISC_KERNEL;
+ misc |= PERF_RECORD_MISC_KERNEL;
else
- header->misc |= PERF_RECORD_MISC_USER;
+ misc |= PERF_RECORD_MISC_USER;
}
- perf_event_header__init_id(header, data, event);
+ perf_event_header__init(header, data,
+ PERF_RECORD_SAMPLE, misc,
+ sizeof(*header) + event->header_size,
+ event);
return 0;
}