From: sashiko-bot@kernel.org
To: "Arnaldo Carvalho de Melo" <acme@kernel.org>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks
Date: Thu, 06 Aug 2026 12:52:02 +0000 [thread overview]
Message-ID: <20260806125203.3D5E01F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260806123604.271277-3-acme@kernel.org>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Pre-existing issues:
- [Critical] The `csize` value from the untrusted JIT dump file is not validated against `total_size`, allowing an integer underflow that leads to a massive out-of-bounds heap read and information leak.
- [Critical] Output `.so` files are opened without `O_EXCL` and `O_NOFOLLOW` in a potentially attacker-controlled directory, allowing a symlink attack to overwrite arbitrary files.
- [High] Code load events fail to consume and free `unwinding_data` and `debug_data` if their respective auxiliary sizes or counts are zero, leading to state contamination.
- [High] Calling `funlockfile()` without a preceding `flockfile()` on the `malloc()` error path causes undefined behavior.
- [High] Missing bounds check on the JIT record `total_size` before accessing the `sym` string pointer causes an out-of-bounds string read.
--
--- Patch [2]: [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks ---
commit e7687575b20ca5df1e7780e1c7b436a5bc7d2f8c
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
perf jitdump: Fix debug_data and unwinding_data leaks
This commit fixes memory leaks in jit_repipe_debug_info() and jit_close().
It uses zfree() to correctly free existing allocations before reassignment
and cleans up at the end of the session.
> diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
> --- a/tools/perf/util/jitdump.c
> +++ b/tools/perf/util/jitdump.c
> @@ -61,12 +61,12 @@ static int
> jit_emit_elf(struct jit_buf_desc *jd,
> char *filename,
[ ... ]
> nsinfo__mountns_enter(jd->nsi, &nsc);
> fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
[Severity: Critical]
This isn't a bug introduced by this patch, but opening output files without
O_EXCL and O_NOFOLLOW in a potentially attacker-controlled directory might
allow a symlink attack to overwrite arbitrary files.
Could this be updated to use safer open flags?
[ ... ]
> @@ -117,6 +117,8 @@ jit_close(struct jit_buf_desc *jd)
> funlockfile(jd->in);
> fclose(jd->in);
> jd->in = NULL;
> + zfree(&jd->debug_data);
> + zfree(&jd->unwinding_data);
> }
[ ... ]
> @@ -154,9 +154,9 @@ static int
> jit_open(struct jit_buf_desc *jd, const char *name)
> {
[ ... ]
> bsz = hmax(sizeof(header), sizeof(*prefix));
>
> buf = malloc(bsz);
> if (!buf)
> goto error;
>
> /*
> * protect from writer modifying the file while we are reading it
> */
> flockfile(jd->in);
[ ... ]
> @@ -217,9 +217,9 @@ static int
> return 0;
> error:
> free(buf);
> funlockfile(jd->in);
[Severity: High]
This isn't a bug introduced by this patch, but if the initial malloc(bsz)
fails, we jump to error and call funlockfile(jd->in) without a preceding
flockfile().
Does calling funlockfile() on an unlocked FILE stream cause undefined
behavior or corruption of internal libc mutexes here?
> fclose(jd->in);
> return retval;
> }
[ ... ]
> @@ -465,10 +465,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> nspid = jr->load.pid;
> pid = jr_entry_pid(jd, jr);
> tid = jr_entry_tid(jd, jr);
> csize = jr->load.code_size;
> usize = jd->unwinding_mapped_size;
> addr = jr->load.code_addr;
> sym = (void *)((unsigned long)jr + sizeof(jr->load));
[Severity: High]
This is a pre-existing issue, but is it possible for jr->load.p.total_size
to be smaller than sizeof(jr->load)?
The sym pointer is derived assuming total_size is at least 56 bytes, which
isn't validated before access. Could this lead to an out-of-bounds string
read if a smaller total_size is provided?
> code = (unsigned long)jr + jr->load.p.total_size - csize;
[Severity: Critical]
This is a pre-existing issue, but the code pointer is calculated using csize
without checking if it exceeds total_size.
Could an attacker provide a csize larger than total_size to cause an integer
underflow, resulting in a massive out-of-bounds heap read and information
leak into the generated ELF file?
> count = jr->load.code_index;
> idr_size = jd->machine->id_hdr_size;
[ ... ]
> @@ -475,10 +475,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> event = calloc(1, sizeof(*event) + idr_size);
> if (!event)
> return -1;
>
> filename = event->mmap2.filename;
> size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so",
> jd->dir,
> nspid,
> count);
[Severity: Critical]
This isn't a bug introduced by this patch, but the filename is predictably
constructed using fields (nspid and count) controlled by the JIT dump.
Combined with the lack of O_EXCL|O_NOFOLLOW in jit_emit_elf(), does this
allow an attacker to perform a symlink attack when perf inject is run?
[ ... ]
> @@ -495,10 +495,10 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
> jd->nr_debug_entries = 0;
> }
>
> if (jd->unwinding_data && jd->eh_frame_hdr_size) {
> zfree(&jd->unwinding_data);
> jd->eh_frame_hdr_size = 0;
> jd->unwinding_mapped_size = 0;
> jd->unwinding_size = 0;
> }
[Severity: High]
This is a pre-existing issue, but this conditional cleanup leaves
jd->unwinding_data dangling if eh_frame_hdr_size is zero.
If a JIT runtime emits JIT_CODE_UNWINDING_INFO without .eh_frame_hdr, is the
unwinding data incorrectly applied to all subsequent JIT_CODE_LOAD events
until overwritten, producing corrupted ELF files?
[ ... ]
> @@ -665,6 +667,7 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
>
> memcpy(data, &jr->info.entries, sz);
>
> + zfree(&jd->debug_data);
> jd->debug_data = data;
>
> /*
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806123604.271277-1-acme@kernel.org?part=2
next prev parent reply other threads:[~2026-08-06 12:52 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 12:35 [PATCHES v3 0/12] perf jitdump: Input validation hardening Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 01/12] perf jitdump: Fix extended header read that always fails Arnaldo Carvalho de Melo
2026-08-06 13:04 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 02/12] perf jitdump: Fix debug_data and unwinding_data leaks Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot [this message]
2026-08-06 12:35 ` [PATCH 03/12] perf jitdump: Validate code_size against total_size in code load Arnaldo Carvalho de Melo
2026-08-06 12:56 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 04/12] perf jitdump: Prevent integer underflow in debug info size calculation Arnaldo Carvalho de Melo
2026-08-06 12:55 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 15:21 ` Arnaldo Carvalho de Melo
2026-08-06 12:35 ` [PATCH 06/12] perf jitdump: Check snprintf return before computing header size Arnaldo Carvalho de Melo
2026-08-06 12:52 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 07/12] perf jitdump: Fix funlockfile on unlocked stream in jit_open() error path Arnaldo Carvalho de Melo
2026-08-06 12:51 ` sashiko-bot
2026-08-06 12:35 ` [PATCH 08/12] perf jitdump: Free event in jit_repipe_code_move() Arnaldo Carvalho de Melo
2026-08-06 12:49 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 09/12] perf jitdump: Use dirname() return value in jit_open() Arnaldo Carvalho de Melo
2026-08-06 12:36 ` [PATCH 10/12] perf jitdump: Validate debug entries on native (non-swap) path Arnaldo Carvalho de Melo
2026-08-06 13:10 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 11/12] perf jitdump: Validate sym string NUL-termination in code load Arnaldo Carvalho de Melo
2026-08-06 13:03 ` sashiko-bot
2026-08-06 12:36 ` [PATCH 12/12] perf jitdump: Validate unwinding sizes against record payload Arnaldo Carvalho de Melo
2026-08-06 13:06 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260806125203.3D5E01F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=acme@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox