https://sourceware.org/bugzilla/show_bug.cgi?id=32650

Mark Wielaard <mark at klomp dot org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|                            |2025-02-08
                 CC|                            |mark at klomp dot org
           Assignee|unassigned at sourceware dot org   |mark at klomp dot org
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |ASSIGNED

--- Comment #1 from Mark Wielaard <mark at klomp dot org> ---
Replicated under valgrind with --debug-dump=abbrev

==552106== Invalid read of size 8
==552106==    at 0x48A7F70: __libdw_thread_tail (libdw_alloc.c:112)
==552106==    by 0x488BB98: __libdw_getabbrev (dwarf_getabbrev.c:104)
==552106==    by 0x48A1BA2: dwarf_offabbrev (dwarf_offabbrev.c:44)
==552106==    by 0x412073: print_debug_abbrev_section (readelf.c:5676)
==552106==    by 0x426003: print_debug (readelf.c:12151)
==552106==    by 0x404614: process_elf_file (readelf.c:1084)
==552106==    by 0x403B91: process_dwflmod (readelf.c:840)
==552106==    by 0x48BD8FF: dwfl_getmodules (dwfl_getmodules.c:86)
==552106==    by 0x403FC5: process_file (readelf.c:948)
==552106==    by 0x402AE0: main (readelf.c:417)
==552106==  Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently)
free'd

The issue triggers in __libdw_getabbrev when an abbrev is found with a number
we have already seen (all abbrev numbers should be unique) or some other sanity
check fails later on:

      if (unlikely (abb->offset != offset))
        {
          /* A duplicate abbrev code at a different offset,
             that should never happen.  */
        invalid:
          if (! foundit)
            libdw_typed_unalloc (dbg, Dwarf_Abbrev);
          __libdw_seterrno (DWARF_E_INVALID_DWARF);
          return NULL;
        }

The unalloc fails when called through dwarf_offabbrev. In that case result !=
NULL. Which means no new abbrev has been allocated. dwarf_offabbrev is the only
function calling with result != NULL, all other calls to __libdw_getabbrev pass
result as NULL and so won't trigger this bug in case of an invalid abbrev.

Bug introduced in commit 287e502815bf ("libdw: Introduce libdw_unalloc to stop
Dwarf_Abbrev leaks.")

Possible fix:

diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index 5b02333f3467..f32326649592 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -100,7 +100,7 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
Dwarf_Off offset,
          /* A duplicate abbrev code at a different offset,
             that should never happen.  */
        invalid:
-         if (! foundit)
+         if (! foundit && result == NULL)
            libdw_typed_unalloc (dbg, Dwarf_Abbrev);
          __libdw_seterrno (DWARF_E_INVALID_DWARF);
          return NULL;
@@ -155,8 +155,11 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
Dwarf_Off offset,
       {
        /* The entry was already in the table, remove the one we just
           created and get the one already inserted.  */
-       libdw_typed_unalloc (dbg, Dwarf_Abbrev);
+       if (result == NULL)
+         libdw_typed_unalloc (dbg, Dwarf_Abbrev);
        abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code);
+       if (result != NULL)
+         *result = *abb;
       }

  out:

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to