]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
readelf: endless loop on attrv2
authorAlan Modra <amodra@gmail.com>
Tue, 24 Feb 2026 11:18:14 +0000 (21:48 +1030)
committerAlan Modra <amodra@gmail.com>
Tue, 24 Feb 2026 11:36:45 +0000 (22:06 +1030)
Given a short attributes section, elf_parse_attrs_subsection_v2 prints
an error message but does not return an error status or consume any
input.  That results in endless printing of "Object attributes section
ends prematurely".  The length checks also ignored a single excess
byte at the end of the section.

* readelf.c (elf_parse_attrs_subsection_v2): Move various
constants out of function.  Don't check for min length here..
(process_attributes_v2): ..do so here instead.

binutils/readelf.c

index b594034d9339c4d23744e9f1c4319e358af29dbe..c9ec085adc49e3b583b9e5e49a116f9604a12174 100644 (file)
@@ -20098,6 +20098,15 @@ typedef struct {
   uint64_t read;
 } BufferReadOp_t;
 
+const uint32_t F_SUBSECTION_LEN = sizeof (uint32_t);
+const uint32_t F_SUBSECTION_COMPREHENSION = sizeof(uint8_t);
+const uint32_t F_SUBSECTION_ENCODING = sizeof(uint8_t);
+/* The minimum subsection length is 7: 4 bytes for the length itself, and 1
+   byte for an empty NUL-terminated string, 1 byte for the comprehension,
+   1 byte for the encoding, and no vendor-data.  */
+const uint32_t F_MIN_SUBSECTION_DATA_LEN = F_SUBSECTION_LEN + 1 /* for '\0' */
+  + F_SUBSECTION_COMPREHENSION + F_SUBSECTION_ENCODING;
+
 static BufferReadOp_t
 elf_parse_attrs_subsection_v2 (const unsigned char *cursor,
                               const uint64_t max_read,
@@ -20105,25 +20114,6 @@ elf_parse_attrs_subsection_v2 (const unsigned char *cursor,
                               display_arch_attr_t display_arch_attr)
 {
   BufferReadOp_t op = { .err = false, .read = 0 };
-
-  const uint32_t F_SUBSECTION_LEN = sizeof (uint32_t);
-  const uint32_t F_SUBSECTION_COMPREHENSION = sizeof(uint8_t);
-  const uint32_t F_SUBSECTION_ENCODING = sizeof(uint8_t);
-  /* The minimum subsection length is 7: 4 bytes for the length itself, and 1
-     byte for an empty NUL-terminated string, 1 byte for the comprehension,
-     1 byte for the encoding, and no vendor-data.  */
-  const uint32_t F_MIN_SUBSECTION_DATA_LEN
-    = F_SUBSECTION_LEN + 1 /* for '\0' */
-      + F_SUBSECTION_COMPREHENSION + F_SUBSECTION_ENCODING;
-
-  /* Handle cases where the attributes data is not strictly valid (e.g. due to
-     fuzzing).  */
-  if (max_read < F_MIN_SUBSECTION_DATA_LEN)
-    {
-      error (_("Object attributes section ends prematurely\n"));
-      return op;
-    }
-
   unsigned int subsection_len = byte_get (cursor, F_SUBSECTION_LEN);
   cursor += F_SUBSECTION_LEN;
   op.read += F_SUBSECTION_LEN;
@@ -20289,8 +20279,9 @@ process_attributes_v2 (Filedata *filedata,
 
   printf (_("Subsections:\n"));
   BufferReadOp_t op;
-  for (uint64_t remaining = sec_hdr->sh_size - 1; // already read 'A'
-       remaining > 1;
+  uint64_t remaining;
+  for (remaining = sec_hdr->sh_size - 1; // already read 'A'
+       remaining >= F_MIN_SUBSECTION_DATA_LEN;
        remaining -= op.read, cursor += op.read)
     {
       op = elf_parse_attrs_subsection_v2 (cursor, remaining, public_name,
@@ -20304,6 +20295,12 @@ process_attributes_v2 (Filedata *filedata,
        }
     }
 
+  if (remaining != 0)
+    {
+      error (_("Object attributes section ends prematurely\n"));
+      res = false;
+    }
+
  free_data:
   free (data);