Re: [PATCH 04/12] perf jitdump: Bounds-check debug entry byte-swap loop
Ian Rogers <[email protected]> Wed, 5 Aug 2026 12:00:58 -0700
| Newsgroups | org.kernel.vger.linux-perf-users,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAP-5=fXZja6D99Fv0=aJ-W27RJbR2=vr8YqV4sf4qGh1KH6SAw@mail.gmail.com> |
On Wed, Aug 5, 2026 at 6:31 AM Arnaldo Carvalho de Melo <[email protected]> wrote: > > From: Arnaldo Carvalho de Melo <[email protected]> > > 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 <[email protected]> > Cc: Stephane Eranian <[email protected]> > Assisted-by: Claude:claude-opus-4.6 > Signed-off-by: Arnaldo Carvalho de Melo <[email protected]> Reviewed-by: Ian Rogers <[email protected]> Thanks! Ian > --- > 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 >