From: Sujal Tuladhar <sujaltuladhar1231@gmail.com>
Subject: [PATCH] readelf: fix 4-byte out-of-bounds read of CU-vector count in print_gdb_index_section

In the symbol table loop of print_gdb_index_section, the constant-pool
offset `vector` taken from the file is validated only with

    if ((size_t) (dataend - const_start) < vector)
      goto invalid_data;

which permits `vector == dataend - const_start`, i.e. `readcus == dataend`.
The following fixed-width read

    uint32_t cus = read_4ubyte_unaligned (dbg, readcus);

then reads 4 bytes at `readcus`, up to 4 bytes past the end of the section
buffer whenever `vector` is within 3 bytes of the constant pool's end.

The immediately following inner loop already guards its own read with
`if (readcus + 4 > dataend) goto invalid_data;`, and the DW_FORM_sec_offset /
str_offsets code paths use the same `(end - ptr) < width` idiom; only this
initial count read omitted the read-width term. Add it.

Reproducible with `eu-readelf --debug-dump=gdb_index` on a crafted ELF whose
`.gdb_index` (version 4-9) symbol slot sets `vector` to the constant-pool size.
AddressSanitizer reports a heap-buffer-overflow READ of size 4 at the count
read.

Signed-off-by: Sujal Tuladhar <sujaltuladhar1231@gmail.com>
---
 src/readelf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/readelf.c b/src/readelf.c
index 947b2d9..0000000 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -12130,7 +12130,8 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl,
 	  fprintf (out, " [%4zu] symbol: %s, CUs: ", n, sym);
 
 	  const unsigned char *readcus = const_start + vector;
-	  if (unlikely ((size_t) (dataend - const_start) < vector))
+	  if (unlikely ((size_t) (dataend - const_start) < vector
+			|| (size_t) (dataend - readcus) < sizeof (uint32_t)))
 	    goto invalid_data;
 	  uint32_t cus = read_4ubyte_unaligned (dbg, readcus);
 	  while (cus--)
-- 
2.43.0
