From b97c53576866d3ba3fb4d9694a0fca7a0ef925ac Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 21 Jul 2026 16:52:53 -0700 Subject: [PATCH] perf synthetic-events: Fix bounds, stale state, and misc flags in kernel module synthesis Clamp long DSO names to mmap/mmap2 filename boundaries accounting for sample ID headers to prevent buffer overruns in perf_event__synthesize_modules_maps_cb(). Explicitly clear misc flags and union padding to prevent stale Build-ID state from leaking between module synthesis events, and cast event buffer pointers to avoid _FORTIFY_SOURCE array bounds aborts when zeroing padding trailers. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Ian Rogers Signed-off-by: Namhyung Kim --- tools/perf/util/synthetic-events.c | 70 +++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index 05075840707c..5bbf024ad606 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -764,6 +764,7 @@ struct perf_event__synthesize_modules_maps_cb_args { perf_event__handler_t process; struct machine *machine; union perf_event *event; + u16 misc; }; static int perf_event__synthesize_modules_maps_cb(struct map *map, void *data) @@ -771,49 +772,78 @@ static int perf_event__synthesize_modules_maps_cb(struct map *map, void *data) struct perf_event__synthesize_modules_maps_cb_args *args = data; union perf_event *event = args->event; struct dso *dso; - size_t size; + size_t size, aligned_size; + int rc = 0; if (!__map__is_kmodule(map)) return 0; dso = map__dso(map); if (!symbol_conf.no_buildid_mmap2) { - size = PERF_ALIGN(dso__long_name_len(dso) + 1, sizeof(u64)); + const char *long_name = dso__long_name(dso); + + size = strlen(long_name); + if (size >= sizeof(event->mmap2.filename) - args->machine->id_hdr_size) + size = sizeof(event->mmap2.filename) - args->machine->id_hdr_size - 1; + + strlcpy(event->mmap2.filename, long_name, + sizeof(event->mmap2.filename) - args->machine->id_hdr_size); + + aligned_size = PERF_ALIGN(size + 1, sizeof(u64)); event->mmap2.header.type = PERF_RECORD_MMAP2; - event->mmap2.header.size = (sizeof(event->mmap2) - - (sizeof(event->mmap2.filename) - size)); - memset(event->mmap2.filename + size, 0, args->machine->id_hdr_size); + event->mmap2.header.misc = args->misc; + event->mmap2.header.size = + offsetof(struct perf_record_mmap2, filename) + + aligned_size; + + /* Zero the padding and ID header trailer safely! */ + memset((char *)event + offsetof(struct perf_record_mmap2, filename) + size, 0, + (aligned_size - size) + args->machine->id_hdr_size); + event->mmap2.header.size += args->machine->id_hdr_size; event->mmap2.start = map__start(map); event->mmap2.len = map__size(map); event->mmap2.pid = args->machine->pid; - memcpy(event->mmap2.filename, dso__long_name(dso), dso__long_name_len(dso) + 1); - - /* Clear stale build ID from previous module iteration */ + /* Clear stale build ID and entire union from previous module iteration */ event->mmap2.header.misc &= ~PERF_RECORD_MISC_MMAP_BUILD_ID; memset(event->mmap2.build_id, 0, sizeof(event->mmap2.build_id)); event->mmap2.build_id_size = 0; + event->mmap2.__reserved_1 = 0; + event->mmap2.__reserved_2 = 0; perf_record_mmap2__read_build_id(&event->mmap2, args->machine, false); } else { - size = PERF_ALIGN(dso__long_name_len(dso) + 1, sizeof(u64)); + const char *long_name = dso__long_name(dso); + + size = strlen(long_name); + if (size >= sizeof(event->mmap.filename) - args->machine->id_hdr_size) + size = sizeof(event->mmap.filename) - args->machine->id_hdr_size - 1; + + strlcpy(event->mmap.filename, long_name, + sizeof(event->mmap.filename) - args->machine->id_hdr_size); + + aligned_size = PERF_ALIGN(size + 1, sizeof(u64)); event->mmap.header.type = PERF_RECORD_MMAP; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, args->machine->id_hdr_size); + event->mmap.header.misc = args->misc; + event->mmap.header.size = + offsetof(struct perf_record_mmap, filename) + + aligned_size; + + /* Zero the padding and ID header trailer safely! */ + memset((char *)event + offsetof(struct perf_record_mmap, filename) + size, 0, + (aligned_size - size) + args->machine->id_hdr_size); + event->mmap.header.size += args->machine->id_hdr_size; event->mmap.start = map__start(map); event->mmap.len = map__size(map); event->mmap.pid = args->machine->pid; - - memcpy(event->mmap.filename, dso__long_name(dso), dso__long_name_len(dso) + 1); } if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0) - return -1; + rc = -1; - return 0; + return rc; } int perf_event__synthesize_modules(const struct perf_tool *tool, perf_event__handler_t process, @@ -838,13 +868,13 @@ int perf_event__synthesize_modules(const struct perf_tool *tool, perf_event__han } /* - * kernel uses 0 for user space maps, see kernel/perf_event.c - * __perf_event_mmap + * Just like the kernel, see perf_misc_flags() in + * kernel/events/core.c */ if (machine__is_host(machine)) - args.event->header.misc = PERF_RECORD_MISC_KERNEL; + args.misc = PERF_RECORD_MISC_KERNEL; else - args.event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; + args.misc = PERF_RECORD_MISC_GUEST_KERNEL; rc = maps__for_each_map(maps, perf_event__synthesize_modules_maps_cb, &args);