Bug 28069 - readelf crashed due to Assertion failed in dwarf.c:display_discr_list
Summary: readelf crashed due to Assertion failed in dwarf.c:display_discr_list
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.38 (HEAD)
: P2 normal
Target Milestone: 2.38
Assignee: Alan Modra
Depends on:
Reported: 2021-07-09 08:06 UTC by Shaohua Li
Modified: 2021-07-10 04:25 UTC (History)
0 users

See Also:
Last reconfirmed: 2021-07-09 00:00:00

poc (416 bytes, application/x-object)
2021-07-09 08:06 UTC, Shaohua Li

Note You need to log in before you can comment on or make changes to this bug.
Description Shaohua Li 2021-07-09 08:06:25 UTC
Created attachment 13550 [details]

Hi there,

I crashed `readelf -w` with a fuzzer. The original error message was "readelf: dwarf.c:2336: void display_discr_list(unsigned long, dwarf_vma, unsigned char *, const unsigned char *, int): Assertion `uvalue > 0' failed."

- Compiler: clang12
- Platform: Ubuntu 18.04.5 LTS, x86_64
- Reproduce: run `readelf -w poc`
Comment 1 cvs-commit@gcc.gnu.org 2021-07-10 04:06:54 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:


commit 9039747fb4863c13eaf07f84bb28d50660fb8d85
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Jul 10 09:34:30 2021 +0930

    PR28069, assertion fail in dwarf.c:display_discr_list
    We shouldn't be asserting on anything to do with leb128 values, or
    reporting file and line numbers when something unexpected happens.
    leb128 data is of indeterminate length, perfect for fuzzer mayhem.
    It would only make sense to assert or report dwarf.c/readelf.c source
    lines if the code had already sized and sanity checked the leb128
    After removing the assertions, the testcase then gave:
        <37>   DW_AT_discr_list  : 5 byte block: 0 0 0 0 0  (label 0, label 0, label 0, label 0, <corrupt>
    readelf: Warning: corrupt discr_list - unrecognized discriminant byte 0x5
        <3d>   DW_AT_encoding    : 0        (void)
        <3e>   DW_AT_identifier_case: 0     (case_sensitive)
        <3f>   DW_AT_virtuality  : 0        (none)
        <40>   DW_AT_decimal_sign: 5        (trailing separate)
    So the DW_AT_discr_list was showing more data than just the 5 byte
    block.  That happened due to "end" pointing a long way past the end of
    block, and uvalue decrementing past zero on one of the leb128 bytes.
            PR 28069
            * dwarf.c (display_discr_list): Remove assertions.  Delete "end"
            parameter, use initial "data" pointer as the end.  Formatting.
            Don't count down bytes as they are read.
            (read_and_display_attr_value): Adjust display_discr_list call.
            (read_and_print_leb128): Don't pass __FILE__ and __LINE__ to
            * dwarf.h (report_leb_status): Don't report file and line
            numbers.  Delete file and lnum parameters,
            (READ_ULEB, READ_SLEB): Adjust.
Comment 2 Alan Modra 2021-07-10 04:25:46 UTC
Fixed mainline, won't backport to 2.37 since this bug is only tickled by fuzzed objects.