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

            Bug ID: 34401
           Summary: heap-buffer-overflow read in elf_getarsym with
                    truncated /SYM64/ archive index
           Product: elfutils
           Version: unspecified
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: libelf
          Assignee: unassigned at sourceware dot org
          Reporter: karankurani3k at gmail dot com
                CC: elfutils-devel at sourceware dot org
  Target Milestone: ---

Created attachment 16845
  --> https://sourceware.org/bugzilla/attachment.cgi?id=16845&action=edit
Standalone reproducer, ASan trace, after-patch trace, and tested diff for
/SYM64/ elf_getarsym OOB read

Reported by:
Karan Kurani <[email protected]>

I found a heap-buffer-overflow read in libelf/elf_getarsym.c when parsing a
malformed 64-bit archive symbol table member named /SYM64/.

Tested version
--------------
Latest elfutils HEAD:

  40d077029b3eeff5b4b71b1b0dd0892d0523350c

git status --porcelain printed no output before testing.

Summary
-------
elf_getarsym() does not fully validate that a /SYM64/ archive index member
contains enough bytes for the 8-byte symbol count field plus n 8-byte archive
offset entries.

For /SYM64/, each archive symbol offset entry is 8 bytes.

A malformed archive can contain:

  member name: /SYM64/
  member size: 9
  symbol count: 1
  offset-table payload after the count field: 1 byte

The existing validation checks:

  n > index_size / w

where w is 8 for /SYM64/.

With index_size=9 and n=1, this check passes because:

  1 > 9 / 8

is false.

However, index_size includes the initial 8-byte count field. After reading that
count field, only 1 byte remains, but elf_getarsym() later copies 8 bytes for
the single archive symbol offset entry.

Vulnerable location
-------------------
File:

  libelf/elf_getarsym.c

Vulnerable line:

  file_data = memcpy (temp_data, elf->map_address + off, sz);

In my ASan build this is reached at:

  libelf/elf_getarsym.c:260

Public API path
---------------
The issue is reachable through the public libelf API:

  elf_memory()
  -> elf_getarsym()

Generated archive layout
------------------------
The generated archive layout is:

  ar magic
  /SYM64/ member header, size=9
  8-byte big-endian symbol count = 1
  1 byte of offset-table payload
  total archive size = 77 bytes

Runtime proof
-------------
ASan confirms the out-of-bounds read:

  ERROR: AddressSanitizer: heap-buffer-overflow
  READ of size 8
      #1 elf_getarsym ././elfutils/libelf/elf_getarsym.c:260

  0x50700000014d is located 0 bytes after 77-byte region

Impact
------
A malicious or malformed archive file can trigger an out-of-bounds read in
libelf consumers that parse archive symbol tables through elf_getarsym().

The immediate impact is crash/DoS or undefined behavior while processing
attacker-controlled archive files. I am not claiming RCE.

Suggested fix
-------------
Validate that index_size includes both the count word and the complete offset
table before copying n entries.

I tested the following fix:

  size_t w = index64_p ? 8 : 4;

  ...
  || index_size < w
  || n > (index_size - w) / w

After rebuilding libelf and rerunning the same PoC, elf_getarsym() returned a
clean error and no ASan/UBSan issue was reported.

Patch diff tested
-----------------
  diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c
  index 79aa3bbe..2ba867ec 100644
  --- a/libelf/elf_getarsym.c
  +++ b/libelf/elf_getarsym.c
  @@ -163,7 +163,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
  -      int w = index64_p ? 8 : 4;
  +      size_t w = index64_p ? 8 : 4;

  @@ -188,7 +188,8 @@ elf_getarsym (Elf *elf, size_t *ptr)
  -         || n > index_size / w)
  +         || index_size < w
  +         || n > (index_size - w) / w)

Not a duplicate
---------------
This is archive symbol-table parsing in libelf/elf_getarsym.c for /SYM64/.

It is not any of the previously reported DWARF parser issues in .debug_macro,
.debug_str_offsets, .debug_rnglists, .debug_loclists, .debug_frame,
.debug_pubnames, .debug_line, or .debug_addr.

Please include the following credit if this is fixed:

  Reported-by: Karan Kurani <[email protected]>

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

Reply via email to