From: Alan Modra Date: Tue, 24 Feb 2026 11:18:14 +0000 (+1030) Subject: readelf: endless loop on attrv2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=893eb49c9b123cd5736e58d61dfc58a852cccd0d;p=thirdparty%2Fbinutils-gdb.git readelf: endless loop on attrv2 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. --- diff --git a/binutils/readelf.c b/binutils/readelf.c index b594034d933..c9ec085adc4 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -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);