From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7865D339370; Mon, 31 Aug 2026 13:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181908; cv=none; b=TF/DLsg5fXjvrt9vLP6AjWdvf0u7xeqDC6O9k7ljYJQNxSiVusK+wrGnA5Uq9485EgdHKlVVxUua8FkJcVYeatiEtWde3xw7X429D6zRGy4gSVg3G095xLbWC480MXRrgUcPEd10tPzMYNawY4/LDGQ8Q8K0X4iA6DWiiwMhRWI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788181908; c=relaxed/simple; bh=sdX+RhPHHulfgf9z0zDxr74gwEi5MYaKk0IR2NseyjY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uaMa2qs4ybcbX/LyMZnTphFIW+KZvfhyzZAojFB3eoBK+Ob60yb2lcQ9MrmsE8PZbrLjHZEShTGe2iTBhSQwLIMmYKV58aXMr4JW+cBV5Z+/E75/GcbeW9UkSwG/DVUKypG3ARFOqqWvb15DNhsBMb9A9oxYrfJGvgvnlMUWzPo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=o10dGK1J; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="o10dGK1J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 277DA1F00A3D; Mon, 31 Aug 2026 13:11:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788181907; bh=sC1DzcEl5JUC81Rna7UIZVoV911LNTe5zyxc+uDQV74=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=o10dGK1Jagz+MAZP22Fxj50Agj4zMitLERwULOq+IFeo48NdaXUUCdrlKHFKqadz3 uy6H2pNbZcD03J+oFmIbbgw5doC8g6cgv9MISD9rXoph4A3tAdaLNqqwadDvzbGZyy NVJvQnr0mU/Rw+rxziHh4OosTatNgkSdKwMxSeKVFRyA8sEwRqCfvMnZlwqP4ACBwq gYovXoficfbkI+K8pURTCd0NG+MagbPyW+e+T2m0fHlGKl90QjVKlArklUyosPH9jr NoXsinBjhEaHucidC3J3aaLmBPvYtXSLS2BbKKGZr7ZOdWj/V5sVWhhgPsPdBVHJkD dz9VOSTRUdgwg== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , sashiko-bot , Stephane Eranian Subject: [PATCH 05/12] perf jitdump: Bounds-check debug entry byte-swap loop Date: Mon, 31 Aug 2026 10:11:01 -0300 Message-ID: <20260831131110.4681-6-acme@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260831131110.4681-1-acme@kernel.org> References: <20260831131110.4681-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-perf-users@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Arnaldo Carvalho de Melo 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 Reviewed-by: Ian Rogers Cc: Stephane Eranian Assisted-by: LLM Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/jitdump.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index f79e9420c6bd7c51..7efbaa07f1ba73f9 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -320,14 +320,32 @@ jit_get_next_entry(struct jit_buf_desc *jd) switch(id) { case JIT_CODE_DEBUG_INFO: if (jd->needs_bswap) { + void *end = (void *)jr + jr->prefix.total_size; + struct debug_entry *ent; uint64_t n; + jr->info.code_addr = bswap_64(jr->info.code_addr); jr->info.nr_entry = bswap_64(jr->info.nr_entry); - for (n = 0 ; n < jr->info.nr_entry; n++) { - jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr); - jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno); - jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim); + + /* + * debug_entry has a variable-length name[], so array + * indexing would compute wrong offsets — use + * debug_entry_next() and bounds-check each entry. + */ + ent = &jr->info.entries[0]; + for (n = 0; n < jr->info.nr_entry; n++) { + if ((void *)ent + sizeof(*ent) > end) + break; + /* name must be NUL-terminated within the record */ + if (!memchr(ent->name, '\0', (char *)end - ent->name)) + break; + ent->addr = bswap_64(ent->addr); + ent->lineno = bswap_32(ent->lineno); + ent->discrim = bswap_32(ent->discrim); + ent = debug_entry_next(ent); } + /* clamp so downstream consumers don't overrun */ + jr->info.nr_entry = n; } break; case JIT_CODE_UNWINDING_INFO: -- 2.55.0