* [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-05 13:29 [PATCHES v1 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
@ 2026-08-05 13:30 ` Arnaldo Carvalho de Melo
2026-08-05 19:19 ` Ian Rogers
0 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 13:30 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
If code_size equals total_size - sizeof(jr->load), the sym pointer
aliases the code blob with no NUL terminator, and strlen() scans past
the buffer into adjacent heap memory.
Add a memchr() check to verify the symbol name is NUL-terminated within
the region between the load header and the code blob before use.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info 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>
---
tools/perf/util/jitdump.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 87612ef3e232598e..5f3a53f818c29f58 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
sym = (void *)((unsigned long)jr + sizeof(jr->load));
code = (unsigned long)jr + jr->load.p.total_size - csize;
+
+ /* sym string lives between the load header and the code blob */
+ if (!memchr(sym, '\0', code - (unsigned long)sym)) {
+ pr_warning("jitdump: unterminated symbol name in code_load record\n");
+ return -1;
+ }
+
count = jr->load.code_index;
idr_size = jd->machine->id_hdr_size;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-05 13:30 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
@ 2026-08-05 19:19 ` Ian Rogers
0 siblings, 0 replies; 29+ messages in thread
From: Ian Rogers @ 2026-08-05 19:19 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
linux-perf-users, Arnaldo Carvalho de Melo, sashiko-bot,
Stephane Eranian
On Wed, Aug 5, 2026 at 6:32 AM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
> passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
> If code_size equals total_size - sizeof(jr->load), the sym pointer
> aliases the code blob with no NUL terminator, and strlen() scans past
> the buffer into adjacent heap memory.
>
> Add a memchr() check to verify the symbol name is NUL-terminated within
> the region between the load header and the code blob before use.
>
> Fixes: 598b7c6919c7bbcc ("perf jit: add source line info 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>
Reviewed-by: Ian Rogers <irogers@google.com>
Thanks!
Ian
> ---
> tools/perf/util/jitdump.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 87612ef3e232598e..5f3a53f818c29f58 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
>
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
> code = (unsigned long)jr + jr->load.p.total_size - csize;
> +
> + /* sym string lives between the load header and the code blob */
> + if (!memchr(sym, '\0', code - (unsigned long)sym)) {
> + pr_warning("jitdump: unterminated symbol name in code_load record\n");
> + return -1;
> + }
> +
> count = jr->load.code_index;
> idr_size = jd->machine->id_hdr_size;
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
@ 2026-08-05 21:27 ` Arnaldo Carvalho de Melo
2026-08-05 21:51 ` sashiko-bot
0 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:27 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
If code_size equals total_size - sizeof(jr->load), the sym pointer
aliases the code blob with no NUL terminator, and strlen() scans past
the buffer into adjacent heap memory.
Add a memchr() check to verify the symbol name is NUL-terminated within
the region between the load header and the code blob before use.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 5a3ea2681fb37105..5898a7d8eb962daf 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
sym = (void *)((unsigned long)jr + sizeof(jr->load));
code = (unsigned long)jr + jr->load.p.total_size - csize;
+
+ /* sym string lives between the load header and the code blob */
+ if (!memchr(sym, '\0', code - (unsigned long)sym)) {
+ pr_warning("jitdump: unterminated symbol name in code_load record\n");
+ return -1;
+ }
+
count = jr->load.code_index;
idr_size = jd->machine->id_hdr_size;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-05 21:27 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
@ 2026-08-05 21:51 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-05 21:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Pre-existing heap out-of-bounds read in `jit_repipe_code_move` due to a hardcoded `+ 16` allocation size while using a dynamically sized header length.
--
--- Patch [11]: [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load ---
commit acba84089a50bc7dce59fc1ccce1335a41bbb013
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Validate sym string NUL-termination in code load
This commit adds a memchr() check to verify that the symbol name is
NUL-terminated within the region between the load header and the code blob.
This prevents an out-of-bounds read that could occur if code_size equals
total_size - sizeof(jr->load).
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 5a3ea2681fb37..5898a7d8eb962 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
>
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
> code = (unsigned long)jr + jr->load.p.total_size - csize;
> +
> + /* sym string lives between the load header and the code blob */
> + if (!memchr(sym, '\0', code - (unsigned long)sym)) {
> + pr_warning("jitdump: unterminated symbol name in code_load record\n");
> + return -1;
> + }
> +
> count = jr->load.code_index;
> idr_size = jd->machine->id_hdr_size;
[Severity: High]
This is a pre-existing issue, but I noticed a potential out-of-bounds read in
the related jit_repipe_code_move() function when calculating header sizes.
In tools/perf/util/jitdump.c:jit_repipe_code_move(), the event buffer is
allocated with a hardcoded +16 byte extra capacity:
/*
* +16 to account for sample_id_all (hack)
*/
event = calloc(1, sizeof(*event) + 16);
However, when setting the header size, it adds the dynamic idr_size:
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
Could this result in an out-of-bounds read when perf_data__write() processes
this event?
If idr_size exceeds 16 bytes (which can happen depending on the sample_type)
and the dynamically sized filename string takes up the remaining slack space,
the calculated event->mmap2.header.size might exceed the allocated buffer size.
Could this leak uninitialized heap memory into the output stream?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=11
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCHES v3 0/12] perf jitdump: Input validation hardening
@ 2026-08-06 12:35 Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
` (11 more replies)
0 siblings, 12 replies; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Stephane Eranian, Stefano Sanfilippo, Arnaldo Carvalho de Melo
Hi,
Please consider merging,
This series addresses twelve classes of input validation and resource
handling bugs in the jitdump file format parser that could cause OOB
memory access or memory leaks when processing maliciously crafted or
corrupted jitdump files.
All issues were discovered by sashiko-bot during automated review of the
jitdump code path. The bugs affect both the native-endian and byte-swap
code paths, with some checks previously only enforced during
byte-swapping.
Critical fix:
code_size validation was bypassable via int truncation. A record with
code_size in [2^31, record_size - 56] passed the existing bounds check
in jit_repipe_code_load() but truncated to a negative int when sent to
jit_process_code_load(), so the code pointer landed ~2GiB past the
record buffer, defeating the memchr() NUL scan and corrupting the
injected ELF.
Before: code_size = 0x80000010 passes the range check, then truncates
to a negative offset
After: code_size > INT_MAX is rejected up front; all subsequent code
size arithmetic stays within the record buffer
Best regards,
- Arnaldo
Changes since v2 (fe3ab00d55aa56b4), series reordered:
- Reordered the series so that the leak plug for debug_data and
unwinding_data (now patch 2/12) comes before the code_size
validation patch that introduces the early-return path flagged by
sashiko-bot during review of v2. With the fix in place first, the
early return no longer introduces a leak that would only have been
plugged later in the series.
- Otherwise the series is unchanged: the end result is byte-identical
to v2 (tree diff between the v2 and v3 tips is empty).
- The pre-existing issues reported by sashiko-bot that are outside the
scope of this series were recorded in a TODO list for the next
series (tools/perf/TODO.hardening), which is now in production.
Changes since v1 (20260805133013.235016-1-acme@kernel.org):
- Rebased onto the current perf-tools-next head (fe3ab00d55aa56b4).
- All 12 patches now carry a Reviewed-by: Ian Rogers <irogers@google.com>.
- Applied the code-convention suggestions from Ian's review of v1:
- Patch "perf jitdump: Check snprintf return before computing header
size": the clamp now uses sizeof(event->mmap2.filename) instead of
PATH_MAX in both jit_repipe_code_load() and
jit_repipe_code_move(), tying the bound to the actual destination
buffer.
- Patch "perf jitdump: Use dirname() return value in jit_open()":
the strlcpy() bound uses sizeof(jd->dir) instead of PATH_MAX.
- A cosmetics-only remark about the include order of <limits.h> was
deliberately not applied.
Issues fixed:
Validation and bounds checks:
- Validate code_size against both the record size and INT_MAX in
jit_repipe_code_load()
- Prevent integer underflow in the debug info size calculation
- Bounds-check the debug entry byte-swap loop
- Validate debug entries on the native (non-swap) path, matching the
existing byte-swap path checks
- Validate sym string NUL-termination in code load, bounding the
strlen() scan to the code blob
- Validate unwinding sizes against the record payload before allocating
- Check the snprintf() return before computing the header size, and
clamp against the actual buffer size
Stream and record handling:
- Fix the extended header read that always failed, causing records to
be misparsed
- Use dirname()'s return value in jit_open(), fixing ENOTDIR failures
- Fix funlockfile() being called on an unlocked stream in the jit_open()
error path
Resource management:
- Free the event in jit_repipe_code_move()
- Fix debug_data and unwinding_data leaks when records are overwritten
Each patch includes a Fixes: tag pointing to the offending commit, dating
back to jitdump mmap injection support (9b07e27f88b9cd78), source line
info support (598b7c6919c7bbcc), and unwinding support
(0284fecd13b6db3e), all from the original 2016 jitdump work.
Testing: Built and tested on x86_64. No existing tests cover jitdump
parsing with malformed input; test suite expansion is left for future
work. The final series was re-reviewed after the fixes and the v1
review (build-checked, Fixes: tags verified); no regressions found.
AI assistance: This series was developed with assistance from Claude
(claude-opus-4.6) and Opencode (deepseek-v4-flash-free) for code
analysis, patch generation, and commit message composition.
Arnaldo Carvalho de Melo (12):
perf jitdump: Fix extended header read that always fails
perf jitdump: Fix debug_data and unwinding_data leaks
perf jitdump: Validate code_size against total_size in code load
perf jitdump: Prevent integer underflow in debug info size calculation
perf jitdump: Bounds-check debug entry byte-swap loop
perf jitdump: Check snprintf return before computing header size
perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path
perf jitdump: Free event in jit_repipe_code_move()
perf jitdump: Use dirname() return value in jit_open()
perf jitdump: Validate debug entries on native (non-swap) path
perf jitdump: Validate sym string NUL-termination in code load
perf jitdump: Validate unwinding sizes against record payload
tools/perf/util/jitdump.c | 126 +++++++++++++++++++++++++++++++++++++++-------
1 file changed, 108 insertions(+), 18 deletions(-)
base-commit: fe3ab00d55aa56b4d55cbc1150448f0aadd6732c
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 01/12] perf jitdump: Fix extended header read that always fails
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 13:04 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
` (10 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_open() sets bsz = bs before the fread() that uses bs - bsz as the
read size, making the expression always evaluate to zero. fread() with
size 0 returns 0, which triggers the ret != 1 error path — so extended
jitdump headers (total_size > sizeof(header)) have been silently broken
since the original implementation.
Additionally, when 0 < bs <= bsz the if (bs > bsz) block is skipped
entirely, leaving extended header bytes unread in the stream. Subsequent
jit_get_next_entry() calls then parse those leftover bytes as a
jr_prefix, corrupting the record stream.
Fix by separating the buffer growth from the read: realloc only when
bs > bsz, then unconditionally fread bs bytes when bs > 0.
Fixes: 9b07e27f88b9cd78 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 83005b30b9bf3fd7..4b7c7ba7cd95ddbb 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -224,10 +224,12 @@ jit_open(struct jit_buf_desc *jd, const char *name)
n = realloc(buf, bs);
if (!n)
goto error;
- bsz = bs;
buf = n;
- /* read extra we do not know about */
- ret = fread(buf, bs - bsz, 1, jd->in);
+ bsz = bs;
+ }
+ if (bs > 0) {
+ /* consume extended header bytes from the stream */
+ ret = fread(buf, bs, 1, jd->in);
if (ret != 1)
goto error;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
` (9 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_debug_info() overwrites jd->debug_data without freeing the
previous allocation. If two consecutive JIT_CODE_DEBUG_INFO records
appear without an intervening LOAD record consuming the data, the first
allocation leaks.
The sibling jit_repipe_unwinding_info() already frees the old
jd->unwinding_data before reassignment — add the same pattern to
jit_repipe_debug_info() using zfree().
Also add cleanup of both buffers in jit_close() so they are freed when
the jitdump session ends, even if no LOAD record consumed them.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 4b7c7ba7cd95ddbb..dcb26d9c6c8fc551 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -117,6 +117,8 @@ jit_close(struct jit_buf_desc *jd)
funlockfile(jd->in);
fclose(jd->in);
jd->in = NULL;
+ zfree(&jd->debug_data);
+ zfree(&jd->unwinding_data);
}
static int
@@ -665,6 +667,7 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
memcpy(data, &jr->info.entries, sz);
+ zfree(&jd->debug_data);
jd->debug_data = data;
/*
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:56 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
` (8 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_code_load() reads code_size from the jitdump record and uses
it to compute a pointer to the code blob:
code = (unsigned long)jr + jr->load.p.total_size - csize;
An oversized code_size underflows the pointer arithmetic, causing OOB
reads into earlier heap memory. Validate that code_size fits within the
record (total_size - sizeof(jr->load)) before the pointer computation.
code_size is uint64_t but csize is int; values above INT_MAX wrap
negative when narrowed into csize, which defeats the bounds check and
sends the code pointer past the end of the record. Reject those too.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Assisted-by: Opencode:mimo-v2.5-free
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index dcb26d9c6c8fc551..14bd23c8d1963e92 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -9,6 +9,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
+#include <limits.h>
#include <byteswap.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -452,6 +453,16 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
csize = jr->load.code_size;
usize = jd->unwinding_mapped_size;
addr = jr->load.code_addr;
+
+ /* code blob lives at the end of the record, validate it fits */
+ if (jr->load.p.total_size < sizeof(jr->load) ||
+ jr->load.code_size > jr->load.p.total_size - sizeof(jr->load) ||
+ jr->load.code_size > INT_MAX) {
+ pr_warning("jitdump: invalid code_size %" PRIu64 " (total_size=%u) in code_load record\n",
+ (uint64_t)jr->load.code_size, jr->load.p.total_size);
+ return -1;
+ }
+
sym = (void *)((unsigned long)jr + sizeof(jr->load));
code = (unsigned long)jr + jr->load.p.total_size - csize;
count = jr->load.code_index;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (2 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:55 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
` (7 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian,
Stefano Sanfilippo
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_debug_info() and jit_repipe_unwinding_info() compute payload
sizes by subtracting the fixed header size from total_size:
sz = jr->prefix.total_size - sizeof(jr->info);
When total_size is smaller than the header struct (from a truncated or
corrupted jitdump record), the subtraction underflows to a massive
value, causing an oversized allocation followed by an OOB memcpy.
Validate that total_size covers at least the fixed header before the
subtraction in both functions.
Fixes: 598b7c6919c7 ("perf jit: add source line info support")
Fixes: 0284fecd13b6 ("perf jit: Add unwinding support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Stefano Sanfilippo <ssanfilippo@chromium.org>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 14bd23c8d1963e92..f79e9420c6bd7c51 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -671,6 +671,10 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
if (!(jd && jr))
return -1;
+ /* total_size must cover at least the fixed header */
+ if (jr->prefix.total_size < sizeof(jr->info))
+ return -1;
+
sz = jr->prefix.total_size - sizeof(jr->info);
data = malloc(sz);
if (!data)
@@ -699,6 +703,10 @@ jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
if (!(jd && jr))
return -1;
+ /* total_size must cover at least the fixed header */
+ if (jr->prefix.total_size < sizeof(jr->unwinding))
+ return -1;
+
unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
unwinding_data = malloc(unwinding_data_size);
if (!unwinding_data)
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (3 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 06/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
` (6 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
The byte-swap loop for JIT_CODE_DEBUG_INFO uses array indexing
(jr->info.entries[n]) to iterate debug entries. struct debug_entry has
a flexible array member name[], so each entry has a different size.
Array indexing computes offsets assuming fixed-size elements, landing
inside variable-length name strings after the first entry and
byte-swapping garbage.
Additionally, nr_entry is read from untrusted jitdump input without
validation against total_size, so a crafted value causes OOB reads.
Replace the array indexing with debug_entry_next() pointer arithmetic
(which correctly accounts for the variable-length name) and
bounds-check each entry against the record's total_size before
byte-swapping.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index f79e9420c6bd7c51..7efbaa07f1ba73f9 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -320,14 +320,32 @@ jit_get_next_entry(struct jit_buf_desc *jd)
switch(id) {
case JIT_CODE_DEBUG_INFO:
if (jd->needs_bswap) {
+ void *end = (void *)jr + jr->prefix.total_size;
+ struct debug_entry *ent;
uint64_t n;
+
jr->info.code_addr = bswap_64(jr->info.code_addr);
jr->info.nr_entry = bswap_64(jr->info.nr_entry);
- for (n = 0 ; n < jr->info.nr_entry; n++) {
- jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
- jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
- jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
+
+ /*
+ * debug_entry has a variable-length name[], so array
+ * indexing would compute wrong offsets — use
+ * debug_entry_next() and bounds-check each entry.
+ */
+ ent = &jr->info.entries[0];
+ for (n = 0; n < jr->info.nr_entry; n++) {
+ if ((void *)ent + sizeof(*ent) > end)
+ break;
+ /* name must be NUL-terminated within the record */
+ if (!memchr(ent->name, '\0', (char *)end - ent->name))
+ break;
+ ent->addr = bswap_64(ent->addr);
+ ent->lineno = bswap_32(ent->lineno);
+ ent->discrim = bswap_32(ent->discrim);
+ ent = debug_entry_next(ent);
}
+ /* clamp so downstream consumers don't overrun */
+ jr->info.nr_entry = n;
}
break;
case JIT_CODE_UNWINDING_INFO:
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 06/12] perf jitdump: Check snprintf return before computing header size
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (4 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
` (5 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
snprintf() returns the would-have-been length on truncation. When the
jitted filename exceeds PATH_MAX, the unclamped 'size' value inflates
sizeof(event->mmap2.filename) - size into a massive underflow, causing
the header.size computation to write an oversized header. The
subsequent write to 'id = event + header.size - idr_size' then corrupts
the heap.
Clamp size to PATH_MAX - 1 after snprintf in both jit_repipe_code_load()
and jit_repipe_code_move().
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 7efbaa07f1ba73f9..45f0e21b0e780cb6 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -495,6 +495,9 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
jd->dir,
nspid,
count);
+ /* snprintf returns would-be length on truncation, clamp to buffer */
+ if (size >= sizeof(event->mmap2.filename))
+ size = sizeof(event->mmap2.filename) - 1;
size++; /* for \0 */
@@ -625,6 +628,9 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
jd->dir,
nspid,
jr->move.code_index);
+ /* snprintf returns would-be length on truncation, clamp to buffer */
+ if (size >= sizeof(event->mmap2.filename))
+ size = sizeof(event->mmap2.filename) - 1;
size++; /* for \0 */
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (5 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 06/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
` (4 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
If the malloc() for the initial read buffer fails, jit_open() jumps to
the error label which calls funlockfile(jd->in). However, flockfile()
is called later in the function, so at this point the stream was never
locked. Calling funlockfile() on an unlocked stream is undefined
behavior per POSIX.
Split the error path into two labels: 'error' (after flockfile) calls
funlockfile before cleanup, 'error_noflock' (before flockfile) skips
the unlock.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 45f0e21b0e780cb6..ae63366b86c6d765 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -157,7 +157,7 @@ jit_open(struct jit_buf_desc *jd, const char *name)
buf = malloc(bsz);
if (!buf)
- goto error;
+ goto error_noflock;
/*
* protect from writer modifying the file while we are reading it
@@ -246,8 +246,9 @@ jit_open(struct jit_buf_desc *jd, const char *name)
return 0;
error:
- free(buf);
funlockfile(jd->in);
+error_noflock:
+ free(buf);
fclose(jd->in);
return retval;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move()
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (6 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
@ 2026-08-06 12:35 ` Arnaldo Carvalho de Melo
2026-08-06 12:49 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
` (3 subsequent siblings)
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:35 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_code_move() allocates a perf_event with calloc but never
frees it — the 'out' label exits with only perf_sample__exit().
The sibling function jit_repipe_code_load() correctly calls
free(event) at its out label. Add the same free(event) to
jit_repipe_code_move().
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index ae63366b86c6d765..91aa1eea8229faac 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -685,6 +685,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
build_id__mark_dso_hit(tool, event, &sample, jd->machine);
out:
perf_sample__exit(&sample);
+ free(event);
return ret;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open()
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (7 preceding siblings ...)
2026-08-06 12:35 ` [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
@ 2026-08-06 12:36 ` Arnaldo Carvalho de Melo
2026-08-06 12:36 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
` (2 subsequent siblings)
11 siblings, 0 replies; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:36 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_open() calls dirname(jd->dir) but ignores the return value. POSIX
says dirname() may return a pointer to internal static storage — glibc
does this when the path has no '/', returning "." from a static buffer
and leaving jd->dir unchanged with the original filename.
Capture the return value and copy it back to jd->dir when dirname()
returns a different pointer.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 91aa1eea8229faac..d3de307532d55065 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -146,6 +146,7 @@ jit_open(struct jit_buf_desc *jd, const char *name)
ssize_t bs, bsz = 0;
void *n, *buf = NULL;
int ret, retval = -1;
+ char *dname;
nsinfo__mountns_enter(jd->nsi, &nsc);
jd->in = fopen(name, "r");
@@ -241,7 +242,9 @@ jit_open(struct jit_buf_desc *jd, const char *name)
*/
strncpy(jd->dir, name, PATH_MAX - 1);
jd->dir[PATH_MAX - 1] = '\0';
- dirname(jd->dir);
+ dname = dirname(jd->dir);
+ if (dname != jd->dir)
+ strlcpy(jd->dir, dname, sizeof(jd->dir));
free(buf);
return 0;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (8 preceding siblings ...)
2026-08-06 12:36 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
@ 2026-08-06 12:36 ` Arnaldo Carvalho de Melo
2026-08-06 13:10 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
2026-08-06 12:36 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:36 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
The bounds-checking and nr_entry clamping added for the byte-swap path
only runs when jd->needs_bswap is true. On native-endian files, nr_entry
passes through unvalidated to jit_repipe_debug_info(), which stores it
as jd->nr_debug_entries. Downstream, jit_process_debug_info() in
genelf_debug.c iterates nr_debug_entries times via debug_entry_next(),
which calls strlen() on each entry's name field — a crafted nr_entry
causes OOB reads and writes.
Add bounds-checked iteration in jit_repipe_debug_info() that validates
each debug_entry fits in the payload and its name is NUL-terminated
before calling debug_entry_next(). Clamp nr_debug_entries to the count
of valid entries.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index d3de307532d55065..5a3ea2681fb37105 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -694,8 +694,10 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
{
- void *data;
- size_t sz;
+ struct debug_entry *ent;
+ void *data, *end;
+ size_t sz, valid;
+ uint64_t i;
if (!(jd && jr))
return -1;
@@ -715,10 +717,25 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
jd->debug_data = data;
/*
- * we must use nr_entry instead of size here because
- * we cannot distinguish actual entry from padding otherwise
+ * Clamp nr_debug_entries to entries that actually fit in the
+ * payload. The byte-swap path already does this for cross-endian
+ * files; validate on the native path too, since downstream
+ * jit_process_debug_info() iterates via debug_entry_next() which
+ * calls strlen() on each entry's name field.
*/
- jd->nr_debug_entries = jr->info.nr_entry;
+ end = data + sz;
+ ent = data;
+ valid = 0;
+ for (i = 0; i < jr->info.nr_entry; i++) {
+ if ((void *)ent + sizeof(*ent) > end)
+ break;
+ /* name must be NUL-terminated within the payload */
+ if (!memchr(ent->name, '\0', (char *)end - ent->name))
+ break;
+ ent = debug_entry_next(ent);
+ valid++;
+ }
+ jd->nr_debug_entries = valid;
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (9 preceding siblings ...)
2026-08-06 12:36 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
@ 2026-08-06 12:36 ` Arnaldo Carvalho de Melo
2026-08-06 13:03 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:36 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
If code_size equals total_size - sizeof(jr->load), the sym pointer
aliases the code blob with no NUL terminator, and strlen() scans past
the buffer into adjacent heap memory.
Add a memchr() check to verify the symbol name is NUL-terminated within
the region between the load header and the code blob before use.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 5a3ea2681fb37105..5898a7d8eb962daf 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
sym = (void *)((unsigned long)jr + sizeof(jr->load));
code = (unsigned long)jr + jr->load.p.total_size - csize;
+
+ /* sym string lives between the load header and the code blob */
+ if (!memchr(sym, '\0', code - (unsigned long)sym)) {
+ pr_warning("jitdump: unterminated symbol name in code_load record\n");
+ return -1;
+ }
+
count = jr->load.code_index;
idr_size = jd->machine->id_hdr_size;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
` (10 preceding siblings ...)
2026-08-06 12:36 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
@ 2026-08-06 12:36 ` Arnaldo Carvalho de Melo
2026-08-06 13:06 ` sashiko-bot
11 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:36 UTC (permalink / raw)
To: Namhyung Kim
Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
Arnaldo Carvalho de Melo, sashiko-bot, Stefano Sanfilippo,
Stephane Eranian
From: Arnaldo Carvalho de Melo <acme@redhat.com>
jit_repipe_unwinding_info() copies unwinding_size and eh_frame_hdr_size
from the jitdump record into jd-> fields without checking them against
the actual payload size. Downstream, jit_add_eh_frame_info() in
genelf.c computes unwinding_table_size = unwinding_size -
eh_frame_hdr_size, which underflows when eh_frame_hdr_size >
unwinding_size. The result is passed as d->d_size to libelf, causing
an OOB heap read into the output ELF file.
Validate that unwinding_size fits within the record payload and that
eh_frame_hdr_size does not exceed unwinding_size before allocating or
storing the values, so a bogus record cannot force a large allocation
that is then discarded.
mapped_size is likewise taken from the record and was narrowed into an
int for the mmap2 len computation in jit_repipe_code_load() and
jit_repipe_code_move(); values above INT_MAX would turn negative,
producing a wrong mmap2 length. Use uint64_t for usize so the value
cannot truncate.
Fixes: 0284fecd13b6db3e ("perf jit: Add unwinding support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stefano Sanfilippo <ssanfilippo@chromium.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Assisted-by: Opencode:mimo-v2.5-free
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/jitdump.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 5898a7d8eb962daf..d25a9fe9b020ce87 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -462,7 +462,8 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
u16 idr_size;
const char *sym;
uint64_t count;
- int ret, csize, usize;
+ int ret, csize;
+ uint64_t usize;
pid_t nspid, pid, tid;
struct {
u32 pid, tid;
@@ -543,7 +544,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
event->mmap2.start = addr;
- event->mmap2.len = usize ? ALIGN_8(csize) + usize : csize;
+ event->mmap2.len = usize ? ALIGN_8((uint64_t)csize) + usize : (uint64_t)csize;
event->mmap2.pid = pid;
event->mmap2.tid = tid;
event->mmap2.ino = st.st_ino;
@@ -612,7 +613,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
char *filename;
size_t size;
struct stat st;
- int usize;
+ uint64_t usize;
u16 idr_size;
int ret;
pid_t nspid, pid, tid;
@@ -761,6 +762,18 @@ jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
return -1;
unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
+
+ /*
+ * Validate sizes before allocating — jit_add_eh_frame_info()
+ * computes unwinding_size - eh_frame_hdr_size and uses the
+ * result as a buffer length for libelf.
+ */
+ if (jr->unwinding.unwinding_size > unwinding_data_size ||
+ jr->unwinding.eh_frame_hdr_size > jr->unwinding.unwinding_size) {
+ pr_warning("jitdump: invalid unwinding sizes in unwinding_info record\n");
+ return -1;
+ }
+
unwinding_data = malloc(unwinding_data_size);
if (!unwinding_data)
return -1;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move()
2026-08-06 12:35 ` [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
@ 2026-08-06 12:49 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:49 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Heap Out-of-Bounds Read when writing event to perf.data in `jit_repipe_code_move()`
--
--- Patch [8]: [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() ---
commit b900743750fdefef6d63a1e65a54cf9d26b1477d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Free event in jit_repipe_code_move()
This commit fixes a memory leak in jit_repipe_code_move() by freeing the
event allocated via calloc at the out label, matching the behavior in
jit_repipe_code_load().
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index ae63366b86c6d..91aa1eea8229f 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -685,6 +685,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
[ ... ]
> build_id__mark_dso_hit(tool, event, &sample, jd->machine);
> out:
> perf_sample__exit(&sample);
> + free(event);
[Severity: High]
This is a pre-existing issue, but does this code have a heap out-of-bounds
read when calculating the event size?
In jit_repipe_code_move(), the event being freed here is initially allocated
with a hardcoded extra 16 bytes:
event = calloc(1, sizeof(*event) + 16);
However, the header size is calculated using idr_size:
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
If idr_size is greater than 16 (which can happen when multiple sample types
like TID, TIME, and CPU are enabled), and the path is very long, the
calculated header.size can exceed the allocated size.
When this event is later injected:
tools/perf/util/jitdump.c:jit_inject_event() {
...
size = perf_data__write(jd->output, event, event->header.size);
...
}
Could this cause perf_data__write() to read out-of-bounds from the heap,
potentially leaking adjacent memory into the perf.data file or causing a crash
if the read crosses into an unmapped page?
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=8
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path
2026-08-06 12:35 ` [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
@ 2026-08-06 12:51 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing validation of `nr_entry` in `JIT_CODE_DEBUG_INFO` records leads to heap out-of-bounds read and write.
- [High] Unvalidated sizes in `JIT_CODE_UNWINDING_INFO` records lead to a heap information leak.
--
--- Patch [7]: [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path ---
commit 8cca1c1db77a8a564c00747fab840f2d6744e3a9
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path
If the malloc() for the initial read buffer fails, jit_open() jumps to
the error label which calls funlockfile(jd->in). However, flockfile()
is called later in the function, so at this point the stream was never
locked. Calling funlockfile() on an unlocked stream is undefined
behavior per POSIX.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 45f0e21b0e780..ae63366b86c6d 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -157,7 +157,7 @@ jit_open(struct jit_buf_desc *jd, const char *name)
>
> buf = malloc(bsz);
> if (!buf)
> - goto error;
> + goto error_noflock;
>
> /*
> * protect from writer modifying the file while we are reading it
> @@ -246,8 +246,9 @@ jit_open(struct jit_buf_desc *jd, const char *name)
>
> return 0;
> error:
> - free(buf);
> funlockfile(jd->in);
> +error_noflock:
> + free(buf);
> fclose(jd->in);
> return retval;
> }
[Severity: High]
This isn't a bug introduced by this patch, but is there a missing validation
of nr_entry in JIT_CODE_DEBUG_INFO records?
If jd->needs_bswap is false, nr_entry is not validated against the actual
record size in jit_get_next_entry():
tools/perf/util/jitdump.c:jit_get_next_entry() {
...
if (jd->needs_bswap) {
void *end = (void *)jr + jr->prefix.total_size;
...
}
jit_repipe_debug_info() then blindly copies this unvalidated count into
jd->nr_debug_entries. Finally, jit_process_debug_info() loops
nr_debug_entries times:
tools/perf/util/genelf_debug.c:jit_process_debug_info() {
...
for (i = 0; i < nr_debug_entries; i++) {
ent->addr = ent->addr - code_addr;
ent = debug_entry_next(ent);
}
...
}
Could an attacker provide a JIT dump with a small payload but a massive
nr_entry, causing an out-of-bounds strlen read followed by an out-of-bounds
write (ent->addr = ...), corrupting heap memory?
[Severity: High]
This is a pre-existing issue, but are there unvalidated sizes in
JIT_CODE_UNWINDING_INFO records?
When parsing a JIT_CODE_UNWINDING_INFO record, jit_repipe_unwinding_info()
blindly copies the attacker-controlled unwinding_size and eh_frame_hdr_size
fields without checking if they fit within the allocated heap buffer:
tools/perf/util/jitdump.c:jit_repipe_unwinding_info() {
...
jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
jd->unwinding_size = jr->unwinding.unwinding_size;
...
}
These unvalidated sizes are later used by jit_add_eh_frame_info() to
configure libelf data sections:
tools/perf/util/genelf.c:jit_add_eh_frame_info() {
...
uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
...
d->d_buf = unwinding;
d->d_size = unwinding_table_size;
...
}
Could an attacker craft a record with a small total_size but massive
unwinding sizes, forcing libelf to read past the end of the heap buffer and
write megabytes of the perf inject process's heap memory into the generated
ELF file, causing an information leak?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=7
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop
2026-08-06 12:35 ` [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
@ 2026-08-06 12:51 ` sashiko-bot
2026-08-06 15:21 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Medium] Replacing array indexing with sequential pointer arithmetic (`debug_entry_next`) on unpadded, variable-length structures results in unaligned struct pointers, causing undefined behavior and SIGBUS crashes on strict-alignment architectures.
Pre-existing issues:
- [Critical] The newly added bounds checking and `nr_entry` clamping for `JIT_CODE_DEBUG_INFO` records are scoped exclusively inside the `if (jd->needs_bswap)` block, leaving native-endian files completely vulnerable to a massive heap buffer overflow.
- [High] Missing validation of `unwinding_size` against `unwinding_data_size` in `JIT_CODE_UNWINDING_INFO` leads to an out-of-bounds read during ELF generation.
- [Medium] The `event` buffer is leaked on all return paths in `jit_repipe_code_move()`.
- [Medium] `jit_repipe_code_move` fails to validate that the record's `total_size` is large enough to contain the `jr_code_move` payload, leading to the processing of uninitialized memory.
--
--- Patch [5]: [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop ---
commit 14beafbf2609e41d04f4020f064d84fdbb15c5a7
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Bounds-check debug entry byte-swap loop
This commit replaces array indexing with pointer arithmetic and adds bounds
checking for JIT_CODE_DEBUG_INFO records during byte-swapping to prevent
out-of-bounds reads.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index f79e9420c6bd7..7efbaa07f1ba7 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -320,14 +320,32 @@ jit_get_next_entry(struct jit_buf_desc *jd)
> switch(id) {
> case JIT_CODE_DEBUG_INFO:
> if (jd->needs_bswap) {
> + void *end = (void *)jr + jr->prefix.total_size;
> + struct debug_entry *ent;
> uint64_t n;
> +
> jr->info.code_addr = bswap_64(jr->info.code_addr);
> jr->info.nr_entry = bswap_64(jr->info.nr_entry);
> - for (n = 0 ; n < jr->info.nr_entry; n++) {
> - jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
> - jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
> - jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
> +
> + /*
> + * debug_entry has a variable-length name[], so array
> + * indexing would compute wrong offsets — use
> + * debug_entry_next() and bounds-check each entry.
> + */
> + ent = &jr->info.entries[0];
> + for (n = 0; n < jr->info.nr_entry; n++) {
> + if ((void *)ent + sizeof(*ent) > end)
> + break;
[Severity: Critical]
This is a pre-existing issue, but by placing the bounds checking and
nr_entry clamping exclusively inside the if (jd->needs_bswap) block,
native-endian files bypass this validation completely.
If a maliciously crafted JIT dump file with a native endianness matching the
host provides an arbitrarily large untrusted nr_entry count for a
JIT_CODE_DEBUG_INFO record, this path is skipped.
Later in the processing, this unvalidated value is assigned directly:
tools/perf/util/jitdump.c:jit_repipe_debug_info()
jd->nr_debug_entries = jr->info.nr_entry;
And then blindly iterated over on the heap:
tools/perf/util/genelf_debug.c:jit_process_debug_info()
for (i = 0; i < nr_debug_entries; i++) {
ent->addr = ent->addr - code_addr;
ent = debug_entry_next(ent);
}
Could we move the bounds validation outside of the byte-swapping block so all
inputs are checked?
> + /* name must be NUL-terminated within the record */
> + if (!memchr(ent->name, '\0', (char *)end - ent->name))
> + break;
> + ent->addr = bswap_64(ent->addr);
> + ent->lineno = bswap_32(ent->lineno);
> + ent->discrim = bswap_32(ent->discrim);
> + ent = debug_entry_next(ent);
[Severity: Medium]
Does this unpadded sequential pointer arithmetic lead to unaligned memory
accesses?
struct debug_entry contains 64-bit and 32-bit fields, requiring 8-byte
alignment, but it is not __packed. The debug_entry_next() helper calculates
the next entry's address by adding the length of the string:
tools/perf/util/jitdump.h:debug_entry_next()
void *a = ent + 1;
size_t l = strlen(ent->name) + 1;
return a + l;
This leaves the pointer unaligned. When the byte-swapping loop uses
ent = debug_entry_next(ent) and accesses ent->addr = bswap_64(ent->addr),
the compiler generates aligned load/store instructions for an unaligned
address, leading to SIGBUS crashes on strict-alignment architectures.
> }
> + /* clamp so downstream consumers don't overrun */
> + jr->info.nr_entry = n;
> }
> break;
> case JIT_CODE_UNWINDING_INFO:
> if (jd->needs_bswap) {
> jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size);
[Severity: High]
This is a pre-existing issue, but is the unwinding_size validated against the
actual payload size?
In jit_repipe_unwinding_info(), the unwinding size is saved directly from the
payload without validation against the allocated heap buffer size:
tools/perf/util/jitdump.c:jit_repipe_unwinding_info()
jd->unwinding_size = jr->unwinding.unwinding_size;
This unvalidated size is later passed to libelf:
tools/perf/util/genelf.c:jit_add_eh_frame_info()
d->d_size = unwinding_table_size;
A crafted record with a small total_size but a huge unwinding_size could
cause libelf to read out-of-bounds heap memory and embed it into the output
ELF, leading to an information leak.
> jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size);
> jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size);
> }
> break;
While reviewing this patch, I also noticed a couple of pre-existing issues
in the handling of JIT_CODE_MOVE records:
tools/perf/util/jitdump.c:jit_repipe_code_move()
[ ... ]
> nspid = jr->load.pid;
> pid = jr_entry_pid(jd, jr);
[Severity: Medium]
This isn't a bug introduced by this patch, but does jit_repipe_code_move()
validate that the record's total_size is large enough to contain the
jr_code_move payload?
If a malformed record is provided with a truncated total_size, fread() will
read only a partial record into jd->buf. The remaining fields will be
uninitialized or contain leftover data, which are then used to construct
the perf event.
[ ... ]
> event = calloc(1, sizeof(*event) + 16);
> if (!event)
> return -1;
[ ... ]
> ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
> if (ret)
> goto out;
>
> ret = jit_inject_event(jd, event);
> if (!ret)
> build_id__mark_dso_hit(tool, event, &sample, jd->machine);
> out:
> perf_sample__exit(&sample);
> return ret;
[Severity: Medium]
This is a pre-existing issue, but does this leak the event buffer?
The memory for event is allocated via calloc() and the function returns at
the out: label without calling free(event). Neither of the processing
functions take ownership of the memory, so the buffer appears to be leaked on
every JIT_CODE_MOVE record.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=5
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks
2026-08-06 12:35 ` [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
@ 2026-08-06 12:52 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:52 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Pre-existing issues:
- [Critical] The `csize` value from the untrusted JIT dump file is not validated against `total_size`, allowing an integer underflow that leads to a massive out-of-bounds heap read and information leak.
- [Critical] Output `.so` files are opened without `O_EXCL` and `O_NOFOLLOW` in a potentially attacker-controlled directory, allowing a symlink attack to overwrite arbitrary files.
- [High] Code load events fail to consume and free `unwinding_data` and `debug_data` if their respective auxiliary sizes or counts are zero, leading to state contamination.
- [High] Calling `funlockfile()` without a preceding `flockfile()` on the `malloc()` error path causes undefined behavior.
- [High] Missing bounds check on the JIT record `total_size` before accessing the `sym` string pointer causes an out-of-bounds string read.
--
--- Patch [2]: [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks ---
commit e7687575b20ca5df1e7780e1c7b436a5bc7d2f8c
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Fix debug_data and unwinding_data leaks
This commit fixes memory leaks in jit_repipe_debug_info() and jit_close().
It uses zfree() to correctly free existing allocations before reassignment
and cleans up at the end of the session.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -61,12 +61,12 @@ static int
> jit_emit_elf(struct jit_buf_desc *jd,
> char *filename,
[ ... ]
> nsinfo__mountns_enter(jd->nsi, &nsc);
> fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
[Severity: Critical]
This isn't a bug introduced by this patch, but opening output files without
O_EXCL and O_NOFOLLOW in a potentially attacker-controlled directory might
allow a symlink attack to overwrite arbitrary files.
Could this be updated to use safer open flags?
[ ... ]
> @@ -117,6 +117,8 @@ jit_close(struct jit_buf_desc *jd)
> funlockfile(jd->in);
> fclose(jd->in);
> jd->in = NULL;
> + zfree(&jd->debug_data);
> + zfree(&jd->unwinding_data);
> }
[ ... ]
> @@ -154,9 +154,9 @@ static int
> jit_open(struct jit_buf_desc *jd, const char *name)
> {
[ ... ]
> bsz = hmax(sizeof(header), sizeof(*prefix));
>
> buf = malloc(bsz);
> if (!buf)
> goto error;
>
> /*
> * protect from writer modifying the file while we are reading it
> */
> flockfile(jd->in);
[ ... ]
> @@ -217,9 +217,9 @@ static int
> return 0;
> error:
> free(buf);
> funlockfile(jd->in);
[Severity: High]
This isn't a bug introduced by this patch, but if the initial malloc(bsz)
fails, we jump to error and call funlockfile(jd->in) without a preceding
flockfile().
Does calling funlockfile() on an unlocked FILE stream cause undefined
behavior or corruption of internal libc mutexes here?
> fclose(jd->in);
> return retval;
> }
[ ... ]
> @@ -465,10 +465,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> nspid = jr->load.pid;
> pid = jr_entry_pid(jd, jr);
> tid = jr_entry_tid(jd, jr);
> csize = jr->load.code_size;
> usize = jd->unwinding_mapped_size;
> addr = jr->load.code_addr;
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
[Severity: High]
This is a pre-existing issue, but is it possible for jr->load.p.total_size
to be smaller than sizeof(jr->load)?
The sym pointer is derived assuming total_size is at least 56 bytes, which
isn't validated before access. Could this lead to an out-of-bounds string
read if a smaller total_size is provided?
> code = (unsigned long)jr + jr->load.p.total_size - csize;
[Severity: Critical]
This is a pre-existing issue, but the code pointer is calculated using csize
without checking if it exceeds total_size.
Could an attacker provide a csize larger than total_size to cause an integer
underflow, resulting in a massive out-of-bounds heap read and information
leak into the generated ELF file?
> count = jr->load.code_index;
> idr_size = jd->machine->id_hdr_size;
[ ... ]
> @@ -475,10 +475,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> event = calloc(1, sizeof(*event) + idr_size);
> if (!event)
> return -1;
>
> filename = event->mmap2.filename;
> size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
> jd->dir,
> nspid,
> count);
[Severity: Critical]
This isn't a bug introduced by this patch, but the filename is predictably
constructed using fields (nspid and count) controlled by the JIT dump.
Combined with the lack of O_EXCL|O_NOFOLLOW in jit_emit_elf(), does this
allow an attacker to perform a symlink attack when perf inject is run?
[ ... ]
> @@ -495,10 +495,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> jd->nr_debug_entries = 0;
> }
>
> if (jd->unwinding_data && jd->eh_frame_hdr_size) {
> zfree(&jd->unwinding_data);
> jd->eh_frame_hdr_size = 0;
> jd->unwinding_mapped_size = 0;
> jd->unwinding_size = 0;
> }
[Severity: High]
This is a pre-existing issue, but this conditional cleanup leaves
jd->unwinding_data dangling if eh_frame_hdr_size is zero.
If a JIT runtime emits JIT_CODE_UNWINDING_INFO without .eh_frame_hdr, is the
unwinding data incorrectly applied to all subsequent JIT_CODE_LOAD events
until overwritten, producing corrupted ELF files?
[ ... ]
> @@ -665,6 +667,7 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
>
> memcpy(data, &jr->info.entries, sz);
>
> + zfree(&jd->debug_data);
> jd->debug_data = data;
>
> /*
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=2
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 06/12] perf jitdump: Check snprintf return before computing header size
2026-08-06 12:35 ` [PATCH 06/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
@ 2026-08-06 12:52 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:52 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Medium] Out-of-bounds heap read leaking information into `perf.data` via `jit_repipe_code_move()`.
--
--- Patch [6]: [PATCH 06/12] perf jitdump: Check snprintf return before computing header size ---
commit 8f494719852b9efdd2ae99317e82686b5aa7c596
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Check snprintf return before computing header size
This commit fixes a heap corruption bug caused by an underflow when
calculating the header size if a jitted filename exceeds PATH_MAX. It
clamps the length returned by snprintf() to fit within the bounds of
the event's filename buffer in both jit_repipe_code_load() and
jit_repipe_code_move().
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 7efbaa07f1ba7..45f0e21b0e780 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
[ ... ]
> @@ -625,6 +628,9 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
> jd->dir,
> nspid,
> jr->move.code_index);
> + /* snprintf returns would-be length on truncation, clamp to buffer */
> + if (size >= sizeof(event->mmap2.filename))
> + size = sizeof(event->mmap2.filename) - 1;
>
> size++; /* for \0 */
>
[Severity: Medium]
This is a pre-existing issue, but does this function allocate enough memory
to handle large dynamic idr_size values?
Earlier in jit_repipe_code_move(), the event is allocated with a hardcoded
+ 16 byte extension:
tools/perf/util/jitdump.c:jit_repipe_code_move() {
...
/*
* +16 to account for sample_id_all (hack)
*/
event = calloc(1, sizeof(*event) + 16);
...
}
However, the event size calculation uses the dynamic idr_size:
tools/perf/util/jitdump.c:jit_repipe_code_move() {
...
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
...
}
If the idr_size is greater than 16 (for example 24 or 32 bytes depending on
sample types like TID, TIME, and CPU), could this lead to an out-of-bounds
heap read when the event is written out? It appears the calculation for the
header size expects the allocation to match the actual idr_size.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=6
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation
2026-08-06 12:35 ` [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
@ 2026-08-06 12:55 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:55 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Unclamped `snprintf` return values when formatting filenames cause integer underflow, inflating event size and leading to out-of-bounds heap writes.
- [High] Cross-endian byte-swapping of debug info entries uses incorrect fixed-size array indexing on a variable-length structure, causing severe heap corruption.
- [High] Unvalidated structural sizes for unwinding info lead to massive out-of-bounds heap reads and information disclosure during ELF generation.
- [High] Missing validation of `nr_entry` against the payload size in `jit_repipe_debug_info()` leads to heap out-of-bounds accesses during debug info processing.
--
--- Patch [4]: [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation ---
commit 279da6780ef70ba142d7c4f7db07000972f0e035
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Prevent integer underflow in debug info size calculation
jit_repipe_debug_info() and jit_repipe_unwinding_info() compute payload
sizes by subtracting the fixed header size from total_size. This prevents
an underflow when total_size is smaller than the header struct.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 14bd23c8d1963..f79e9420c6bd7 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -671,6 +671,10 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
> if (!(jd && jr))
> return -1;
>
> + /* total_size must cover at least the fixed header */
> + if (jr->prefix.total_size < sizeof(jr->info))
> + return -1;
> +
> sz = jr->prefix.total_size - sizeof(jr->info);
> data = malloc(sz);
> if (!data)
[Severity: High]
This is a pre-existing issue, but does this function also need to validate
jr->info.nr_entry against the payload size?
It appears the unvalidated count is saved to jd->nr_debug_entries. Later,
in jit_process_debug_info(), a loop iterates nr_debug_entries times:
tools/perf/util/genelf_debug.c:jit_process_debug_info() {
[ ... ]
for (i = 0; i < nr_debug_entries; i++) {
ent->addr = ent->addr - code_addr;
ent = debug_entry_next(ent);
}
[ ... ]
}
Since debug_entry_next() computes pointer offsets by reading variable-length
strings, could an artificially inflated nr_entry force the loop to iterate
past the allocated debug_data buffer and cause an out-of-bounds heap write?
[ ... ]
> @@ -699,6 +703,10 @@ jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
> if (!(jd && jr))
> return -1;
>
> + /* total_size must cover at least the fixed header */
> + if (jr->prefix.total_size < sizeof(jr->unwinding))
> + return -1;
> +
> unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
> unwinding_data = malloc(unwinding_data_size);
> if (!unwinding_data)
[Severity: High]
This isn't a bug introduced by this patch, but could the structural sizes
extracted from the untrusted record cause out-of-bounds reads later?
In jit_repipe_unwinding_info(), these sizes are blindly extracted:
tools/perf/util/jitdump.c:jit_repipe_unwinding_info() {
[ ... ]
jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
jd->unwinding_size = jr->unwinding.unwinding_size;
[ ... ]
}
Then they are used to configure libelf data sections:
tools/perf/util/genelf.c:jit_add_eh_frame_info() {
[ ... ]
uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
[ ... ]
d->d_buf = unwinding;
d->d_size = unwinding_table_size;
[ ... ]
}
If jr->unwinding.unwinding_size is inflated beyond the actual payload size,
could libelf read past the end of the unwinding_data allocation and leak
arbitrary heap memory to the generated ELF file?
[Severity: High]
This is a pre-existing issue, but I also noticed a potential integer underflow
when formatting filenames in jit_repipe_code_move() and
jit_repipe_code_load().
tools/perf/util/jitdump.c:jit_repipe_code_move() {
[ ... ]
size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so", ...);
size++; /* for \0 */
[ ... ]
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) +
idr_size);
[ ... ]
}
If an untrusted jitdump file causes snprintf to truncate the filename (for
example by providing a long nspid or code_index), size will exceed PATH_MAX.
Would the subsequent calculation for event->mmap2.header.size undergo a double
integer underflow since both operands are unsigned size_t?
This mathematically reduces to sizeof(event->mmap2) - PATH_MAX + size + idr_size.
Because size > PATH_MAX, header.size strictly exceeds the size of the event
structure.
The id pointer is then calculated as event + header.size - idr_size, placing
it past the end of the dynamically allocated event buffer, which could lead to
an out-of-bounds heap write on id->pid and id->tid.
[Severity: High]
This isn't a bug introduced by this patch, but does cross-endian byte-swapping
of debug info entries incorrectly use fixed-size array indexing?
tools/perf/util/jitdump.c:jit_get_next_entry() {
[ ... ]
for (n = 0 ; n < jr->info.nr_entry; n++) {
jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
}
[ ... ]
}
Since struct debug_entry contains a flexible array member for the name, each
entry is variable in length. Will using standard array indexing ignore the
interleaved variable-length strings and cause the byte-swap operations to
stride incorrectly across the buffer, potentially writing out-of-bounds on
the heap?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=4
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load
2026-08-06 12:35 ` [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
@ 2026-08-06 12:56 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 12:56 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Missing total_size validation leads to integer underflow and massive memory corruption or crashes in debug/unwinding info parsing.
- [Critical] `jit_get_next_entry` fails to bound `nr_entry` and improperly uses array indexing on a variable-length struct, causing heap buffer overflows.
- [Critical] Unvalidated `nr_entry` in debug info leads to out-of-bounds heap accesses during ELF generation.
- [Critical] Truncation in `snprintf` without clamping causes integer underflow when calculating event size in `jit_repipe_code_move`, leading to out-of-bounds heap writes.
- [High] Missing `free(event)` causes a memory leak in `jit_repipe_code_move`.
- [High] Heap information leak into generated ELF file via unvalidated `unwinding_size`.
--
--- Patch [3]: [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load ---
commit 1f1a1ff66272152cc1c578445365c0049a6fa38d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Validate code_size against total_size in code load
This commit adds bounds checking for code_size in jit_repipe_code_load()
to prevent out-of-bounds heap reads during pointer arithmetic. It ensures
that code_size fits within the jitdump record's total_size and prevents
integer wrapping when cast to a signed int.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index dcb26d9c6c8fc..14bd23c8d1963 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
[ ... ]
> @@ -452,6 +453,16 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> csize = jr->load.code_size;
> usize = jd->unwinding_mapped_size;
> addr = jr->load.code_addr;
> +
> + /* code blob lives at the end of the record, validate it fits */
> + if (jr->load.p.total_size < sizeof(jr->load) ||
> + jr->load.code_size > jr->load.p.total_size - sizeof(jr->load) ||
> + jr->load.code_size > INT_MAX) {
> + pr_warning("jitdump: invalid code_size %" PRIu64 " (total_size=%u) in code_load record\n",
> + (uint64_t)jr->load.code_size, jr->load.p.total_size);
> + return -1;
> + }
> +
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
> code = (unsigned long)jr + jr->load.p.total_size - csize;
> count = jr->load.code_index;
[Severity: High]
This is a pre-existing issue, but I noticed a memory leak in
jit_repipe_code_move() when handling an untrusted file:
tools/perf/util/jitdump.c:jit_repipe_code_move() {
...
out:
perf_sample__exit(&sample);
return ret;
}
Does this code leak the dynamically allocated event buffer on this return
path?
[Severity: Critical]
This is a pre-existing issue, but there appears to be an integer underflow
risk when calculating allocation sizes in jit_repipe_unwinding_info() and
jit_repipe_debug_info():
tools/perf/util/jitdump.c:jit_repipe_unwinding_info() {
...
unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
unwinding_data = malloc(unwinding_data_size);
...
}
And similarly:
tools/perf/util/jitdump.c:jit_repipe_debug_info() {
...
sz = jr->prefix.total_size - sizeof(jr->info);
data = malloc(sz);
...
}
If a maliciously crafted record has a total_size smaller than the fixed header
size, could this subtraction underflow and cause a massive allocation and
subsequent out-of-bounds copy?
[Severity: Critical]
This is a pre-existing issue, but there might be a heap buffer overflow in
jit_get_next_entry() when byte-swapping entries:
tools/perf/util/jitdump.c:jit_get_next_entry() {
...
for (n = 0 ; n < jr->info.nr_entry; n++) {
jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
...
}
Since nr_entry is not bounds-checked against total_size, and struct debug_entry
contains a flexible array member, does standard array indexing here compute
misaligned pointers and write out-of-bounds of the allocated buffer?
[Severity: Critical]
This is a pre-existing issue, but the unvalidated nr_entry from debug info
seems to cause out-of-bounds access during ELF generation:
tools/perf/util/genelf_debug.c:jit_process_debug_info() {
...
for (i = 0; i < nr_debug_entries; i++) {
ent->addr = ent->addr - code_addr;
ent = debug_entry_next(ent);
}
...
}
If jd->nr_debug_entries is set from an attacker-controlled nr_entry without
verification, could this loop read out-of-bounds via strlen() in
debug_entry_next() and write out-of-bounds via ent->addr?
[Severity: Critical]
This is a pre-existing issue, but I see a risk of underflow in event size
calculation in jit_repipe_code_move() due to un-clamped snprintf length:
tools/perf/util/jitdump.c:jit_repipe_code_move() {
...
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
...
id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
if (jd->sample_type & PERF_SAMPLE_TID) {
id->pid = pid;
id->tid = tid;
...
}
Since snprintf returns the length that would have been written, if size exceeds
the filename buffer size, might the subtraction underflow and corrupt the event
header size?
Would this result in out-of-bounds pointer arithmetic for id and lead to
arbitrary heap writes?
[Severity: High]
This is a pre-existing issue, but there appears to be a heap information leak
into generated ELF files due to an unvalidated unwinding_size:
tools/perf/util/jitdump.c:jit_repipe_unwinding_info() {
...
jd->unwinding_size = jr->unwinding.unwinding_size;
...
}
tools/perf/util/genelf.c:jit_add_eh_frame_info() {
...
d->d_buf = unwinding;
d->d_type = ELF_T_BYTE;
d->d_size = unwinding_table_size;
...
}
If jd->unwinding_size is populated directly from an untrusted payload without
verification against the actual available size, can libelf read out-of-bounds
heap memory and leak it into the generated file?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=3
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load
2026-08-06 12:36 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
@ 2026-08-06 13:03 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 13:03 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Heap Buffer Overflow / Out-of-bounds Write in JIT event synthesis due to hardcoded sample ID struct.
- [High] Out-of-bounds Read / Information Leak in `jit_repipe_code_move` due to fixed 16-byte sample ID allocation.
--
--- Patch [11]: [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load ---
commit 6b4b582de49c92ce6528fb28a944ec4bfb31b834
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Validate sym string NUL-termination in code load
jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
If code_size equals total_size - sizeof(jr->load), the sym pointer
aliases the code blob with no NUL terminator, and strlen() scans past
the buffer into adjacent heap memory.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 5a3ea2681fb37..5898a7d8eb962 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -487,6 +487,13 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
>
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
> code = (unsigned long)jr + jr->load.p.total_size - csize;
> +
> + /* sym string lives between the load header and the code blob */
> + if (!memchr(sym, '\0', code - (unsigned long)sym)) {
> + pr_warning("jitdump: unterminated symbol name in code_load record\n");
> + return -1;
> + }
> +
> count = jr->load.code_index;
> idr_size = jd->machine->id_hdr_size;
>
[Severity: Critical]
This isn't a bug introduced by this patch, but I noticed a potential
out-of-bounds write later in jit_repipe_code_load() and
jit_repipe_code_move() when setting up the sample ID:
tools/perf/util/jitdump.c:jit_repipe_code_load() {
...
id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
if (jd->sample_type & PERF_SAMPLE_TID) {
id->pid = pid;
id->tid = tid;
}
if (jd->sample_type & PERF_SAMPLE_TIME)
id->time = convert_timestamp(jd, jr->load.p.timestamp);
...
}
The code casts the end of the event payload to a hardcoded struct layout.
If the session is recorded with PERF_SAMPLE_TIME but without PERF_SAMPLE_TID,
idr_size is 8 bytes.
The id pointer is placed 8 bytes before the end of the payload size, but
writing to id->time (at offset 8) will write exactly 8 bytes past the end of
the buffer.
Could this corrupt heap memory if the original filename is long enough to
maximize the event buffer?
[Severity: High]
This is also a pre-existing issue, but could this calculation in
jit_repipe_code_move() lead to an out-of-bounds read?
tools/perf/util/jitdump.c:jit_repipe_code_move() {
...
event = calloc(1, sizeof(*event) + 16);
...
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
...
}
The allocation hardcodes 16 bytes for the sample ID payload, but header.size
incorporates idr_size.
If the session was recorded with multiple sample attributes, idr_size can
exceed 16 bytes.
If the calculated header.size exceeds the allocated heap size, will
perf_data__write() read past the end of the buffer?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=11
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 01/12] perf jitdump: Fix extended header read that always fails
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
@ 2026-08-06 13:04 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 13:04 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing bounds checks for JIT records allow out-of-bounds memory accesses.
- [High] The error path for a failed malloc() calls funlockfile() on an un-locked FILE pointer.
--
--- Patch [1]: [PATCH 01/12] perf jitdump: Fix extended header read that always fails ---
commit dc8d1e17077d95aa9e9434ca752e0c0e9bb0e0de
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Fix extended header read that always fails
This commit fixes an issue in jit_open() where extended header bytes were
not being properly read. It separates the buffer reallocation from the
stream read, ensuring the extended header bytes are correctly consumed.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 83005b30b9bf3..4b7c7ba7cd95d 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
[ ... ]
[Severity: High]
This is a pre-existing issue, but I noticed a potential missing bounds check
in this file while reviewing.
In jit_repipe_code_load(), csize and sym are extracted without bounds checks
against total_size:
tools/perf/util/jitdump.c:jit_repipe_code_load() {
...
csize = jr->load.code_size;
...
sym = (void *)((unsigned long)jr + sizeof(jr->load));
code = (unsigned long)jr + jr->load.p.total_size - csize;
...
}
Could this allow code to point out-of-bounds if total_size is not validated
against the record size?
There seems to be a similar issue in jit_repipe_unwinding_info():
tools/perf/util/jitdump.c:jit_repipe_unwinding_info() {
...
unwinding_data_size = jr->prefix.total_size - sizeof(jr->unwinding);
unwinding_data = malloc(unwinding_data_size);
...
memcpy(unwinding_data, &jr->unwinding.unwinding_data,
unwinding_data_size);
...
}
If total_size is smaller than sizeof(jr->unwinding), could this underflow
unwinding_data_size and lead to a large allocation and an out-of-bounds
memcpy?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload
2026-08-06 12:36 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
@ 2026-08-06 13:06 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 13:06 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Out-of-bounds heap read and information leak in `jit_repipe_code_move()` due to undersized event allocation.
- [High] Memory/state leak and mapping corruption when `eh_frame_hdr_size` is 0.
--
--- Patch [12]: [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload ---
commit e53fcebef8f0cf9ec357ae7d5ca199498a47b1da
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Validate unwinding sizes against record payload
Validate that unwinding_size fits within the record payload and that
eh_frame_hdr_size does not exceed unwinding_size before allocating or
storing the values, so a bogus record cannot force a large allocation
that is then discarded. mapped_size is likewise taken from the record
and was narrowed into an int. Use uint64_t for usize so the value
cannot truncate.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 5898a7d8eb962..d25a9fe9b020c 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
[ ... ]
> @@ -543,7 +544,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
>
> event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
> event->mmap2.start = addr;
> - event->mmap2.len = usize ? ALIGN_8(csize) + usize : csize;
> + event->mmap2.len = usize ? ALIGN_8((uint64_t)csize) + usize : (uint64_t)csize;
[Severity: High]
This is a pre-existing issue, but is it possible for the unwinding state
to be leaked and corrupt subsequent event lengths?
Looking at jit_repipe_code_load() just above this assignment, we only
clean up the unwinding state if eh_frame_hdr_size is non-zero:
if (jd->unwinding_data && jd->eh_frame_hdr_size) {
zfree(&jd->unwinding_data);
jd->eh_frame_hdr_size = 0;
jd->unwinding_mapped_size = 0;
jd->unwinding_size = 0;
}
If a JIT runtime emits a record with eh_frame_hdr_size == 0, this check
fails. As a result, unwinding_mapped_size is not reset.
When processing the next JIT code load record, the stale unwinding_mapped_size
is pulled into the usize variable and added to event->mmap2.len here.
Could this inflate the mapping size and cause collisions in the perf mapping
tree, corrupting the stack trace unwinding process?
> event->mmap2.pid = pid;
> event->mmap2.tid = tid;
> event->mmap2.ino = st.st_ino;
[ ... ]
> @@ -612,7 +613,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
> char *filename;
> size_t size;
> struct stat st;
> - int usize;
> + uint64_t usize;
> u16 idr_size;
[Severity: High]
This is a pre-existing issue, but does the event allocation in
jit_repipe_code_move() leave room for a buffer over-read?
The event buffer is allocated with a hardcoded +16 padding:
event = calloc(1, sizeof(*event) + 16);
However, later in the same function, the header size incorporates idr_size:
event->mmap2.header.size = (sizeof(event->mmap2) -
(sizeof(event->mmap2.filename) - size) + idr_size);
If idr_size (derived from the PERF_SAMPLE_* format) is greater than 16 bytes,
header.size could exceed the allocated chunk size.
If perf_data__write() later reads header.size bytes, could this cause an
out-of-bounds heap read and leak uninitialized heap memory into the output
perf.data file?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=12
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path
2026-08-06 12:36 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
@ 2026-08-06 13:10 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-08-06 13:10 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Iterating over `struct debug_entry` with `debug_entry_next()` produces unaligned pointers, causing undefined behavior and hardware exceptions (SIGBUS) on strict-alignment architectures.
- [Medium] Parsing errors in JIT dump records are silently ignored in `jit_process_dump()`, leaving stale debug and unwinding data active and overwriting error return codes.
- [Medium] `jit_repipe_code_move()` processes `JIT_CODE_MOVE` records without verifying that the record's `total_size` is large enough to contain the struct, leading to uninitialized heap memory reads.
--
--- Patch [10]: [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path ---
commit f31dd5de27938e11279a2fce6356aeba4e9918b4
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Validate debug entries on native (non-swap) path
The bounds-checking and nr_entry clamping added for the byte-swap path
only runs when jd->needs_bswap is true. This patch adds bounds-checked
iteration in jit_repipe_debug_info() to validate each debug_entry fits in
the payload.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index d3de307532d55..5a3ea2681fb37 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -694,8 +694,10 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
[Severity: Medium]
This is a pre-existing issue, but does jit_repipe_code_move() process
JIT_CODE_MOVE records without verifying that the record's total_size is
large enough to contain the struct?
If a malformed JIT_CODE_MOVE record specifies a small total_size, fread()
might read 0 bytes, leaving the jr->move fields mapped to uninitialized
bytes in jd->buf. Could this cause uninitialized heap memory to be read,
byte-swapped in jit_get_next_entry(), and written to the output perf.data
file?
>
> static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
> {
> - void *data;
> - size_t sz;
> + struct debug_entry *ent;
> + void *data, *end;
> + size_t sz, valid;
> + uint64_t i;
[ ... ]
> /*
> - * we must use nr_entry instead of size here because
> - * we cannot distinguish actual entry from padding otherwise
> + * Clamp nr_debug_entries to entries that actually fit in the
> + * payload. The byte-swap path already does this for cross-endian
> + * files; validate on the native path too, since downstream
> + * jit_process_debug_info() iterates via debug_entry_next() which
> + * calls strlen() on each entry's name field.
> */
> - jd->nr_debug_entries = jr->info.nr_entry;
> + end = data + sz;
> + ent = data;
> + valid = 0;
> + for (i = 0; i < jr->info.nr_entry; i++) {
> + if ((void *)ent + sizeof(*ent) > end)
> + break;
> + /* name must be NUL-terminated within the payload */
> + if (!memchr(ent->name, '\0', (char *)end - ent->name))
> + break;
> + ent = debug_entry_next(ent);
[Severity: High]
This isn't a bug introduced by this patch, but does debug_entry_next()
produce unaligned pointers here?
Because struct debug_entry contains 64-bit and 32-bit fields but lacks
__attribute__((packed)), the compiler emits 8-byte aligned memory accesses.
Since the variable-length string does not pad to 8-byte boundaries,
subsequent entries appear to become naturally unaligned in memory.
When downstream code dereferences these fields, such as:
tools/perf/util/genelf_debug.c:jit_process_debug_info() {
...
ent->addr = ent->addr - code_addr;
...
}
could this perform unaligned 64-bit loads and stores, triggering hardware
alignment faults (SIGBUS) on strict-alignment architectures?
> + valid++;
> + }
> + jd->nr_debug_entries = valid;
>
> return 0;
> }
[Severity: Medium]
This is a pre-existing issue, but are the error codes returned by this
function silently ignored by its caller?
In jit_process_dump():
tools/perf/util/jitdump.c:jit_process_dump() {
...
ret = jit_repipe_debug_info(jd, jr);
...
default:
ret = 0;
continue;
}
If jit_repipe_debug_info() returns -1 (e.g., due to OOM), the while loop
doesn't seem to break. If a subsequent unrecognized record or JIT_CODE_CLOSE
triggers the default case, ret is overwritten to 0. Does this successfully
hide the parse failure and leave stale debug data active?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=10
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop
2026-08-06 12:51 ` sashiko-bot
@ 2026-08-06 15:21 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 15:21 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-perf-users
On Thu, Aug 06, 2026 at 12:51:56PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
>
> New issues:
> - [Medium] Replacing array indexing with sequential pointer arithmetic (`debug_entry_next`) on unpadded, variable-length structures results in unaligned struct pointers, causing undefined behavior and SIGBUS crashes on strict-alignment architectures.
This is something bigger, the proper fix needs research, the TODO entry
#154 notes we must confirm the JDK/Mono/V8 jitdump writers actually pad
entries to 8-byte boundaries before choosing between get_unaligned and
ALIGN() — that's next-series work.
- Arnaldo
> Pre-existing issues:
> - [Critical] The newly added bounds checking and `nr_entry` clamping for `JIT_CODE_DEBUG_INFO` records are scoped exclusively inside the `if (jd->needs_bswap)` block, leaving native-endian files completely vulnerable to a massive heap buffer overflow.
> - [High] Missing validation of `unwinding_size` against `unwinding_data_size` in `JIT_CODE_UNWINDING_INFO` leads to an out-of-bounds read during ELF generation.
> - [Medium] The `event` buffer is leaked on all return paths in `jit_repipe_code_move()`.
> - [Medium] `jit_repipe_code_move` fails to validate that the record's `total_size` is large enough to contain the `jr_code_move` payload, leading to the processing of uninitialized memory.
> --
>
> --- Patch [5]: [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop ---
> commit 14beafbf2609e41d04f4020f064d84fdbb15c5a7
> Author: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> perf jitdump: Bounds-check debug entry byte-swap loop
>
> This commit replaces array indexing with pointer arithmetic and adds bounds
> checking for JIT_CODE_DEBUG_INFO records during byte-swapping to prevent
> out-of-bounds reads.
>
> > diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> > index f79e9420c6bd7..7efbaa07f1ba7 100644
> > --- a/tools/perf/util/jitdump.c
> > +++ b/tools/perf/util/jitdump.c
> > @@ -320,14 +320,32 @@ jit_get_next_entry(struct jit_buf_desc *jd)
> > switch(id) {
> > case JIT_CODE_DEBUG_INFO:
> > if (jd->needs_bswap) {
> > + void *end = (void *)jr + jr->prefix.total_size;
> > + struct debug_entry *ent;
> > uint64_t n;
> > +
> > jr->info.code_addr = bswap_64(jr->info.code_addr);
> > jr->info.nr_entry = bswap_64(jr->info.nr_entry);
> > - for (n = 0 ; n < jr->info.nr_entry; n++) {
> > - jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
> > - jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
> > - jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
> > +
> > + /*
> > + * debug_entry has a variable-length name[], so array
> > + * indexing would compute wrong offsets — use
> > + * debug_entry_next() and bounds-check each entry.
> > + */
> > + ent = &jr->info.entries[0];
> > + for (n = 0; n < jr->info.nr_entry; n++) {
> > + if ((void *)ent + sizeof(*ent) > end)
> > + break;
>
> [Severity: Critical]
> This is a pre-existing issue, but by placing the bounds checking and
> nr_entry clamping exclusively inside the if (jd->needs_bswap) block,
> native-endian files bypass this validation completely.
>
> If a maliciously crafted JIT dump file with a native endianness matching the
> host provides an arbitrarily large untrusted nr_entry count for a
> JIT_CODE_DEBUG_INFO record, this path is skipped.
>
> Later in the processing, this unvalidated value is assigned directly:
>
> tools/perf/util/jitdump.c:jit_repipe_debug_info()
> jd->nr_debug_entries = jr->info.nr_entry;
>
> And then blindly iterated over on the heap:
>
> tools/perf/util/genelf_debug.c:jit_process_debug_info()
> for (i = 0; i < nr_debug_entries; i++) {
> ent->addr = ent->addr - code_addr;
> ent = debug_entry_next(ent);
> }
>
> Could we move the bounds validation outside of the byte-swapping block so all
> inputs are checked?
>
> > + /* name must be NUL-terminated within the record */
> > + if (!memchr(ent->name, '\0', (char *)end - ent->name))
> > + break;
> > + ent->addr = bswap_64(ent->addr);
> > + ent->lineno = bswap_32(ent->lineno);
> > + ent->discrim = bswap_32(ent->discrim);
> > + ent = debug_entry_next(ent);
>
> [Severity: Medium]
> Does this unpadded sequential pointer arithmetic lead to unaligned memory
> accesses?
>
> struct debug_entry contains 64-bit and 32-bit fields, requiring 8-byte
> alignment, but it is not __packed. The debug_entry_next() helper calculates
> the next entry's address by adding the length of the string:
>
> tools/perf/util/jitdump.h:debug_entry_next()
> void *a = ent + 1;
> size_t l = strlen(ent->name) + 1;
> return a + l;
>
> This leaves the pointer unaligned. When the byte-swapping loop uses
> ent = debug_entry_next(ent) and accesses ent->addr = bswap_64(ent->addr),
> the compiler generates aligned load/store instructions for an unaligned
> address, leading to SIGBUS crashes on strict-alignment architectures.
>
> > }
> > + /* clamp so downstream consumers don't overrun */
> > + jr->info.nr_entry = n;
> > }
> > break;
> > case JIT_CODE_UNWINDING_INFO:
> > if (jd->needs_bswap) {
> > jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size);
>
> [Severity: High]
> This is a pre-existing issue, but is the unwinding_size validated against the
> actual payload size?
>
> In jit_repipe_unwinding_info(), the unwinding size is saved directly from the
> payload without validation against the allocated heap buffer size:
>
> tools/perf/util/jitdump.c:jit_repipe_unwinding_info()
> jd->unwinding_size = jr->unwinding.unwinding_size;
>
> This unvalidated size is later passed to libelf:
>
> tools/perf/util/genelf.c:jit_add_eh_frame_info()
> d->d_size = unwinding_table_size;
>
> A crafted record with a small total_size but a huge unwinding_size could
> cause libelf to read out-of-bounds heap memory and embed it into the output
> ELF, leading to an information leak.
>
> > jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size);
> > jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size);
> > }
> > break;
>
> While reviewing this patch, I also noticed a couple of pre-existing issues
> in the handling of JIT_CODE_MOVE records:
>
> tools/perf/util/jitdump.c:jit_repipe_code_move()
> [ ... ]
> > nspid = jr->load.pid;
> > pid = jr_entry_pid(jd, jr);
>
> [Severity: Medium]
> This isn't a bug introduced by this patch, but does jit_repipe_code_move()
> validate that the record's total_size is large enough to contain the
> jr_code_move payload?
>
> If a malformed record is provided with a truncated total_size, fread() will
> read only a partial record into jd->buf. The remaining fields will be
> uninitialized or contain leftover data, which are then used to construct
> the perf event.
>
> [ ... ]
> > event = calloc(1, sizeof(*event) + 16);
> > if (!event)
> > return -1;
> [ ... ]
> > ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
> > if (ret)
> > goto out;
> >
> > ret = jit_inject_event(jd, event);
> > if (!ret)
> > build_id__mark_dso_hit(tool, event, &sample, jd->machine);
> > out:
> > perf_sample__exit(&sample);
> > return ret;
>
> [Severity: Medium]
> This is a pre-existing issue, but does this leak the event buffer?
>
> The memory for event is allocated via calloc() and the function returns at
> the out: label without calling free(event). Neither of the processing
> functions take ownership of the memory, so the buffer appears to be leaked on
> every JIT_CODE_MOVE record.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=5
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-08-06 15:21 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
2026-08-06 13:04 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
2026-08-06 12:56 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
2026-08-06 12:55 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 15:21 ` Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 06/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
2026-08-06 12:49 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
2026-08-06 12:36 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
2026-08-06 13:10 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
2026-08-06 13:03 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
2026-08-06 13:06 ` sashiko-bot
-- strict thread matches above, loose matches on Subject: below --
2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-05 21:27 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
2026-08-05 21:51 ` sashiko-bot
2026-08-05 13:29 [PATCHES v1 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-05 13:30 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
2026-08-05 19:19 ` Ian Rogers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox