Linux Perf Users
 help / color / mirror / Atom feed
* [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; 26+ 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] 26+ 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; 26+ 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] 26+ messages in thread

* [PATCHES v2 0/12] perf jitdump: Input validation hardening
@ 2026-08-05 21:26 Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
                   ` (11 more replies)
  0 siblings, 12 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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, Stephane Eranian, Stefano Sanfilippo

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 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: 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: Fix debug_data and unwinding_data leaks
  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

Arnaldo Carvalho de Melo (12):
  perf jitdump: Fix extended header read that always fails
  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: Fix debug_data and unwinding_data leaks
  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(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 01/12] perf jitdump: Fix extended header read that always fails
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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] 26+ messages in thread

* [PATCH 02/12] perf jitdump: Validate code_size against total_size 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:26 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:42   ` sashiko-bot
  2026-08-05 21:26 ` [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 4b7c7ba7cd95ddbb..3195f94187164066 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>
@@ -450,6 +451,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] 26+ messages in thread

* [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:46   ` sashiko-bot
  2026-08-05 21:26 ` [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 3195f94187164066..787f8a03dae87908 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -669,6 +669,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)
@@ -696,6 +700,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] 26+ messages in thread

* [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (2 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:40   ` sashiko-bot
  2026-08-05 21:26 ` [PATCH 05/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 787f8a03dae87908..078d3304d2b7ebce 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -318,14 +318,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] 26+ messages in thread

* [PATCH 05/12] perf jitdump: Check snprintf return before computing header size
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (3 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:40   ` sashiko-bot
  2026-08-05 21:26 ` [PATCH 06/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 078d3304d2b7ebce..d7e3dcfc63b78edb 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -493,6 +493,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 */
 
@@ -623,6 +626,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] 26+ messages in thread

* [PATCH 06/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (4 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 05/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 07/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 d7e3dcfc63b78edb..e865a43f6ea8f884 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -155,7 +155,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
@@ -244,8 +244,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] 26+ messages in thread

* [PATCH 07/12] perf jitdump: Free event in jit_repipe_code_move()
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (5 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 06/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 08/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 e865a43f6ea8f884..f3d9a2b01053a92b 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -683,6 +683,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] 26+ messages in thread

* [PATCH 08/12] perf jitdump: Fix debug_data and unwinding_data leaks
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (6 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 07/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:26 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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 f3d9a2b01053a92b..91aa1eea8229faac 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -118,6 +118,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
@@ -706,6 +708,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] 26+ messages in thread

* [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open()
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (7 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 08/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
@ 2026-08-05 21:26 ` Arnaldo Carvalho de Melo
  2026-08-05 21:45   ` sashiko-bot
  2026-08-05 21:27 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-05 21:26 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] 26+ messages in thread

* [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (8 preceding siblings ...)
  2026-08-05 21:26 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
@ 2026-08-05 21:27 ` Arnaldo Carvalho de Melo
  2026-08-05 22:00   ` sashiko-bot
  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:27 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
  11 siblings, 1 reply; 26+ 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>

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] 26+ 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
                   ` (9 preceding siblings ...)
  2026-08-05 21:27 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
@ 2026-08-05 21:27 ` Arnaldo Carvalho de Melo
  2026-08-05 21:51   ` sashiko-bot
  2026-08-05 21:27 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
  11 siblings, 1 reply; 26+ 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] 26+ messages in thread

* [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload
  2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
                   ` (10 preceding siblings ...)
  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:27 ` Arnaldo Carvalho de Melo
  2026-08-05 21:53   ` sashiko-bot
  11 siblings, 1 reply; 26+ 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, 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] 26+ messages in thread

* Re: [PATCH 05/12] perf jitdump: Check snprintf return before computing header size
  2026-08-05 21:26 ` [PATCH 05/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
@ 2026-08-05 21:40   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:40 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] In `jit_repipe_code_move`, an out-of-bounds heap read occurs when the required event size exceeds the allocated buffer, leaking heap memory into the `perf.data` file.
- [High] The dynamically allocated `event` buffer in `jit_repipe_code_move` is never freed, resulting in a memory leak.
- [Medium] The JIT event injection logic violates the perf ABI's dynamic packing rules for the `sample_id_all` suffix, leading to event data corruption.
- [Medium] The `uint64_t` variable `jd->unwinding_mapped_size` is silently truncated to a 32-bit signed `int`, potentially corrupting the event length.
--

--- Patch [5]: [PATCH 05/12] perf jitdump: Check snprintf return before computing header size ---
commit ec3758fe10c5b2ae1b52a849ea060531bfeec315
Author: Arnaldo Carvalho de Melo <acme@redhat.com>

    perf jitdump: Check snprintf return before computing header size

This commit fixes a heap corruption in the jitdump mmap injection code.
It clamps the return value of snprintf to the filename buffer size in both
jit_repipe_code_load() and jit_repipe_code_move() to prevent oversized
header computations when the jitted filename exceeds PATH_MAX.

> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 078d3304d2b7e..d7e3dcfc63b78 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -493,6 +493,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 */
>  

[Severity: Medium]
This is a pre-existing issue, but does the sample ID injection in
jit_repipe_code_load() violate the dynamic packing rules for the sample_id_all
suffix?

The code casts the suffix payload to a static struct and unconditionally writes
the timestamp at offset 8:

	struct {
		u32 pid, tid;
		u64 time;
	} *id;
...
	if (jd->sample_type & PERF_SAMPLE_TIME)
		id->time = convert_timestamp(jd, jr->load.p.timestamp);

If PERF_SAMPLE_TID is disabled but PERF_SAMPLE_TIME is present, shouldn't the
timestamp be placed at offset 0?

Leaving offset 0 uninitialized and forcing the timestamp into offset 8 could
corrupt the parsed timestamp and subsequent fields.

[Severity: Medium]
This is also a pre-existing issue, but does jit_repipe_code_load() silently
truncate the 64-bit unwinding mapped size?

The function assigns a uint64_t from the untrusted jitdump file to a signed
32-bit int:

	int ret, csize, usize;
...
	usize = jd->unwinding_mapped_size;

If the mapped_size is larger than INT_MAX, wouldn't this truncate into a
negative value?

This could then be added to the code size to compute event->mmap2.len, causing
unintended subtraction or massive wraparound.

> @@ -623,6 +626,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: High]
This isn't a bug introduced by this patch, but does jit_repipe_code_move()
have an out-of-bounds heap read when calculating the event size?

The event buffer is allocated with a hardcoded size:

	event = calloc(1, sizeof(*event) + 16);

But the header.size is dynamically computed using idr_size:

	event->mmap2.header.size = (sizeof(event->mmap2) - (sizeof(event->mmap2.filename) - size) + idr_size);

Since idr_size can be up to 64 bytes depending on the active sample_type, the
calculated header.size can exceed the allocated buffer by up to 48 bytes.

When perf_data__write() is later called in jit_inject_event(), couldn't this
read past the end of the allocation and leak heap memory into the perf.data
file?

[Severity: Medium]
This is a pre-existing issue, but does jit_repipe_code_move() also suffer from
the same dynamic packing violation as jit_repipe_code_load()?

The same static struct layout is used for the sample ID fields:

	struct {
		u32 pid, tid;
		u64 time;
	} *id;
...
	if (jd->sample_type & PERF_SAMPLE_TIME)
		id->time = convert_timestamp(jd, jr->load.p.timestamp);

This appears to corrupt the event data if PERF_SAMPLE_TID is disabled.

[Severity: High]
This is a pre-existing issue, but does jit_repipe_code_move() leak the event
buffer?

The buffer is dynamically allocated, but the function appears to return without
freeing it:

	event = calloc(1, sizeof(*event) + 16);
	if (!event)
		return -1;
...
out:
	perf_sample__exit(&sample);
	return ret;

Since a jitdump file can contain thousands of code move events, wouldn't this
consume significant memory and potentially lead to out-of-memory errors during
processing?

[Severity: Medium]
This is a pre-existing issue, but does jit_repipe_code_move() also truncate the
unwinding mapped size into a 32-bit integer?

Just like in jit_repipe_code_load(), the size is assigned to an int:

	int usize;
...
	usize = jd->unwinding_mapped_size;

