From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Namhyung Kim <namhyung@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
James Clark <james.clark@linaro.org>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Kan Liang <kan.liang@linux.intel.com>,
Clark Williams <williams@redhat.com>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH 00/28] perf: Harden perf.data parsing against crafted/corrupted files
Date: Sun, 10 May 2026 00:33:51 -0300 [thread overview]
Message-ID: <20260510033424.255812-1-acme@kernel.org> (raw)
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Hi,
Here is a series experimenting with AI assistance, I did several
experiments that resulted in improvements to sashiko: a response cache,
support for IPv6, ways to better communicate agents, etc.
Please take a look, I took more time than I expected to submit
this, and I'm not sure it is in the right shape, but at some point we
need to just submit to get things going.
- Arnaldo
AI-assisted development notice
==============================
This series was developed with AI assistance (Claude, tagged with
Assisted-by) and reviewed iteratively by sashiko, an AI code reviewer
(tagged with Reported-by for issues it found). This is a first
attempt at using AI tools to help improve the perf tools from a
maintainer's perspective, and the workflow is still being refined.
The human (Arnaldo) read every diff, verified every fix, ran perf
test at multiple points in the series, and built with both gcc and
clang. Every design decision, architectural choice, and commit
message was reviewed and approved by the maintainer. The AI helped
with exploration, code generation, and iterative review analysis,
but the Signed-off-by represents the maintainer's judgment that
the code is correct and appropriate for upstream.
That said, this is new territory. The series may have issues that
a more traditional development process would have caught differently,
or patterns that experienced reviewers find unusual. Constructive
feedback on both the code and the process is welcome.
What this series does
=====================
Defense-in-depth validation for perf.data file parsing. A crafted or
corrupted perf.data file can currently cause out-of-bounds reads/writes,
infinite loops, heap overflows, and segfaults in perf report, perf
script, perf inject, perf timechart, and perf kwork.
The series adds:
- A per-event-type minimum size table, enforced before swap and
processing on both native and cross-endian paths.
- Swap handler return values (void → int) so handlers can propagate
errors instead of silently corrupting adjacent memory.
- Bounds checking for string fields (null-termination), array counts
(nr vs payload size), feature section sizes (vs file size), and
CPU indices (vs nr_cpus_avail / array allocation).
- ABI0 handling for perf_event_attr.size == 0 across all code paths
(swap, native, synthesize, read_event_desc), with consistent
behavior regardless of file endianness.
- Backtrace ownership transfer in timechart (const char ** pattern)
to fix a pre-existing memory leak.
- A shell test that truncates perf.data at various offsets and
verifies perf report doesn't crash.
Design decisions reviewers may question
=======================================
1. Why not copy events to local buffers?
Native-endian files are MAP_SHARED+PROT_READ. Copying each event
would eliminate TOCTOU but adds overhead for the common case.
Instead, we validate once and accept the theoretical TOCTOU risk.
A follow-up could switch to MAP_PRIVATE for both paths — zero
overhead when no writes occur (COW is lazy).
2. Why warn+clamp instead of abort on invalid CPU?
Synthesized events (MMAP, COMM) lack sample_id_all data, so
evsel__parse_sample reads garbage from the event payload.
Aborting would kill perf report on perfectly normal perf.data
files. Clamping to 0 protects downstream array indexing.
The (u32)-1 sentinel is preserved for perf script and perf inject.
3. Why per-handler nr validation AND a central min_size table?
The min_size table catches undersized events before the swap
handler runs. But variable-length events (namespaces, thread_map,
cpu_map, stat_config) have array counts that must be validated
against the payload — that's per-handler because each layout
differs.
4. Why not validate on the native path by clamping in place?
Native-endian events are on a read-only mmap. Writing to them
would SIGSEGV. The swap path uses MAP_PRIVATE and can clamp in
place. The native path must skip or reject instead.
5. Why read attr.size into a local variable?
The event may be on a shared mmap. Re-reading could yield a
different value if another process modifies the file. Reading
once eliminates this class of concern.
FIXME items left for follow-up
==============================
- perf.data should record the recording system's page size.
Currently comp_mmap_len validation assumes 4K alignment.
- Block device input should be rejected or handled explicitly.
All file-size validation is skipped for non-regular files.
- MAP_PRIVATE for both native and swap paths would eliminate
ABI0 write-back workarounds and reduce TOCTOU surface.
Pre-existing bugs fixed opportunistically
==========================================
- event_contains() macro off-by-one (checked start, not full extent)
- zstd_decompress_stream multi-iteration output.pos bug
- zstd_compress_stream_to_records: broken memcpy fallback
- PERF_RECORD_SWITCH sample_id_all offset wrong for non-CPU_WIDE
- cpu_map__from_range any_cpu used as count instead of boolean
- cpu_map__from_mask double-fetch heap overflow
- kwork cpus_runtime BUG_ON with signed comparison
- perf_header__getbuffer64 EOF without errno
- timechart backtrace memory leak
- read_event_desc ABI0 sentinel corruption
Testing
=======
- perf test at baseline and at patches 1, 7, 10, 16, 20, 25, 27
with 300s timeout — no regressions detected.
- Build with both gcc and clang at every patch.
- checkpatch.pl on all 28 patches.
- 34 sashiko review rounds, all genuine findings addressed.
- Patch 28 adds a truncated perf.data test that exercises the
hardening code.
Arnaldo Carvalho de Melo (28):
perf session: Add minimum event size validation table
perf tools: Fix event_contains() macro to verify full field extent
perf zstd: Fix compression error path in
zstd_compress_stream_to_records()
perf zstd: Fix multi-iteration decompression and error handling
perf session: Fix PERF_RECORD_READ swap and dump for variable-length
events
perf session: Align auxtrace_info priv size before byte-swapping
perf session: Add validated swap infrastructure with null-termination
checks
perf session: Use bounded copy for PERF_RECORD_TIME_CONV
perf session: Validate HEADER_ATTR alignment and attr.size before
swapping
perf session: Validate nr fields against event size on both swap and
common paths
perf header: Byte-swap build ID event pid and bounds check section
entries
perf cpumap: Reject RANGE_CPUS with start_cpu > end_cpu
perf auxtrace: Harden auxtrace_error event handling
perf session: Add byte-swap and bounds check for
PERF_RECORD_BPF_METADATA events
perf header: Validate null-termination in PERF_RECORD_EVENT_UPDATE
string fields
perf tools: Bounds check perf_event_attr fields against attr.size
before printing
perf header: Propagate feature section processing errors
perf header: Validate f_attr.ids section before use in
perf_session__read_header()
perf header: Validate feature section size and add read path bounds
checking
perf header: Sanity check HEADER_EVENT_DESC attr.size before swap
perf header: Validate bitmap size before allocating in
do_read_bitmap()
perf session: Add byte-swap for PERF_RECORD_COMPRESSED2 events
perf tools: Harden compressed event processing
perf session: Check for decompression buffer size overflow
perf session: Bound nr_cpus_avail and validate sample CPU
perf timechart: Bounds check cpu_id and fix topology_map allocation
perf kwork: Bounds check work->cpu before indexing cpus_runtime[]
perf test: Add truncated perf.data robustness test
tools/lib/perf/include/perf/event.h | 4 +-
tools/perf/builtin-kwork.c | 49 +-
tools/perf/builtin-timechart.c | 117 +-
tools/perf/tests/parse-no-sample-id-all.c | 6 +
tools/perf/tests/shell/data_validation.sh | 59 +
tools/perf/trace/beauty/perf_event_open.c | 19 +-
tools/perf/util/arm-spe.c | 2 +-
tools/perf/util/auxtrace.c | 24 +-
tools/perf/util/cpumap.c | 22 +-
tools/perf/util/cs-etm.c | 2 +-
tools/perf/util/header.c | 601 ++++++++-
tools/perf/util/jitdump.c | 2 +-
tools/perf/util/kwork.h | 1 +
tools/perf/util/perf_event_attr_fprintf.c | 140 +-
.../scripting-engines/trace-event-python.c | 28 +-
tools/perf/util/session.c | 1154 +++++++++++++++--
tools/perf/util/svghelper.c | 6 +-
tools/perf/util/synthetic-events.c | 25 +-
tools/perf/util/tool.c | 51 +-
tools/perf/util/tsc.c | 2 +-
tools/perf/util/zstd.c | 35 +-
21 files changed, 2088 insertions(+), 261 deletions(-)
create mode 100755 tools/perf/tests/shell/data_validation.sh
--
2.54.0
next reply other threads:[~2026-05-10 3:34 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-10 3:33 Arnaldo Carvalho de Melo [this message]
2026-05-10 3:33 ` [PATCH 01/28] perf session: Add minimum event size validation table Arnaldo Carvalho de Melo
2026-05-11 19:01 ` Ian Rogers
2026-05-10 3:33 ` [PATCH 02/28] perf tools: Fix event_contains() macro to verify full field extent Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 03/28] perf zstd: Fix compression error path in zstd_compress_stream_to_records() Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 04/28] perf zstd: Fix multi-iteration decompression and error handling Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 05/28] perf session: Fix PERF_RECORD_READ swap and dump for variable-length events Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 06/28] perf session: Align auxtrace_info priv size before byte-swapping Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 07/28] perf session: Add validated swap infrastructure with null-termination checks Arnaldo Carvalho de Melo
2026-05-10 3:33 ` [PATCH 08/28] perf session: Use bounded copy for PERF_RECORD_TIME_CONV Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 09/28] perf session: Validate HEADER_ATTR alignment and attr.size before swapping Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 10/28] perf session: Validate nr fields against event size on both swap and common paths Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 11/28] perf header: Byte-swap build ID event pid and bounds check section entries Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 12/28] perf cpumap: Reject RANGE_CPUS with start_cpu > end_cpu Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 13/28] perf auxtrace: Harden auxtrace_error event handling Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 14/28] perf session: Add byte-swap and bounds check for PERF_RECORD_BPF_METADATA events Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 15/28] perf header: Validate null-termination in PERF_RECORD_EVENT_UPDATE string fields Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 16/28] perf tools: Bounds check perf_event_attr fields against attr.size before printing Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 17/28] perf header: Propagate feature section processing errors Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 18/28] perf header: Validate f_attr.ids section before use in perf_session__read_header() Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 19/28] perf header: Validate feature section size and add read path bounds checking Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 20/28] perf header: Sanity check HEADER_EVENT_DESC attr.size before swap Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 21/28] perf header: Validate bitmap size before allocating in do_read_bitmap() Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 22/28] perf session: Add byte-swap for PERF_RECORD_COMPRESSED2 events Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 23/28] perf tools: Harden compressed event processing Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 24/28] perf session: Check for decompression buffer size overflow Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 25/28] perf session: Bound nr_cpus_avail and validate sample CPU Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 26/28] perf timechart: Bounds check cpu_id and fix topology_map allocation Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 27/28] perf kwork: Bounds check work->cpu before indexing cpus_runtime[] Arnaldo Carvalho de Melo
2026-05-10 3:34 ` [PATCH 28/28] perf test: Add truncated perf.data robustness test Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260510033424.255812-1-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=adrian.hunter@intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=kan.liang@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=tglx@linutronix.de \
--cc=williams@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox