From 131567040b8661e6df119ae9d461fa6de369dc8e Mon Sep 17 00:00:00 2001
From: Karan Kurani <karankurani3k@gmail.com>
Date: Fri, 24 Jul 2026 13:15:37 +0000
Subject: [PATCH 2/2] libdw: Use checked reads for DWARF5 initial lengths

str_offsets_base_off, __libdw_cu_ranges_base and __libdw_cu_locs_base each
read a four byte initial length and, when it is 0xffffffff, an eight byte
DWARF64 length.  Use the checked readers for both, so the availability
check and the read stay together.

The rnglists and loclists guards were written as readp > dataend - 4 and
readp > dataend - 8.  For a section shorter than the subtracted width that
computes a pointer before the start of the section data, which the C object
model does not define.  __libdw_can_read compares the two pointers before
subtracting instead.  The same replacement is made for the availability
clause of the later combined checks; the remaining clauses of those checks,
and the version, padding, unit extent, offset size, address size and
segment selector checks, are unchanged.

Error labels and return values are unchanged, and valid input is parsed as
before.

Signed-off-by: Karan Kurani <karankurani3k@gmail.com>
---
 libdw/libdwP.h | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 1a3aea2d..d575330a 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1282,14 +1282,16 @@ str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
   uint64_t unit_length;
   uint16_t version;
 
-  if (unlikely (readendp - readp < 4))
+  uint32_t initial_length;
+  if (unlikely (! read_4ubyte_unaligned_inc_checked (dbg, &readp, readendp,
+						      &initial_length)))
     goto no_header;
-  unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+  unit_length = initial_length;
   if (unlikely (unit_length == 0xffffffff))
     {
-      if (unlikely (readendp - readp < 8))
+      if (unlikely (! read_8ubyte_unaligned_inc_checked (dbg, &readp, readendp,
+							 &unit_length)))
 	goto no_header;
-      unit_length = read_8ubyte_unaligned_inc (dbg, readp);
       /* In theory the offset size could be different
 	 between CU and str_offsets unit.  But we just
 	 ignore that here. */
@@ -1373,20 +1375,21 @@ __libdw_cu_ranges_base (Dwarf_CU *cu)
 	      const unsigned char *const dataend
 		= (unsigned char *) data->d_buf + data->d_size;
 
-	      if (unlikely (readp > dataend - 4))
+	      uint32_t initial_length;
+	      if (unlikely (! read_4ubyte_unaligned_inc_checked
+			    (dbg, &readp, dataend, &initial_length)))
 		goto no_header;
-	      uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+	      uint64_t unit_length = initial_length;
 	      unsigned int offset_size = 4;
 	      if (unlikely (unit_length == 0xffffffff))
 		{
-		  if (unlikely (readp > dataend - 8))
+		  if (unlikely (! read_8ubyte_unaligned_inc_checked
+			  (dbg, &readp, dataend, &unit_length)))
 		    goto no_header;
-
-		  unit_length = read_8ubyte_unaligned_inc (dbg, readp);
 		  offset_size = 8;
 		}
 
-	      if (readp > dataend - 8
+	      if (! __libdw_can_read (readp, dataend, 8)
 		  || unit_length < 8
 		  || unit_length > (uint64_t) (dataend - readp))
 		goto no_header;
@@ -1458,20 +1461,21 @@ __libdw_cu_locs_base (Dwarf_CU *cu)
 	  const unsigned char *const dataend
 	    = (unsigned char *) data->d_buf + data->d_size;
 
-	  if (unlikely (readp > dataend - 4))
+	  uint32_t initial_length;
+	  if (unlikely (! read_4ubyte_unaligned_inc_checked
+			(dbg, &readp, dataend, &initial_length)))
 	    goto no_header;
-	  uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+	  uint64_t unit_length = initial_length;
 	  unsigned int offset_size = 4;
 	  if (unlikely (unit_length == 0xffffffff))
 	    {
-	      if (unlikely (readp > dataend - 8))
+	      if (unlikely (! read_8ubyte_unaligned_inc_checked
+			    (dbg, &readp, dataend, &unit_length)))
 		goto no_header;
-
-	      unit_length = read_8ubyte_unaligned_inc (dbg, readp);
 	      offset_size = 8;
 	    }
 
-	  if (readp > dataend - 8
+	  if (! __libdw_can_read (readp, dataend, 8)
 	      || unit_length < 8
 	      || unit_length > (uint64_t) (dataend - readp))
 	    goto no_header;
-- 
2.44.0