Could this cause the same event length corruption if the mapped_size exceeds
INT_MAX?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=5

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop
  2026-08-05 21:26 ` [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
@ 2026-08-05 21:40   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:40 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] The newly added bounds-checking and string NUL-termination validation for debug entries are isolated within the `if (jd->needs_bswap)` block. For native-endian files, validation is bypassed, leaving out-of-bounds heap read/write vulnerabilities unmitigated.
--

--- Patch [4]: [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop ---
commit b0b40e7a47c677d680f97fb1312ed129f617d651
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 for debug_entry
structures in the JIT_CODE_DEBUG_INFO byte-swap loop to handle
variable-length names. It also adds bounds checking against total_size to
prevent out-of-bounds reads.

> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 787f8a03dae87..078d3304d2b7e 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c

[ ... ]

> @@ -318,14 +318,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;

[Severity: High]
This is a pre-existing issue, but by keeping the new bounds-checking and
clamping logic exclusively inside the if (jd->needs_bswap) block, doesn't
this leave native-endian files unvalidated?

For a native-endian file, jd->needs_bswap is false, so jr->info.nr_entry
bypasses this clamping in jit_get_next_entry(). Later in
tools/perf/util/jitdump.c, it is assigned directly:

jit_repipe_debug_info() {
    ...
    jd->nr_debug_entries = jr->info.nr_entry;
    ...
}

This unvalidated count is then used in 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 the number of entries is artificially inflated, or if NUL terminators are
missing, could this lead to out-of-bounds reads and writes in
jit_process_debug_info() when processing a native-endian jitdump file?

Should the entry validation and clamping logic be pulled out of the
jd->needs_bswap block so it applies to all files regardless of endianness?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load
  2026-08-05 21:26 ` [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
@ 2026-08-05 21:42   ` sashiko-bot
  2026-08-06 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:42 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users

Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:

New issues:
- [Medium] jd->debug_data and jd->unwinding_data are leaked on the new validation failure path.

Pre-existing issues:
- [High] Integer underflow when calculating unwinding_data_size in jit_repipe_unwinding_info leads to a massive heap allocation and out-of-bounds read.
- [High] Missing snprintf truncation clamping in jit_repipe_code_move and jit_repipe_code_load leads to an undersized event allocation calculation and out-of-bounds heap write.
- [High] jit_get_next_entry iterates over an unvalidated nr_entry array using fixed-size indexing for a variable-length structure, leading to out-of-bounds byte-swapping.
- [High] The parser lacks total_size boundary checks for JIT_CODE_MOVE, leading to uninitialized heap reads.
- [High] Lack of validation between buffer size and nr_entry leads to heap OOB read and write in debug info parsing.
- [Medium] The perf_event allocated via calloc is unconditionally leaked in jit_repipe_code_move.
- [Medium] Multiple memory leaks of dynamically allocated buffers in the jitdump parser, including missing cleanup in jit_close and overwrites in debug info.
- [Medium] The ALIGN_8 macro evaluates using signed arithmetic, causing integer wrap and massive length corruption for mmap2 events.
- [Medium] Truncation of 64-bit unwinding_mapped_size to 32-bit int can corrupt mmap2 event length.
--

--- Patch [2]: [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load ---
commit 97b091976e049b90397f99d555b22a4934abb49d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>

perf jitdump: Validate code_size against total_size in code load

This commit introduces validation checks to ensure that the code_size
does not exceed the available size in the JIT load record. It adds bounds
checking to prevent out-of-bounds heap reads when calculating the code
blob pointer.

> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 4b7c7ba7cd95d..3195f94187164 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>
> @@ -450,6 +451,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;

[Severity: Medium]
Does this early return skip freeing the buffered debug and unwinding data?

Later in the function, these dynamically allocated buffers are freed:

    if (jd->debug_data && jd->nr_debug_entries) {
            zfree(&jd->debug_data);
            jd->nr_debug_entries = 0;
    }

    if (jd->unwinding_data && jd->eh_frame_hdr_size) {
            zfree(&jd->unwinding_data);
            ...

If the code returns -1 here, do jd->debug_data and jd->unwinding_data remain
allocated, permanently leaking since jit_close() does not appear to clean them
up?

> +	}
> +
>  	sym   = (void *)((unsigned long)jr + sizeof(jr->load));
>  	code  = (unsigned long)jr + jr->load.p.total_size - csize;
>  	count = jr->load.code_index;

[ ... ]

Other findings in this file:

[Severity: High]
This is a pre-existing issue, but does integer underflow occur when calculating
unwinding_data_size 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), does the unsigned 32-bit
subtraction underflow to a massive value, causing malloc to allocate too much
memory and memcpy to perform an out-of-bounds read?


[Severity: Medium]
This is a pre-existing issue, but is the perf_event leaked in
jit_repipe_code_move()?

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    event = calloc(1, sizeof(*event) + 16);
    if (!event)
        return -1;
    ...
    return ret;
}

The event pointer is allocated via calloc but is never freed on the success
or error return paths. Does this gradually exhaust memory when parsing large
dumps?


[Severity: High]
This is a pre-existing issue, but does missing snprintf truncation clamping
lead to out-of-bounds heap writes?

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);
    ...
}

When generating the filename, snprintf returns the length that would have
been written. If this exceeds PATH_MAX, does the returned size wrap in the
unsigned arithmetic for header.size, underflowing it and pushing the trailing
id pointer out of the allocated event buffer bounds?


[Severity: Medium]
This is a pre-existing issue, but are dynamic buffers repeatedly leaked in
jit_repipe_debug_info() and jit_close()?

tools/perf/util/jitdump.c:jit_repipe_debug_info() {
    ...
    data = malloc(sz);
    /* ... */
    jd->debug_data       = data;
    ...
}

Repeated JIT_CODE_DEBUG_INFO records will malloc a new buffer and overwrite
jd->debug_data without freeing the old one. Additionally, jit_close() frees
the jd struct resources but does not seem to clean up internal heap buffers
like debug_data and unwinding_data. Does this leave them un-freed
indefinitely?


[Severity: High]
This is a pre-existing issue, but does standard array indexing on a variable
length struct cause memory corruption during bswap?

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);
    ...
}

In cross-endian mode, this iterates over an unvalidated nr_entry array using
fixed-size indexing. Since debug_entry includes a variable-length name[]
string inline, doesn't fixed-size array indexing read from and byte-swap
completely incorrect offsets?


[Severity: High]
This is a pre-existing issue, but does jit_repipe_code_move() lack boundary
checks for the JIT_CODE_MOVE total_size?

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    event->mmap2.start = jr->move.new_code_addr;
    event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize : jr->move.code_size;
    ...
}

Unlike the new validation added to JIT_CODE_LOAD in this patch,
jit_repipe_code_move() lacks a check confirming that total_size is greater
than or equal to sizeof(jr->move). Can malformed records cause the parser
to read uninitialized heap or stale data from jd->buf into perf.data?


[Severity: Medium]
This is a pre-existing issue, but does the ALIGN_8 macro silently overflow
into a negative value?

tools/perf/util/jitdump.c:jit_repipe_code_load() {
    ...
    int ret, csize, usize;
    /* ... */
    event->mmap2.len   = usize ? ALIGN_8(csize) + usize : csize;
    ...
}

Since csize is typed as a signed int, does calculating ALIGN_8(csize) with a
value near INT_MAX trigger signed integer overflow to a negative value, which
is then sign-extended into a corrupted uint64_t length?


[Severity: Medium]
This is a pre-existing issue, but can the truncation of unwinding_mapped_size
corrupt the mmap2 event length?

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    int usize;
    /* ... */
    usize = jd->unwinding_mapped_size;
    /* ... */
    event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize : jr->move.code_size;
    ...
}

The 64-bit jd->unwinding_mapped_size is truncated to a 32-bit signed integer
(usize). Could a maliciously crafted mapped_size result in a negative or
truncated value, corrupting the final event->mmap2.len?


[Severity: High]
This is a pre-existing issue, but does the lack of validation between buffer
size and nr_entry lead to heap out-of-bounds reads and writes?

tools/perf/util/jitdump.c:jit_repipe_debug_info() {
    ...
    jd->nr_debug_entries = jr->info.nr_entry;
    ...
}

The parser sets jd->nr_debug_entries from the unvalidated nr_entry file field
without confirming the allocated sz bytes can accommodate them. When
jit_process_debug_info() loops nr_entry times calling strlen on heap data,
does this result in out-of-bounds heap writes?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=2

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open()
  2026-08-05 21:26 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
@ 2026-08-05 21:45   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:45 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] Missing bounds checking and validation of JIT_CODE_DEBUG_INFO when architecture endianness matches.
- [High] Missing validation of unwinding record sizes allows heap information leaks into generated ELF files.
- [High] Missing NUL-termination check for symbol name in JIT_CODE_LOAD.
--

--- Patch [9]: [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() ---
commit b82fdc2ff8228d697093005adb380338825bb2dd
Author: Arnaldo Carvalho de Melo <acme@redhat.com>

perf jitdump: Use dirname() return value in jit_open()
    
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.

> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 91aa1eea8229f..d3de307532d55 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;

[Severity: High]
This is a pre-existing issue, but is it possible to corrupt memory when
processing JIT_CODE_DEBUG_INFO?

In tools/perf/util/jitdump.c:jit_get_next_entry(), the bounds-checking
logic is only executed if the host and file endianness differ:

    case JIT_CODE_DEBUG_INFO:
        if (jd->needs_bswap) { ... }

If they share the same endianness, this check is skipped. Then, in
tools/perf/util/genelf_debug.c:jit_process_debug_info(), the code iterates
blindly using the untrusted nr_debug_entries:

    for (i = 0; i < nr_debug_entries; i++) {
        ent->addr = ent->addr - code_addr;
        ent = debug_entry_next(ent);
    }

Could a maliciously crafted jitdump file with an artificially large
nr_entry cause an out-of-bounds heap write here?

[Severity: High]
This is a pre-existing issue, but does this code leak heap information
into the generated ELF files?

In tools/perf/util/jitdump.c:jit_repipe_unwinding_info(), internal
structure sizes are read without validating them against the record
payload length:

    jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
    jd->unwinding_size = jr->unwinding.unwinding_size;

Later, in tools/perf/util/genelf.c:jit_add_eh_frame_info(), these
unvalidated sizes are used to compute offsets:

    uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
    ...
    d->d_buf = unwinding + unwinding_table_size;

If unwinding_size exceeds the payload, could this instruct libelf to read
adjacent heap memory? Furthermore, if unwinding_size is less than
unwinding_header_size, could unwinding_table_size underflow and cause
out-of-bounds pointer arithmetic?

[Severity: High]
This is a pre-existing issue, but is there a missing NUL-termination check
for the symbol name?

In tools/perf/util/jitdump.c:jit_repipe_code_load(), the string pointer is
calculated directly from the payload:

    sym   = (void *)((unsigned long)jr + sizeof(jr->load));

When this is passed to tools/perf/util/genelf.c:jit_write_elf(), it
calculates the length:

    symlen = 2 + strlen(sym);

If the symbol name payload lacks a NUL terminator, will strlen() read past
the end of the heap allocation and crash the process?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=9

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation
  2026-08-05 21:26 ` [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
@ 2026-08-05 21:46   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-perf-users

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

Pre-existing issues:
- [High] Cross-endian byte-swapping in `jit_get_next_entry()` lacks bounds checks for specific record types and incorrectly indexes variable-sized structures, causing out-of-bounds memory corruption.
- [High] Missing size validation for `JIT_CODE_MOVE` records allows uninitialized heap memory to be read and injected into synthesized perf events.
- [High] Missing validation of attacker-controlled sizes in `jit_repipe_unwinding_info` allows a massive out-of-bounds heap read when generating ELF files.
- [High] Missing NUL-termination check for the 'sym' string in `jit_repipe_code_load` allows an out-of-bounds read and heap info leak.
- [Medium] `jit_process_dump()` silently ignores parser errors and continues processing, which can hide corruption and cause downstream semantic bugs.
- [Medium] Buffers `jd->debug_data` and `jd->unwinding_data` are leaked during `jit_process` teardown and when record metadata contains zero-counts.
- [Medium] Calling `funlockfile()` on `jd->in` in the `jit_open()` error path before successfully locking it invokes undefined behavior.
--

--- Patch [3]: [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation ---
commit c2cf5f4eefed4933a21b8a0b0ee0587c371dd92d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>

perf jitdump: Prevent integer underflow in debug info size calculation

Prevent integer underflow by checking if total_size covers the fixed header
size in jit_repipe_debug_info and jit_repipe_unwinding_info.

> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> index 3195f94187164..787f8a03dae87 100644
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -669,6 +669,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)
> @@ -696,6 +700,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 is a pre-existing issue, but could we also validate the unwinding sizes
extracted here?

In jit_repipe_unwinding_info():

    jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
    jd->unwinding_size = jr->unwinding.unwinding_size;

These sizes are extracted without validation against the allocated payload size.

Later, in jit_add_eh_frame_info() in tools/perf/util/genelf.c:

    uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
    ...
    d->d_size = unwinding_table_size;

Could this unvalidated unwinding_size allow libelf to read out-of-bounds heap
memory and embed it in the generated ELF file?


[Severity: High]
This is a pre-existing issue, but does cross-endian byte-swapping in
jit_get_next_entry() lack bounds checks for specific record types?

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);
    ...
}

Because struct debug_entry contains a flexible array member (const char name[]),
doesn't standard array[n] indexing calculate the wrong offsets (skipping exactly
16 bytes and ignoring the string payload)?

Could this cause bswap_64 and bswap_32 to read from and write to unintended
out-of-bounds memory locations, especially since nr_entry itself is never
validated against the payload size?


[Severity: High]
This isn't a bug introduced by this patch, but does jit_repipe_code_move()
miss size validation for JIT_CODE_MOVE records?

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    event->mmap2.start = jr->move.new_code_addr;
    event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize
                               : jr->move.code_size;
    event->mmap2.pid   = pid;
    ...
}

If a truncated JIT_CODE_MOVE record is processed where total_size is smaller
than sizeof(struct jr_code_move), jit_get_next_entry() only reads total_size
bytes.

Does this unconditionally access uninitialized heap memory and inject it into
synthesized perf events?


[Severity: Medium]
This is a pre-existing issue, but does jit_process_dump() silently ignore
parser errors?

tools/perf/util/jitdump.c:jit_process_dump() {
    ...
    while ((jr = jit_get_next_entry(jd))) {
        switch(jr->prefix.id) {
        case JIT_CODE_LOAD:
            ret = jit_repipe_code_load(jd, jr);
    ...
}

If a handler like jit_repipe_debug_info returns -1, the return value is
assigned to ret, but the while loop does not break.

Could this continue processing subsequent records, overwriting ret, and
silently hide the corruption?


[Severity: Medium]
This isn't a bug introduced by this patch, but does jit_process() leak
jd->debug_data and jd->unwinding_data during teardown?

tools/perf/util/jitdump.c:jit_process() {
    ...
    nsinfo__put(jd.nsi);
    free(jd.buf);
    return ret;
}

These buffers are dynamically allocated during parsing. If the JIT dump trace
ends immediately after a debug or unwinding record, or if parsing aborts, the
stack-allocated jd context is destroyed without freeing these buffers.

Additionally, in jit_repipe_code_load():

    if (jd->debug_data && jd->nr_debug_entries) {
        zfree(&jd->debug_data);

Is it possible to skip zfree if jd->nr_debug_entries == 0, leaking the active
allocation?


[Severity: Medium]
This is a pre-existing issue, but does jit_open() invoke undefined behavior on
the error path?

tools/perf/util/jitdump.c:jit_open() {
    ...
error:
    free(buf);
    funlockfile(jd->in);
    fclose(jd->in);
}

If the initial metadata buffer allocation fails, the code jumps to the error
label and calls funlockfile(jd->in).

Since the lock was never acquired with flockfile() prior to this point, doesn't
unlocking a file descriptor that is not locked by the thread invoke undefined
behavior?


[Severity: High]
This isn't a bug introduced by this patch, but is there a missing
NUL-termination check for the sym string in jit_repipe_code_load()?

tools/perf/util/jitdump.c:jit_repipe_code_load() {
    ...
    sym   = (void *)((unsigned long)jr + sizeof(jr->load));
    code  = (unsigned long)jr + jr->load.p.total_size - csize;
    ...
}

A JIT_CODE_LOAD record sets code_size == total_size - sizeof(jr->load). The
sym string pointer is calculated to point to the end of the struct, which
directly overlaps with the raw code blob.

Later, in jit_write_elf() in tools/perf/util/genelf.c:

    symlen = 2 + strlen(sym);
    strsym = calloc(1, symlen);
    ...
    strcpy(strsym + 1, sym);

If the string is not validated to be NUL-terminated within bounds, could
strlen(sym) read past the jd->buf allocation and copy out-of-bounds heap
memory into the ELF string table?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=3

^ permalink raw reply	[flat|nested] 26+ 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; 26+ 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] 26+ messages in thread

* Re: [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload
  2026-08-05 21:27 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
@ 2026-08-05 21:53   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 21:53 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] State leakage of unwinding data due to flawed conditional cleanup, corrupting subsequent JIT loads.
- [High] Heap buffer overflow in `jit_repipe_code_move` due to undersized padding for the `event` buffer.
--

--- Patch [12]: [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload ---
commit 6a41da3e449813b67858843724cc900be799f924
Author: Arnaldo Carvalho de Melo <acme@redhat.com>

perf jitdump: Validate unwinding sizes against record payload

This commit validates unwinding sizes against the record payload to
prevent an out-of-bounds heap read in libelf. It also changes the type
of mapped_size to uint64_t to prevent truncation.

> 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
> @@ -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;

[Severity: High]
This is a pre-existing issue, but is it possible for stale unwinding state to
persist and corrupt subsequent JIT code loads?

Looking earlier in jit_repipe_code_load(), the cleanup logic requires
eh_frame_hdr_size to be 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_CODE_UNWINDING_INFO record provides unwinding data without an EH
frame header (where eh_frame_hdr_size == 0), this cleanup is bypassed.
The stale unwinding_data and unwinding_mapped_size would then remain in the
context descriptor (jd) and incorrectly apply to subsequent JIT_CODE_LOAD
events.

>  	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;

[Severity: High]
This is also a pre-existing issue, but could this undersized padding cause a
heap buffer overflow when copying sample IDs?

Looking further down in jit_repipe_code_move(), the event buffer is allocated
with a hardcoded 16-byte padding:

	/*
	 * +16 to account for sample_id_all (hack)
	 */
	event = calloc(1, sizeof(*event) + 16);

However, the mmap2 event size is calculated using the machine's idr_size:

	event->mmap2.header.size = (sizeof(event->mmap2) -
			(sizeof(event->mmap2.filename) - size) + idr_size);

And the sample ID data is written based on that dynamically sized offset:

	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);

If idr_size exceeds 16 bytes and the output filename is near PATH_MAX, the
calculated size could exceed the allocated space, causing the program to
write the pid, tid, and time out of bounds, followed by an out-of-bounds read
during output.

>  	u16 idr_size;
>  	int ret;
>  	pid_t nspid, pid, tid;

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=12

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path
  2026-08-05 21:27 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
@ 2026-08-05 22:00   ` sashiko-bot
  0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-05 22:00 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:
- [High] Missing NUL-termination validation for the symbol string in JIT_CODE_LOAD records causes out-of-bounds reads via strlen().
- [High] In `jit_repipe_unwinding_info()`, missing validation of `unwinding_size` and `eh_frame_hdr_size` causes an integer underflow and massive out-of-bounds read.
- [Medium] Dereferencing fields of `struct debug_entry` causes undefined behavior and SIGBUS on strict-alignment architectures.
- [Medium] Failing to allocate memory in `jit_repipe_debug_info` causes the next `JIT_CODE_LOAD` to inherit stale debug info.
- [Medium] In `jit_repipe_code_move()`, the synthetic MMAP2 event allocation hardcodes a +16 byte hack for the sample ID header, causing an out-of-bounds heap read.
--

--- Patch [10]: [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path ---
commit 6e2ff5c2d1b7c024e8a5cacbadffafaf75094372
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: 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.  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.

> 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 in jit_repipe_code_move(), the synthetic
MMAP2 event allocation hardcodes a +16 byte hack for the sample ID header:

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    event = calloc(1, sizeof(*event) + 16);
    ...
}

The sample ID header size (idr_size) can be up to 48 or 64 bytes depending
on the perf record configuration.

If the JIT path length is very long, the clamped size pushes
event->mmap2.header.size to exceed the allocated buffer size.

When jit_inject_event() writes the event out:

tools/perf/util/jitdump.c:jit_repipe_code_move() {
    ...
    ret = jit_inject_event(jd, event);
    ...
}

Could this read past the allocated heap block and leak uninitialized heap memory
into perf.data?

>  
>  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;

[Severity: Medium]
This is a pre-existing issue, but if malloc() fails in jit_repipe_debug_info():

tools/perf/util/jitdump.c:jit_repipe_debug_info() {
    ...
    data = malloc(sz);
    if (!data)
        return -1;
    ...
}

The function returns early without clearing the previously allocated
jd->debug_data.

Since the caller jit_process_dump() ignores this error, will the next
JIT_CODE_LOAD erroneously use the leftover stale debug_data and attach
it to the new code?

> @@ -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);

[Severity: Medium]
This is a pre-existing issue, but debug_entry_next() advances the pointer
without guaranteeing 8-byte alignment.

Later, when unaligned ent pointers are dereferenced to read the uint64_t addr
field, either in the byte-swap path:

tools/perf/util/jitdump.c:jit_get_next_entry() {
    ...
    ent->addr = bswap_64(ent->addr);
    ...
}

or downstream during iteration:

tools/perf/util/genelf_debug.c:jit_process_debug_info() {
    ...
    ent = debug_entry_next(ent);
    ...
}

Will this cause undefined behavior and a SIGBUS crash on architectures that
enforce strict alignment, like SPARC?

> +		valid++;
> +	}
> +	jd->nr_debug_entries = valid;
>  
>  	return 0;
>  }

[Severity: High]
This isn't a bug introduced by this patch, but while processing JIT_CODE_LOAD
records, jit_repipe_code_load() extracts the sym pointer from the payload:

tools/perf/util/jitdump.c:jit_repipe_code_load() {
    ...
    sym = (void *)((unsigned long)jr + sizeof(jr->load));
    ...
}

This extraction happens without verifying that it is NUL-terminated within the
bounds of the available buffer size.

Later, when jit_write_elf() computes the symbol length:

tools/perf/util/genelf.c:jit_write_elf() {
    ...
    symlen = 2 + strlen(sym);
    ...
}

Might this lead to an out-of-bounds read via strlen() if a malformed record
omits the NUL byte?

[Severity: High]
This is a pre-existing issue, but in jit_repipe_unwinding_info(), untrusted
size fields are copied without validation:

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;
    ...
}

If unwinding_header_size is greater than unwinding_size, will the calculation
in jit_add_eh_frame_info() underflow?

tools/perf/util/genelf.c:jit_add_eh_frame_info() {
    ...
    uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
    ...
}

Can this underflow result in a massive out-of-bounds read when the huge size
is subsequently passed to libelf for the section buffer size?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=10

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load
  2026-08-05 21:42   ` sashiko-bot
@ 2026-08-06 12:30     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-08-06 12:30 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: linux-perf-users

On Wed, Aug 05, 2026 at 09:42:41PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
> 
> New issues:
> - [Medium] jd->debug_data and jd->unwinding_data are leaked on the new validation failure path.

This is fixed in a later patch in this series, I'll reorder the series
so that this leak doesn't gets introduced to then be fixed in another
patch.

All the pre-existing issues reported are being tracked in TODO files for
upcoming series, one is already in the making.

Thanks,

- Arnaldo
 
> Pre-existing issues:
> - [High] Integer underflow when calculating unwinding_data_size in jit_repipe_unwinding_info leads to a massive heap allocation and out-of-bounds read.
> - [High] Missing snprintf truncation clamping in jit_repipe_code_move and jit_repipe_code_load leads to an undersized event allocation calculation and out-of-bounds heap write.
> - [High] jit_get_next_entry iterates over an unvalidated nr_entry array using fixed-size indexing for a variable-length structure, leading to out-of-bounds byte-swapping.
> - [High] The parser lacks total_size boundary checks for JIT_CODE_MOVE, leading to uninitialized heap reads.
> - [High] Lack of validation between buffer size and nr_entry leads to heap OOB read and write in debug info parsing.
> - [Medium] The perf_event allocated via calloc is unconditionally leaked in jit_repipe_code_move.
> - [Medium] Multiple memory leaks of dynamically allocated buffers in the jitdump parser, including missing cleanup in jit_close and overwrites in debug info.
> - [Medium] The ALIGN_8 macro evaluates using signed arithmetic, causing integer wrap and massive length corruption for mmap2 events.
> - [Medium] Truncation of 64-bit unwinding_mapped_size to 32-bit int can corrupt mmap2 event length.
> --
> 
> --- Patch [2]: [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load ---
> commit 97b091976e049b90397f99d555b22a4934abb49d
> Author: Arnaldo Carvalho de Melo <acme@redhat.com>
> 
> perf jitdump: Validate code_size against total_size in code load
> 
> This commit introduces validation checks to ensure that the code_size
> does not exceed the available size in the JIT load record. It adds bounds
> checking to prevent out-of-bounds heap reads when calculating the code
> blob pointer.
> 
> > diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> > index 4b7c7ba7cd95d..3195f94187164 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>
> > @@ -450,6 +451,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;
> 
> [Severity: Medium]
> Does this early return skip freeing the buffered debug and unwinding data?
> 
> Later in the function, these dynamically allocated buffers are freed:
> 
>     if (jd->debug_data && jd->nr_debug_entries) {
>             zfree(&jd->debug_data);
>             jd->nr_debug_entries = 0;
>     }
> 
>     if (jd->unwinding_data && jd->eh_frame_hdr_size) {
>             zfree(&jd->unwinding_data);
>             ...
> 
> If the code returns -1 here, do jd->debug_data and jd->unwinding_data remain
> allocated, permanently leaking since jit_close() does not appear to clean them
> up?
> 
> > +	}
> > +
> >  	sym   = (void *)((unsigned long)jr + sizeof(jr->load));
> >  	code  = (unsigned long)jr + jr->load.p.total_size - csize;
> >  	count = jr->load.code_index;
> 
> [ ... ]
> 
> Other findings in this file:
> 
> [Severity: High]
> This is a pre-existing issue, but does integer underflow occur when calculating
> unwinding_data_size 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), does the unsigned 32-bit
> subtraction underflow to a massive value, causing malloc to allocate too much
> memory and memcpy to perform an out-of-bounds read?
> 
> 
> [Severity: Medium]
> This is a pre-existing issue, but is the perf_event leaked in
> jit_repipe_code_move()?
> 
> tools/perf/util/jitdump.c:jit_repipe_code_move() {
>     ...
>     event = calloc(1, sizeof(*event) + 16);
>     if (!event)
>         return -1;
>     ...
>     return ret;
> }
> 
> The event pointer is allocated via calloc but is never freed on the success
> or error return paths. Does this gradually exhaust memory when parsing large
> dumps?
> 
> 
> [Severity: High]
> This is a pre-existing issue, but does missing snprintf truncation clamping
> lead to out-of-bounds heap writes?
> 
> 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);
>     ...
> }
> 
> When generating the filename, snprintf returns the length that would have
> been written. If this exceeds PATH_MAX, does the returned size wrap in the
> unsigned arithmetic for header.size, underflowing it and pushing the trailing
> id pointer out of the allocated event buffer bounds?
> 
> 
> [Severity: Medium]
> This is a pre-existing issue, but are dynamic buffers repeatedly leaked in
> jit_repipe_debug_info() and jit_close()?
> 
> tools/perf/util/jitdump.c:jit_repipe_debug_info() {
>     ...
>     data = malloc(sz);
>     /* ... */
>     jd->debug_data       = data;
>     ...
> }
> 
> Repeated JIT_CODE_DEBUG_INFO records will malloc a new buffer and overwrite
> jd->debug_data without freeing the old one. Additionally, jit_close() frees
> the jd struct resources but does not seem to clean up internal heap buffers
> like debug_data and unwinding_data. Does this leave them un-freed
> indefinitely?
> 
> 
> [Severity: High]
> This is a pre-existing issue, but does standard array indexing on a variable
> length struct cause memory corruption during bswap?
> 
> 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);
>     ...
> }
> 
> In cross-endian mode, this iterates over an unvalidated nr_entry array using
> fixed-size indexing. Since debug_entry includes a variable-length name[]
> string inline, doesn't fixed-size array indexing read from and byte-swap
> completely incorrect offsets?
> 
> 
> [Severity: High]
> This is a pre-existing issue, but does jit_repipe_code_move() lack boundary
> checks for the JIT_CODE_MOVE total_size?
> 
> tools/perf/util/jitdump.c:jit_repipe_code_move() {
>     ...
>     event->mmap2.start = jr->move.new_code_addr;
>     event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize : jr->move.code_size;
>     ...
> }
> 
> Unlike the new validation added to JIT_CODE_LOAD in this patch,
> jit_repipe_code_move() lacks a check confirming that total_size is greater
> than or equal to sizeof(jr->move). Can malformed records cause the parser
> to read uninitialized heap or stale data from jd->buf into perf.data?
> 
> 
> [Severity: Medium]
> This is a pre-existing issue, but does the ALIGN_8 macro silently overflow
> into a negative value?
> 
> tools/perf/util/jitdump.c:jit_repipe_code_load() {
>     ...
>     int ret, csize, usize;
>     /* ... */
>     event->mmap2.len   = usize ? ALIGN_8(csize) + usize : csize;
>     ...
> }
> 
> Since csize is typed as a signed int, does calculating ALIGN_8(csize) with a
> value near INT_MAX trigger signed integer overflow to a negative value, which
> is then sign-extended into a corrupted uint64_t length?
> 
> 
> [Severity: Medium]
> This is a pre-existing issue, but can the truncation of unwinding_mapped_size
> corrupt the mmap2 event length?
> 
> tools/perf/util/jitdump.c:jit_repipe_code_move() {
>     ...
>     int usize;
>     /* ... */
>     usize = jd->unwinding_mapped_size;
>     /* ... */
>     event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize : jr->move.code_size;
>     ...
> }
> 
> The 64-bit jd->unwinding_mapped_size is truncated to a 32-bit signed integer
> (usize). Could a maliciously crafted mapped_size result in a negative or
> truncated value, corrupting the final event->mmap2.len?
> 
> 
> [Severity: High]
> This is a pre-existing issue, but does the lack of validation between buffer
> size and nr_entry lead to heap out-of-bounds reads and writes?
> 
> tools/perf/util/jitdump.c:jit_repipe_debug_info() {
>     ...
>     jd->nr_debug_entries = jr->info.nr_entry;
>     ...
> }
> 
> The parser sets jd->nr_debug_entries from the unvalidated nr_entry file field
> without confirming the allocated sz bytes can accommodate them. When
> jit_process_debug_info() loops nr_entry times calling strlen on heap data,
> does this result in out-of-bounds heap writes?
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/20260805212704.267779-1-acme@kernel.org?part=2

^ permalink raw reply	[flat|nested] 26+ 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
@ 2026-08-06 12:36 ` Arnaldo Carvalho de Melo
  2026-08-06 13:03   ` sashiko-bot
  0 siblings, 1 reply; 26+ 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] 26+ 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; 26+ 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] 26+ messages in thread

end of thread, other threads:[~2026-08-06 13:03 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-05 21:26 [PATCHES v2 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 02/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
2026-08-05 21:42   ` sashiko-bot
2026-08-06 12:30     ` Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 03/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
2026-08-05 21:46   ` sashiko-bot
2026-08-05 21:26 ` [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
2026-08-05 21:40   ` sashiko-bot
2026-08-05 21:26 ` [PATCH 05/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
2026-08-05 21:40   ` sashiko-bot
2026-08-05 21:26 ` [PATCH 06/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 07/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 08/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
2026-08-05 21:26 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
2026-08-05 21:45   ` sashiko-bot
2026-08-05 21:27 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
2026-08-05 22:00   ` sashiko-bot
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 21:27 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
2026-08-05 21:53   ` sashiko-bot
  -- strict thread matches above, loose matches on Subject: below --
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
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-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