From c87ed59208e1ce665f08ae2b2d8c1cdc2a653ea2 Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Sat, 22 Nov 2025 09:52:18 +1030
Subject: [PATCH] PR 33639 .debug_loclists output

The fuzzed testcase in this PR prints an almost endless table of
offsets, due to a bogus offset count.  Limit that count, and the total
length too.

	PR 33639
	* dwarf.c (display_loclists_unit_header): Return error on
	length too small to read header.  Limit length to section
	size.  Limit offset count similarly.

CVE: CVE-2025-69647

Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=455446bbdc8675f34808187de2bbad4682016ff7]

Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
---
 binutils/dwarf.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 72bc9d7497a..06d68074046 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -7221,8 +7221,6 @@ display_loclists_unit_header (struct dwarf_section *  section,
   bool is_64bit;
   uint32_t i;
 
-  printf (_("Table at Offset %#" PRIx64 "\n"), header_offset);
-
   SAFE_BYTE_GET_AND_INC (length, start, 4, end);
   if (length == 0xffffffff)
     {
@@ -7231,6 +7229,11 @@ display_loclists_unit_header (struct dwarf_section *  section,
     }
   else
     is_64bit = false;
+  if (length < 8)
+    return (uint64_t) -1;
+
+  printf (_("Table at Offset %#" PRIx64 "\n"), header_offset);
+  header_offset = start - section->start;
 
   SAFE_BYTE_GET_AND_INC (version, start, 2, end);
   SAFE_BYTE_GET_AND_INC (address_size, start, 1, end);
@@ -7243,15 +7246,21 @@ display_loclists_unit_header (struct dwarf_section *  section,
   printf (_("  Segment size:    %u\n"), segment_selector_size);
   printf (_("  Offset entries:  %u\n"), *offset_count);
 
+  if (length > section->size - header_offset)
+    length = section->size - header_offset;
+
   if (segment_selector_size != 0)
     {
       warn (_("The %s section contains an "
 	      "unsupported segment selector size: %d.\n"),
 	    section->name, segment_selector_size);
-      return (uint64_t)-1;
+      return (uint64_t) -1;
     }
 
-  if ( *offset_count)
+  uint64_t max_off_count = length >> (is_64bit ? 3 : 2);
+  if (*offset_count > max_off_count)
+    *offset_count = max_off_count;
+  if (*offset_count)
     {
       printf (_("\n   Offset Entries starting at %#tx:\n"),
 	      start - section->start);
@@ -7268,8 +7277,7 @@ display_loclists_unit_header (struct dwarf_section *  section,
   putchar ('\n');
   *loclists_start = start;
 
-  /* The length field doesn't include the length field itself.  */
-  return header_offset + length + (is_64bit ? 12 : 4);
+  return header_offset + length;
 }
 
 static int
-- 
2.34.1

