Giter VIP home page Giter VIP logo

libelfin's Introduction

Libelfin is a from-scratch C++11 library for reading ELF binaries and DWARFv4 debug information.

Quick start

make, and optionally make install. You'll need GCC 4.7 or later.

Features

  • Native C++11 code and interface, designed from scratch to interact well with C++11 features, from range-based for loops to move semantics to enum classes.

  • Libelfin fully implements parsing for Debugging Information Entries (DIEs), the core data structure used by the DWARF format, as well as most DWARFv4 tables.

  • Supports all DWARFv4 DIE value types except location lists and macros.

  • Nearly complete evaluator for DWARFv4 expressions and location descriptions.

  • Complete interpreter for DWARFv4 line tables.

  • Iterators for easily and naturally traversing compilation units, type units, DIE trees, and DIE attribute lists.

  • Every enum value can be pretty-printed.

  • Large collection of type-safe DIE attribute fetchers.

Non-features

Libelfin implements a syntactic layer for DWARF and ELF, but not a semantic layer. Interpreting the information stored in DWARF DIE trees still requires a great deal of understanding of DWARF, but libelfin will make sense of the bytes for you.

Using libelfin

To build against libdwarf++, use, for example

g++ -std=c++11 a.cc $(pkg-config --cflags --libs libdwarf++)

To use a local build of libelfin, set PKG_CONFIG_PATH. For example,

export PKG_CONFIG_PATH=$PWD/elf:$PWD/dwarf

There are various example programs in examples/.

Status

Libelfin is a good start. It's not production-ready and there are many parts of the DWARF specification it does not yet implement, but it's complete enough to be useful for many things and is a good deal more pleasant to use than every other debug info library I've tried.

libelfin's People

Contributors

abenkhadra avatar aclements avatar banshee avatar ccurtsinger avatar diabonas avatar emeryberger avatar jbangert avatar jwilk avatar petterreinholdtsen avatar tartanllama avatar zeldovich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libelfin's Issues

Could libelfin benefit from free security help?

Hello libelfin community! Open Source Technology Improvement Fund is piloting out helping critical projects like libelfin with their security needs. We have some resources dedicated to helping improve security posture and tooling. I wasn't sure how best to reach out. Please let me know if this sounds interesting and who to connect with. Thank you in advance!

Add copyright / license statements to the source files

Would you be willing to add copyright / license statements to the source files? It would make it easier for packages reviewing the license status of the package and make it easier to make the package available in Debian.

It could look something like the comment below:

/*
 * Copyright (c) 2012-2016 Austin T Clements
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

This would allow the tools used in Debian to check copyright status to work well with the code. The copyright year should be adjusted to reflect the modifications done to individual files.

using DW_AT_ranges

Using DW_AT_ranges when DW_AT_high_pc and DW_AT_low_pc is not available in a compilation unit.
We should use the DW_AT_ranges attribute to determine which addresses are contained in a compilation unit.

SEGV in function line_table::line_table at dwarf/line.cc:104

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-lines.

The testcase is dump_line_segv.

I use the following command:

/path-to-libelfin/examples/dump-lines dump_line_segv

and got:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-lines dump_line_segv
==4796== Memcheck, a memory error detector
==4796== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4796== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4796== Command: /path-to-libelfin/examples/dump-lines dump_line_segv
==4796== 
==4796== Invalid write of size 1
==4796==    at 0x47DA88: dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (line.cc:104)
==4796==    by 0x413558: dwarf::compilation_unit::get_line_table() const (dwarf.cc:304)
==4796==    by 0x402CB7: main (dump-lines.cc:41)
==4796==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==4796== 
==4796== 
==4796== Process terminating with default action of signal 11 (SIGSEGV)
==4796==  Access not within mapped region at address 0x0
==4796==    at 0x47DA88: dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (line.cc:104)
==4796==    by 0x413558: dwarf::compilation_unit::get_line_table() const (dwarf.cc:304)
==4796==    by 0x402CB7: main (dump-lines.cc:41)
==4796==  If you believe this happened as a result of a stack
==4796==  overflow in your program's main thread (unlikely but
==4796==  possible), you can try to increase the size of the
==4796==  main thread stack using the --main-stacksize= flag.
==4796==  The main thread stack size used in this run was 8388608.
--- <0>
==4796== 
==4796== HEAP SUMMARY:
==4796==     in use at exit: 81,475 bytes in 72 blocks
==4796==   total heap usage: 132 allocs, 60 frees, 89,399 bytes allocated
==4796== 
==4796== LEAK SUMMARY:
==4796==    definitely lost: 0 bytes in 0 blocks
==4796==    indirectly lost: 0 bytes in 0 blocks
==4796==      possibly lost: 0 bytes in 0 blocks
==4796==    still reachable: 81,475 bytes in 72 blocks
==4796==         suppressed: 0 bytes in 0 blocks
==4796== Rerun with --leak-check=full to see details of leaked memory
==4796== 
==4796== For counts of detected and suppressed errors, rerun with: -v
==4796== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-lines dump_line_segv

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-lines dump_line_segv
ASAN:SIGSEGV
=================================================================
==4850==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000043b335 bp 0x7fff42876e40 sp 0x7fff428769e0 T0)
    #0 0x43b334 in dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /path-to-libelfin-address/dwarf/line.cc:104
    #1 0x40f67b in dwarf::compilation_unit::get_line_table() const /path-to-libelfin-address/dwarf/dwarf.cc:304
    #2 0x403356 in main /path-to-libelfin-address/examples/dump-lines.cc:41
    #3 0x7f82f990682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x403888 in _start (/path-to-libelfin-address/examples/dump-lines+0x403888)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /path-to-libelfin-address/dwarf/line.cc:104 dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
==4850==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

A Segmentation fault in elf.cc:293:56

System info

Ubuntu X64, gcc (Ubuntu 5.5.0-12ubuntu1), dump-syms (latest master 946dde)

Command line

./examples/dump-syms @@

Output

Symbol table '.dynsym':
   Num: Value            Size  Type    Binding Index Name
Segmentation fault

AddressSanitizer output

AddressSanitizer:DEADLYSIGNAL
=================================================================
==62483==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000014 (pc 0x00000052317a bp 0x7ffd570d1fd0 sp 0x7ffd570d1ec0 T0)
==62483==The signal is caused by a READ memory access.
==62483==Hint: address points to the zero page.
    #0 0x523179 in elf::section::as_strtab() const /home/seviezhou/libelfin/elf/elf.cc
    #1 0x525305 in elf::section::as_symtab() const /home/seviezhou/libelfin/elf/elf.cc:293:56
    #2 0x51c45e in main /home/seviezhou/libelfin/examples/dump-syms.cc:32:37
    #3 0x7f2d8cf4c83f in __libc_start_main /build/glibc-e6zv40/glibc-2.23/csu/../csu/libc-start.c:291
    #4 0x41bbd8 in _start (/home/seviezhou/libelfin/examples/dump-syms+0x41bbd8)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/seviezhou/libelfin/elf/elf.cc in elf::section::as_strtab() const
==62483==ABORTING

POC

SEGV-as_symtab-elf-293.zip

Please tag new release

As there has been recent activity on this repo, a new release would be very appreciated.

The most recent release is 8 years old, and there are several important fixes since then.

A new release would make packaging this for distribution much easier

Link to project homepage in README?

For those looking at the libelfin source after finding it in a tarball, it would be useful if the README had a link to the project homepage. Perhaps something you could add?

Unknown-crash in function dwarf::line_table::begin at dwarf/line.cc:153

Hi,

I am running some experiments for AFLAPI and it has found a Unknown-crash in function dwarf::line_table::begin at dwarf/line.cc:153. This bug may allows attackers to cause DoS, so I report it here.

Environment: Ubuntu 18.04 + Clang 6.0

Test target: examples/dump-lines

Testcase here: badelf_unknown_crash.zip

To reproduce:
• Complie the hole project and examples with ASAN

You can use like this: ./dump-lines ./badelf_unknown_crash

🤔 ASAN says:

=================================================================
==5860==ERROR: AddressSanitizer: unknown-crash on address 0x7f7a5bbdd7de at pc 0x0000005a4d22 bp 0x7fff60293fb0 sp 0x7fff60293fa8
READ of size 1 at 0x7f7a5bbdd7de thread T0
#0 0x5a4d21 in dwarf::line_table::iterator::step(dwarf::cursor*) /home/ubuntu/libelfin/dwarf/./internal.hh:211:24
#1 0x59adea in dwarf::line_table::iterator::operator++() /home/ubuntu/libelfin/dwarf/line.cc:280:26
#2 0x59822e in dwarf::line_table::iterator::iterator(dwarf::line_table const*, unsigned long) /home/ubuntu/libelfin/dwarf/line.cc:267:17
#3 0x59822e in dwarf::line_table::begin() const /home/ubuntu/libelfin/dwarf/line.cc:153
#4 0x5188e1 in dump_line_table(dwarf::line_table const&) /home/ubuntu/libelfin/examples/dump-lines.cc:13:25
#5 0x519ff0 in main /home/ubuntu/libelfin/examples/dump-lines.cc:41:17
#6 0x7f7a5a768c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
#7 0x41bf29 in _start (/home/ubuntu/libelfin/examples/dump-lines+0x41bf29)

Address 0x7f7a5bbdd7de is a wild pointer.
SUMMARY: AddressSanitizer: unknown-crash /home/ubuntu/libelfin/dwarf/./internal.hh:211:24 in dwarf::line_table::iterator::step(dwarf::cursor*)
Shadow bytes around the buggy address:
0x0fefcb773aa0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773ab0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773ac0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773ad0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773ae0: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
=>0x0fefcb773af0: fe fe fe fe fe fe fe fe fe fe fe[fe]fe fe fe fe
0x0fefcb773b00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773b10: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773b20: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773b30: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
0x0fefcb773b40: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==5860==ABORTING

Impact:
An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a DoS.

problem with dump_lines.cc example

im getting compelation error in line 37.
dwarf::dwarf dw(dwarf::elf::create_loader(ef));

error:
Problem description: Invalid arguments ' Candidates are: dwarf(const std::shared_ptr &) dwarf(const dwarf::dwarf &) dwarf(dwarf::dwarf &&) '

any idea what can cause the problem?

thanks!

symbol is missing

When I get the elf information for libc.so.6, the symbol __libc_start_call_main is not found, but objdump -tT libc.so.6 finds it.

Global-Buffer-Overflow in function dwarf::line_table::line_table at dwarf/line.cc:107

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump_line.

The testcase is dump_line_global_buffer_overflow.

I use the following command:

/path-to-libelfin/examples/dump-lines dump_line_global_buffer_overflow

and get:

terminate called after throwing an instance of 'dwarf::format_error'
  what():  expected 858944595 arguments for line number opcode 16, got 2
--- <0>
Aborted (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-lines dump_line_global_buffer_overflow
==9235== Memcheck, a memory error detector
==9235== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==9235== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==9235== Command: /path-to-libelfin/examples/dump-lines dump_line_global_buffer_overflow
==9235== 
terminate called after throwing an instance of 'dwarf::format_error'
  what():  expected 858944595 arguments for line number opcode 16, got 2
--- <0>
==9235== 
==9235== Process terminating with default action of signal 6 (SIGABRT)
==9235==    at 0x546A428: raise (raise.c:54)
==9235==    by 0x546C029: abort (abort.c:89)
==9235==    by 0x4ED3DDD: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==9235==    by 0x4EDF895: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==9235==    by 0x4EDF900: std::terminate() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==9235==    by 0x4EDFB54: __cxa_throw (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==9235==    by 0x48226F: dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (line.cc:116)
==9235==    by 0x413558: dwarf::compilation_unit::get_line_table() const (dwarf.cc:304)
==9235==    by 0x402CB7: main (dump-lines.cc:41)
==9235== 
==9235== HEAP SUMMARY:
==9235==     in use at exit: 81,960 bytes in 75 blocks
==9235==   total heap usage: 139 allocs, 64 frees, 90,129 bytes allocated
==9235== 
==9235== LEAK SUMMARY:
==9235==    definitely lost: 0 bytes in 0 blocks
==9235==    indirectly lost: 0 bytes in 0 blocks
==9235==      possibly lost: 144 bytes in 1 blocks
==9235==    still reachable: 81,816 bytes in 74 blocks
==9235==                       of which reachable via heuristic:
==9235==                         stdstring          : 86 bytes in 1 blocks
==9235==         suppressed: 0 bytes in 0 blocks
==9235== Rerun with --leak-check=full to see details of leaked memory
==9235== 
==9235== For counts of detected and suppressed errors, rerun with: -v
==9235== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Aborted (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-lines dump_line_global_buffer_overflow

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-lines dump_line_global_buffer_overflow
=================================================================
==9296==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00000045f374 at pc 0x00000043db90 bp 0x7fff57889ea0 sp 0x7fff57889e90
READ of size 4 at 0x00000045f374 thread T0
    #0 0x43db8f in dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /path-to-libelfin-address/dwarf/line.cc:107
    #1 0x40f67b in dwarf::compilation_unit::get_line_table() const /path-to-libelfin-address/dwarf/dwarf.cc:304
    #2 0x403356 in main /path-to-libelfin-address/examples/dump-lines.cc:41
    #3 0x7f0bb309682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x403888 in _start (/path-to-libelfin-address/examples/dump-lines+0x403888)

0x00000045f374 is located 0 bytes to the right of global variable 'opcode_lengths' defined in 'line.cc:15:18' (0x45f340) of size 52
SUMMARY: AddressSanitizer: global-buffer-overflow /path-to-libelfin-address/dwarf/line.cc:107 dwarf::line_table::line_table(std::shared_ptr<dwarf::section> const&, unsigned long, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
Shadow bytes around the buggy address:
  0x000080083e10: f9 f9 f9 f9 00 00 00 00 03 f9 f9 f9 f9 f9 f9 f9
  0x000080083e20: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9
  0x000080083e30: 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 00 02 f9 f9
  0x000080083e40: f9 f9 f9 f9 00 00 00 00 03 f9 f9 f9 f9 f9 f9 f9
  0x000080083e50: 07 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
=>0x000080083e60: 04 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00[04]f9
  0x000080083e70: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080083e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080083e90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080083ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080083eb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==9296==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS) even buffer overflow.

DESTDIR support in make install

Setting custom install location independent from $PREFIX should be implemented. For example, I want make DESTDIR=/tmp/pkg PREFIX=/usr install to install libraries and headers to /tmp/pkg/usr, but write libdir and includedir entries to pkg-config files based only on $PREFIX (like $PREFIX/lib and $PREFIX/include, but not $DESTDIR/$PREFIX/whatever).

The main reason for it is packaging. When you are creating a package you often need to install the program or library to a temporary directory, which then will be archived and will go to the package. Simply setting PREFIX doesn't help because it will make pkg-config entries to look like this (incorrect): /path/to/pkgdir/usr/include instead of this (correct): /usr/include. You can see it in detail in this terminal transcript: https://gist.github.com/kodo-pp/482bef5afbece8bdb3c01bac461b1e03

SEGV in function elf::section::as_strtab at elf/elf.cc:284

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-syms.

The testcase is dump_syms_segv.

I use the following command:

/path-to-libelfin/examples/dump-syms dump_syms_segv

and get:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-syms dump_syms_segv
==13575== Memcheck, a memory error detector
==13575== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13575== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==13575== Command: /path-to-libelfin/examples/dump-syms dump_syms_segv
==13575== 
==13575== Invalid read of size 4
==13575==    at 0x40A8A3: elf::section::as_strtab() const (elf.cc:284)
==13575==    by 0x40BD91: elf::section::as_symtab() const (elf.cc:295)
==13575==    by 0x401FD8: main (dump-syms.cc:32)
==13575==  Address 0x14 is not stack'd, malloc'd or (recently) free'd
==13575== 
==13575== 
==13575== Process terminating with default action of signal 11 (SIGSEGV)
==13575==  Access not within mapped region at address 0x14
==13575==    at 0x40A8A3: elf::section::as_strtab() const (elf.cc:284)
==13575==    by 0x40BD91: elf::section::as_symtab() const (elf.cc:295)
==13575==    by 0x401FD8: main (dump-syms.cc:32)
==13575==  If you believe this happened as a result of a stack
==13575==  overflow in your program's main thread (unlikely but
==13575==  possible), you can try to increase the size of the
==13575==  main thread stack using the --main-stacksize= flag.
==13575==  The main thread stack size used in this run was 8388608.
Symbol table '.dynsym':
   Num: Value            Size  Type    Binding Index Name
==13575== 
==13575== HEAP SUMMARY:
==13575==     in use at exit: 79,384 bytes in 50 blocks
==13575==   total heap usage: 62 allocs, 12 frees, 84,776 bytes allocated
==13575== 
==13575== LEAK SUMMARY:
==13575==    definitely lost: 0 bytes in 0 blocks
==13575==    indirectly lost: 0 bytes in 0 blocks
==13575==      possibly lost: 0 bytes in 0 blocks
==13575==    still reachable: 79,384 bytes in 50 blocks
==13575==         suppressed: 0 bytes in 0 blocks
==13575== Rerun with --leak-check=full to see details of leaked memory
==13575== 
==13575== For counts of detected and suppressed errors, rerun with: -v
==13575== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-syms dump_syms_segv

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-syms dump_syms_segv
ASAN:SIGSEGV
=================================================================
==13619==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000014 (pc 0x000000409050 bp 0x7ffdc34bbe50 sp 0x7ffdc34bbe10 T0)
    #0 0x40904f in elf::section::as_strtab() const /path-to-libelfin-address/elf/elf.cc:284
    #1 0x4099f5 in elf::section::as_symtab() const /path-to-libelfin-address/elf/elf.cc:295
    #2 0x4023fa in main /path-to-libelfin-address/examples/dump-syms.cc:32
    #3 0x7fae884aa82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x403728 in _start (/path-to-libelfin-address/examples/dump-syms+0x403728)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /path-to-libelfin-address/elf/elf.cc:284 elf::section::as_strtab() const
==13619==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

Check in autogenerated "to_string.cc" files

Compiling the project with CMake, Ninja and GCC10 works perfectly fine with not much effort and with no warnings but the linker complains about undefined references to "dwarf::to_string" functions. Trying to manually run the python script fails, probably because of a wrong Python version, which is super annoying. I think it would be better to just check in the generated files to avoid dealing with Python.

SEGV in function dwarf::to_string at dwarf/value.cc:300

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-tree.

The testcase is dump_tree_segv2.

I use the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv2

and get:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-tree dump_tree_segv2
==22094== Memcheck, a memory error detector
==22094== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22094== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==22094== Command: /path-to-libelfin/examples/dump-tree dump_tree_segv2
==22094== 
==22094== Invalid read of size 1
==22094==    at 0x44CE58: dwarf::to_string[abi:cxx11](dwarf::value const&) (value.cc:300)
==22094==    by 0x4031B0: dump_tree (dump-tree.cc:19)
==22094==    by 0x4031B0: main (dump-tree.cc:43)
==22094==  Address 0x402a000 is not stack'd, malloc'd or (recently) free'd
==22094== 
==22094== 
==22094== Process terminating with default action of signal 11 (SIGSEGV)
==22094==  Access not within mapped region at address 0x402A000
==22094==    at 0x44CE58: dwarf::to_string[abi:cxx11](dwarf::value const&) (value.cc:300)
==22094==    by 0x4031B0: dump_tree (dump-tree.cc:19)
==22094==    by 0x4031B0: main (dump-tree.cc:43)
==22094==  If you believe this happened as a result of a stack
==22094==  overflow in your program's main thread (unlikely but
==22094==  possible), you can try to increase the size of the
==22094==  main thread stack using the --main-stacksize= flag.
==22094==  The main thread stack size used in this run was 8388608.
--- <0>
<b> DW_TAG_compile_unit
      DW_AT_producer 
      DW_AT_language 12 byte block: cb 0 0 0 12 0 0 0 26 5 40 0
      DW_AT_name long unsigned int
==22094== 
==22094== HEAP SUMMARY:
==22094==     in use at exit: 111,921 bytes in 68 blocks
==22094==   total heap usage: 145 allocs, 77 frees, 150,879 bytes allocated
==22094== 
==22094== LEAK SUMMARY:
==22094==    definitely lost: 0 bytes in 0 blocks
==22094==    indirectly lost: 0 bytes in 0 blocks
==22094==      possibly lost: 0 bytes in 0 blocks
==22094==    still reachable: 111,921 bytes in 68 blocks
==22094==         suppressed: 0 bytes in 0 blocks
==22094== Rerun with --leak-check=full to see details of leaked memory
==22094== 
==22094== For counts of detected and suppressed errors, rerun with: -v
==22094== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv2
Segmentation fault (core dumped)

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-tree dump_tree_segv2
=================================================================
==22134==ERROR: AddressSanitizer: unknown-crash on address 0x7f6f8b233000 at pc 0x000000428213 bp 0x7ffd7ae677d0 sp 0x7ffd7ae677c0
READ of size 1 at 0x7f6f8b233000 thread T0
    #0 0x428212 in dwarf::to_string[abi:cxx11](dwarf::value const&) /path-to-libelfin-address/dwarf/value.cc:300
    #1 0x403aec in dump_tree(dwarf::die const&, int) /path-to-libelfin-address/examples/dump-tree.cc:19
    #2 0x403361 in main /path-to-libelfin-address/examples/dump-tree.cc:43
    #3 0x7f6f8971282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x403878 in _start (/path-to-libelfin-address/examples/dump-tree+0x403878)

AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: unknown-crash /path-to-libelfin-address/dwarf/value.cc:300 dwarf::to_string[abi:cxx11](dwarf::value const&)
Shadow bytes around the buggy address:
  0x0fee7163e5b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fee7163e5c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fee7163e5d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fee7163e5e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fee7163e5f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0fee7163e600:[fe]fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fee7163e610: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fee7163e620: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fee7163e630: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fee7163e640: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
  0x0fee7163e650: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==22134==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

Building examples doesn't work

I'm trying to build the examples and started with dump-lines.cc following the documentation. However, build fails to due missing type definitions and symbols. For instance, type definitions for section_offset, section_length and DW_AT are missing. I couldn't find the missing definitions in the sources. Therefore, I'm assuming that you depend on some external library. Can you please provide the dependencies of libelfin.

dwarf 5 support

This is a great lib to parse ELF. Currently it doesn't support dwarf 5, but newer versions of linux distribution are already using dwarf 5. It should be great to add support for dwarf 5. Thanks!

found integer overflow bugs

found integer overflow bug

by source code audit,i just found integer overflow at function load(...) which return pointer on mmap address.
var offset and size can assumed as u64
so in this case, if offset and size big enough,it may cause Addition overflow and return a pointer points to invalid address.

mmap_loader.cc:48:

        const void *load(off_t offset, size_t size)
        {
                if (offset + size > lim) //         integer overflow here
                        throw range_error("offset exceeds file size");
                return (const char*)base + offset;
        }

here a sample:
a.zip
which i just modify the offset of program_head to -1(0xffffffffffffffff)

$readelf -h a
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x401040
  Start of program headers:          -1 (bytes into file)    //  modify offset here
  Start of section headers:          23000 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30
readelf: a: Error: Reading 728 bytes extends past end of file for program headers

use ./dump-segments a
Screenshot from 2023-01-14 01-26-41

and this is a batch problem at elf.cc which cause segmentation violation

elf/elf.cc
  70,44:         } *core_hdr = (struct core_hdr*)l->load(0, sizeof *core_hdr);
  87,30:         const void *hdr = l->load(0, hdr_size);
  97,35:         const void *seg_data = l->load(m->hdr.phoff,
  105,35:         const void *sec_data = l->load(m->hdr.shoff,
  191,46:                 m->data = m->f.get_loader()->load(m->hdr.offset,
  270,46:                 m->data = m->f.get_loader()->load(m->hdr.offset, m->hdr.size);

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

Add MSVC support

This would be a nice library to have, but it seems MSVC isn't a supported toolchain.

I'm trying to make it work myself right now, and I may submit a PR

dwarf/small_vector.hh destructs new buffer on calls to reserve()

Hi! I've been working on the memory leak in relation to one of my own projects and stumbled across this bizarre behavior in the small_vector.hh class used by the dwarf folder of libelfin.

Specifically, calls to small_vector::reserve() will cause the small_vector to copy the objects in its buffer, destroy the newly copied objects, then release the old buffer (of not-yet-destroyed objects.)

I built a few tests to examine the issue, and check whether this was in-fact proper use of placement-new. (It doesn't appear to be.)

test.cpp makes this behavior minimally apparent, by removing the rest of the small_vector.hh file and just performing the problematic operations in reserve, specifically within the "reserve2" section.

test_their.cpp uses the unmodified small_vector.hh class to show the exact same behavior as test.cpp.

test_mine.cpp uses small_vector_fixed.hh which changes the problematic destruction to destroy the objects in the old buffer and, if available on the type T, uses move semantics to relocate the objects in the buffer.

All tests work on a type A which simply marks its ID in order of construction, its validity under C++ object lifetimes, whether it was copy constructed, whether it was moved-into, and whether it was moved-from.

tl;dr: small_vector.hh runs destructors on the new buffer on reserve() calls instead of the old one. small_vector_fixed.hh in this tests archive doesn't do that, and will std::move the Ts if they have move semantics.

SEGV in function dwarf::cursor::skip_form at dwarf/cursor.cc:191

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-tree.

The testcase is dump_tree_segv3.

I use the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv3

and get:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-tree dump_tree_segv3
==423== Memcheck, a memory error detector
==423== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==423== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==423== Command: /path-to-libelfin/examples/dump-tree dump_tree_segv3
==423== 
==423== Invalid read of size 1
==423==    at 0x42C998: uleb128 (internal.hh:154)
==423==    by 0x42C998: dwarf::cursor::skip_form(dwarf::DW_FORM) (cursor.cc:147)
==423==    by 0x433B4C: dwarf::die::read(unsigned long) (die.cc:51)
==423==    by 0x414B7C: dwarf::unit::root() const (dwarf.cc:195)
==423==    by 0x402CD0: main (dump-tree.cc:43)
==423==  Address 0x750280b3 is not stack'd, malloc'd or (recently) free'd
==423== 
==423== 
==423== Process terminating with default action of signal 11 (SIGSEGV)
==423==  Access not within mapped region at address 0x750280B3
==423==    at 0x42C998: uleb128 (internal.hh:154)
==423==    by 0x42C998: dwarf::cursor::skip_form(dwarf::DW_FORM) (cursor.cc:147)
==423==    by 0x433B4C: dwarf::die::read(unsigned long) (die.cc:51)
==423==    by 0x414B7C: dwarf::unit::root() const (dwarf.cc:195)
==423==    by 0x402CD0: main (dump-tree.cc:43)
==423==  If you believe this happened as a result of a stack
==423==  overflow in your program's main thread (unlikely but
==423==  possible), you can try to increase the size of the
==423==  main thread stack using the --main-stacksize= flag.
==423==  The main thread stack size used in this run was 8388608.
--- <0>
==423== 
==423== HEAP SUMMARY:
==423==     in use at exit: 80,652 bytes in 63 blocks
==423==   total heap usage: 120 allocs, 57 frees, 88,208 bytes allocated
==423== 
==423== LEAK SUMMARY:
==423==    definitely lost: 0 bytes in 0 blocks
==423==    indirectly lost: 0 bytes in 0 blocks
==423==      possibly lost: 0 bytes in 0 blocks
==423==    still reachable: 80,652 bytes in 63 blocks
==423==         suppressed: 0 bytes in 0 blocks
==423== Rerun with --leak-check=full to see details of leaked memory
==423== 
==423== For counts of detected and suppressed errors, rerun with: -v
==423== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv3

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-tree dump_tree_segv3
ASAN:SIGSEGV
=================================================================
==451==ERROR: AddressSanitizer: SEGV on unknown address 0x7f84237480b3 (pc 0x0000004167e8 bp 0x7fff99fc19f0 sp 0x7fff99fc18f0 T0)
    #0 0x4167e7 in dwarf::cursor::skip_form(dwarf::DW_FORM) /path-to-libelfin-address/dwarf/cursor.cc:191
    #1 0x4183b3 in dwarf::die::read(unsigned long) /path-to-libelfin-address/dwarf/die.cc:51
    #2 0x40f548 in dwarf::unit::root() const /path-to-libelfin-address/dwarf/dwarf.cc:195
    #3 0x403357 in main /path-to-libelfin-address/examples/dump-tree.cc:43
    #4 0x7f83b0c2982f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #5 0x403878 in _start (/path-to-libelfin-address/examples/dump-tree+0x403878)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /path-to-libelfin-address/dwarf/cursor.cc:191 dwarf::cursor::skip_form(dwarf::DW_FORM)
==451==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

Fail to work on s390 in Debian

The source build but fail to work on s390 when built for Debian. See https://buildd.debian.org/status/fetch.php?pkg=libelfin&arch=s390x&ver=0.2-5&stamp=1479224801 for the complete build log. This is the error:

PASS dump-segments golden-gcc-4.9.2/example
FAIL dump-lines golden-gcc-4.9.2/example
	./test.sh: line 24: 24954 Aborted                 ../examples/dump-$dump golden-$compiler/$binary 1>&$output.out
	failed: exit status 134
	--- golden-gcc-4.9.2/lines	2016-09-28 18:00:31.000000000 +0000
	+++ /tmp/libelfin.iav8gPN88i.out	2016-11-15 15:46:34.004275388 +0000
	@@ -1,10 +1,2 @@
	---- <0>
	-x/example.c                                    2            0x4004b6
	-x/example.c                                    3            0x4004c2
	-x/example.c                                    4            0x4004c8
	-x/example.c                                    5            0x4004cd
	-x/example.c                                    6            0x4004eb
	-x/example.c                                    9            0x4004f2
	-x/example.c                                   10            0x400501
	-x/example.c                                   11            0x40050b
	-
	+terminate called after throwing an instance of 'dwarf::format_error'
	+  what():  unknown compilation unit version 1024
PASS dump-syms golden-gcc-4.9.2/example
FAIL dump-tree golden-gcc-4.9.2/example
	./test.sh: line 24: 24959 Aborted                 ../examples/dump-$dump golden-$compiler/$binary 1>&$output.out
	failed: exit status 134
	--- golden-gcc-4.9.2/tree	2016-09-28 18:00:31.000000000 +0000
	+++ /tmp/libelfin.iav8gPN88i.out	2016-11-15 15:46:34.012275388 +0000
	@@ -1,65 +1,2 @@
	---- <0>
	-<b> DW_TAG_compile_unit
	-      DW_AT_producer GNU C 4.9.2 -mtune=generic -march=x86-64 -g -fdebug-prefix-map=/home/amthrax/r/libelfin/test=x
	-      DW_AT_language 0x1
	-      DW_AT_name example.c
	-      DW_AT_comp_dir x
	-      DW_AT_low_pc 0x4004b6
	-      DW_AT_high_pc 0x57
	-      DW_AT_stmt_list <line 0x0>
	- <2b> DW_TAG_subprogram
	-       DW_AT_external true
	-       DW_AT_name fib
	-       DW_AT_decl_file 0x1
	-       DW_AT_decl_line 0x1
	-       DW_AT_prototyped true
	-       DW_AT_type <0x59>
	-       DW_AT_low_pc 0x4004b6
	-       DW_AT_high_pc 0x3c
	-       DW_AT_frame_base <exprloc>
	-       (DW_AT)0x2116 true
	-       DW_AT_sibling <0x59>
	-  <4c> DW_TAG_formal_parameter
	-        DW_AT_name x
	-        DW_AT_decl_file 0x1
	-        DW_AT_decl_line 0x1
	-        DW_AT_type <0x59>
	-        DW_AT_location <exprloc>
	- <59> DW_TAG_base_type
	-       DW_AT_byte_size 0x4
	-       DW_AT_encoding 0x5
	-       DW_AT_name int
	- <60> DW_TAG_subprogram
	-       DW_AT_external true
	-       DW_AT_name main
	-       DW_AT_decl_file 0x1
	-       DW_AT_decl_line 0x8
	-       DW_AT_prototyped true
	-       DW_AT_type <0x59>
	-       DW_AT_low_pc 0x4004f2
	-       DW_AT_high_pc 0x1b
	-       DW_AT_frame_base <exprloc>
	-       (DW_AT)0x2116 true
	-       DW_AT_sibling <0x9e>
	-  <81> DW_TAG_formal_parameter
	-        DW_AT_name argc
	-        DW_AT_decl_file 0x1
	-        DW_AT_decl_line 0x8
	-        DW_AT_type <0x59>
	-        DW_AT_location <exprloc>
	-  <8f> DW_TAG_formal_parameter
	-        DW_AT_name argv
	-        DW_AT_decl_file 0x1
	-        DW_AT_decl_line 0x8
	-        DW_AT_type <0x9e>
	-        DW_AT_location <exprloc>
	- <9e> DW_TAG_pointer_type
	-       DW_AT_byte_size 0x8
	-       DW_AT_type <0xa4>
	- <a4> DW_TAG_pointer_type
	-       DW_AT_byte_size 0x8
	-       DW_AT_type <0xaa>
	- <aa> DW_TAG_base_type
	-       DW_AT_byte_size 0x1
	-       DW_AT_encoding 0x6
	-       DW_AT_name char
	+terminate called after throwing an instance of 'dwarf::format_error'
	+  what():  unknown compilation unit version 1024
2 test(s) failed

Thank you very much for providing the self test in the code. It avoided uploading broken binaries to Debian. :)

SEGV in function dwarf::cursor::uleb128 at dwarf/internal.hh:154

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-tree.

The testcase is dump_tree_segv.

I use the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv

and get:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-tree dump_tree_segv
==21176== Memcheck, a memory error detector
==21176== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21176== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==21176== Command: /path-to-libelfin/examples/dump-tree dump_tree_segv
==21176== 
==21176== Invalid read of size 1
==21176==    at 0x431161: uleb128 (internal.hh:154)
==21176==    by 0x431161: dwarf::die::read(unsigned long) (die.cc:35)
==21176==    by 0x44869E: dwarf::value::as_reference() const (value.cc:215)
==21176==    by 0x44C482: dwarf::to_string[abi:cxx11](dwarf::value const&) (value.cc:324)
==21176==    by 0x404A3B: dump_tree(dwarf::die const&, int) (dump-tree.cc:19)
==21176==    by 0x4035C1: dump_tree (dump-tree.cc:21)
==21176==    by 0x4035C1: main (dump-tree.cc:43)
==21176==  Address 0x5b02809b is not stack'd, malloc'd or (recently) free'd
==21176== 
==21176== 
==21176== Process terminating with default action of signal 11 (SIGSEGV)
==21176==  Access not within mapped region at address 0x5B02809B
==21176==    at 0x431161: uleb128 (internal.hh:154)
==21176==    by 0x431161: dwarf::die::read(unsigned long) (die.cc:35)
==21176==    by 0x44869E: dwarf::value::as_reference() const (value.cc:215)
==21176==    by 0x44C482: dwarf::to_string[abi:cxx11](dwarf::value const&) (value.cc:324)
==21176==    by 0x404A3B: dump_tree(dwarf::die const&, int) (dump-tree.cc:19)
==21176==    by 0x4035C1: dump_tree (dump-tree.cc:21)
==21176==    by 0x4035C1: main (dump-tree.cc:43)
==21176==  If you believe this happened as a result of a stack
==21176==  overflow in your program's main thread (unlikely but
==21176==  possible), you can try to increase the size of the
==21176==  main thread stack using the --main-stacksize= flag.
==21176==  The main thread stack size used in this run was 8388608.
--- <0>
<b> DW_TAG_compile_unit
      DW_AT_producer 
      DW_AT_language 4 byte block: cb 0 0 0
      DW_AT_name 
      DW_AT_comp_dir 
      DW_AT_low_pc 0x0
      DW_AT_high_pc 0x1500000000000000
      DW_AT_stmt_list <line 0x0>
 <2d> DW_TAG_base_type
       DW_AT_byte_size 0x8
       DW_AT_encoding 0x7
       DW_AT_name long unsigned int
 <34> DW_TAG_base_type
       DW_AT_byte_size 0x1
       DW_AT_encoding 0x8
       DW_AT_name 
 <3b> DW_TAG_base_type
       DW_AT_byte_size 0x2
       DW_AT_encoding 0x7
       DW_AT_name 
 <42> DW_TAG_base_type
       DW_AT_byte_size 0x4
       DW_AT_encoding 0x7
       DW_AT_name 
 <49> DW_TAG_base_type
       DW_AT_byte_size 0x1
       DW_AT_encoding 0x6
       DW_AT_name 
 <50> DW_TAG_base_type
       DW_AT_byte_size 0x2
       DW_AT_encoding 0x5
       DW_AT_name 
 <57> DW_TAG_base_type
       DW_AT_byte_size 0x4
       DW_AT_encoding 0x5
       DW_AT_name int
 <5e> DW_TAG_base_type
       DW_AT_byte_size 0x8
       DW_AT_encoding 0x5
       DW_AT_name 
 <65> DW_TAG_base_type
       DW_AT_byte_size 0x8
       DW_AT_encoding 0x7
       DW_AT_name 
 <6c> DW_TAG_base_type
       DW_AT_byte_size 0x1
       DW_AT_encoding 0x6
       DW_AT_name 
 <73> DW_TAG_subprogram
       DW_AT_external true
       DW_AT_name 
       DW_AT_decl_file 0x1
       DW_AT_decl_line 0x3
==21176== 
==21176== HEAP SUMMARY:
==21176==     in use at exit: 81,552 bytes in 68 blocks
==21176==   total heap usage: 182 allocs, 114 frees, 92,963 bytes allocated
==21176== 
==21176== LEAK SUMMARY:
==21176==    definitely lost: 0 bytes in 0 blocks
==21176==    indirectly lost: 0 bytes in 0 blocks
==21176==      possibly lost: 0 bytes in 0 blocks
==21176==    still reachable: 81,552 bytes in 68 blocks
==21176==         suppressed: 0 bytes in 0 blocks
==21176== Rerun with --leak-check=full to see details of leaked memory
==21176== 
==21176== For counts of detected and suppressed errors, rerun with: -v
==21176== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-tree dump_tree_segv

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-tree dump_tree_segv
ASAN:SIGSEGV
=================================================================
==21215==ERROR: AddressSanitizer: SEGV on unknown address 0x7f519be3409b (pc 0x000000417cb5 bp 0x7ffddf8f6830 sp 0x7ffddf8f6730 T0)
    #0 0x417cb4 in dwarf::cursor::uleb128() /path-to-libelfin-address/dwarf/internal.hh:154
    #1 0x417cb4 in dwarf::die::read(unsigned long) /path-to-libelfin-address/dwarf/die.cc:35
    #2 0x422a25 in dwarf::value::as_reference() const /path-to-libelfin-address/dwarf/value.cc:215
    #3 0x425711 in dwarf::to_string[abi:cxx11](dwarf::value const&) /path-to-libelfin-address/dwarf/value.cc:324
    #4 0x403aec in dump_tree(dwarf::die const&, int) /path-to-libelfin-address/examples/dump-tree.cc:19
    #5 0x403bea in dump_tree(dwarf::die const&, int) /path-to-libelfin-address/examples/dump-tree.cc:21
    #6 0x403361 in main /path-to-libelfin-address/examples/dump-tree.cc:43
    #7 0x7f514331582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #8 0x403878 in _start (/path-to-libelfin-address/examples/dump-tree+0x403878)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /path-to-libelfin-address/dwarf/internal.hh:154 dwarf::cursor::uleb128()
==21215==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

New release

I'm working on packaging libelfin (as a dependency for coz), and I'd appreciate it if you can make a new release. The latest one (0.1) has no "install" target and still does not use "-fPIC", and I'd prefer not to package a snapshot.

SEGV in function dwarf::cursor::skip_form at dwarf/cursor.cc:181

Tested in Ubuntu 16.04, 64bit.

The tested program is the example program dump-lines.

The testcase is dump_line_segv2.

I use the following command:

/path-to-libelfin/examples/dump-lines dump_line_segv2

and got:

Segmentation fault (core dumped)

I use valgrind to analysis the bug and get the below information (absolute path information omitted):

valgrind /path-to-libelfin/examples/dump-lines dump_line_segv2
==11807== Memcheck, a memory error detector
==11807== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11807== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==11807== Command: /path-to-libelfin/examples/dump-lines dump_line_segv2
==11807== 
==11807== Invalid read of size 1
==11807==    at 0x42A39C: dwarf::cursor::skip_form(dwarf::DW_FORM) (cursor.cc:181)
==11807==    by 0x431FAC: dwarf::die::read(unsigned long) (die.cc:51)
==11807==    by 0x412EFC: dwarf::unit::root() const (dwarf.cc:195)
==11807==    by 0x413177: dwarf::compilation_unit::get_line_table() const (dwarf.cc:291)
==11807==    by 0x402CB7: main (dump-lines.cc:41)
==11807==  Address 0x10cd80af is not stack'd, malloc'd or (recently) free'd
==11807== 
==11807== 
==11807== Process terminating with default action of signal 11 (SIGSEGV)
==11807==  Access not within mapped region at address 0x10CD80AF
==11807==    at 0x42A39C: dwarf::cursor::skip_form(dwarf::DW_FORM) (cursor.cc:181)
==11807==    by 0x431FAC: dwarf::die::read(unsigned long) (die.cc:51)
==11807==    by 0x412EFC: dwarf::unit::root() const (dwarf.cc:195)
==11807==    by 0x413177: dwarf::compilation_unit::get_line_table() const (dwarf.cc:291)
==11807==    by 0x402CB7: main (dump-lines.cc:41)
==11807==  If you believe this happened as a result of a stack
==11807==  overflow in your program's main thread (unlikely but
==11807==  possible), you can try to increase the size of the
==11807==  main thread stack using the --main-stacksize= flag.
==11807==  The main thread stack size used in this run was 8388608.
--- <0>
==11807== 
==11807== HEAP SUMMARY:
==11807==     in use at exit: 80,832 bytes in 64 blocks
==11807==   total heap usage: 122 allocs, 58 frees, 88,640 bytes allocated
==11807== 
==11807== LEAK SUMMARY:
==11807==    definitely lost: 0 bytes in 0 blocks
==11807==    indirectly lost: 0 bytes in 0 blocks
==11807==      possibly lost: 0 bytes in 0 blocks
==11807==    still reachable: 80,832 bytes in 64 blocks
==11807==         suppressed: 0 bytes in 0 blocks
==11807== Rerun with --leak-check=full to see details of leaked memory
==11807== 
==11807== For counts of detected and suppressed errors, rerun with: -v
==11807== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

I use AddressSanitizer to build ffjpeg and running it with the following command:

/path-to-libelfin/examples/dump-lines dump_line_segv2

This is the ASAN information (absolute path information omitted):

/path-to-libelfin-address/examples/dump-lines dump_line_segv2
ASAN:SIGSEGV
=================================================================
==11879==ERROR: AddressSanitizer: SEGV on unknown address 0x7fc5c7ec50af (pc 0x000000416720 bp 0x7fffc67fa700 sp 0x7fffc67fa600 T0)
    #0 0x41671f in dwarf::cursor::skip_form(dwarf::DW_FORM) /path-to-libelfin-address/dwarf/cursor.cc:181
    #1 0x418023 in dwarf::die::read(unsigned long) /path-to-libelfin-address/dwarf/die.cc:51
    #2 0x40f158 in dwarf::unit::root() const /path-to-libelfin-address/dwarf/dwarf.cc:195
    #3 0x40f41e in dwarf::compilation_unit::get_line_table() const /path-to-libelfin-address/dwarf/dwarf.cc:291
    #4 0x403356 in main /path-to-libelfin-address/examples/dump-lines.cc:41
    #5 0x7fc5b96f682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #6 0x403888 in _start (/path-to-libelfin-address/examples/dump-lines+0x403888)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /path-to-libelfin-address/dwarf/cursor.cc:181 dwarf::cursor::skip_form(dwarf::DW_FORM)
==11879==ABORTING

An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a Denial of Service (DoS).

Support for relocation sections

Hi there,

Awesome library, it worked great and easy to integrate onto my embedded target.

However, I don't see how to read the entries in the relocation sections?

Memory leaks in `make check` with address sanitizer.

I'm trying to use libelfin in a personal project, but when I turned on address sanitizer in my unit tests I noticed some leaks coming from this library. I was able to reproduce these leaks in libelfin's own test suite:

commit ac45a094fadba77ad840063fb7aab82571546be0
Author: James Moore <[email protected]>
Date:   Sat Aug 25 09:36:46 2018 -0700

    Added #include <errno.h> to files that use errno.
    
    This fixes #32.

gfg@rom ~/git/uprofile/ext/libelfin $ make clean
make -C elf clean
make[1]: Entering directory '/home/gfg/git/uprofile/ext/libelfin/elf'
rm -f  libelf++.a elf.o mmap_loader.o to_string.o to_string.cc libelf++.so.* libelf++.so libelf++.pc
make[1]: Leaving directory '/home/gfg/git/uprofile/ext/libelfin/elf'
make -C dwarf clean
make[1]: Entering directory '/home/gfg/git/uprofile/ext/libelfin/dwarf'
rm -f  libdwarf++.a dwarf.o cursor.o die.o value.o abbrev.o expr.o rangelist.o line.o attrs.o die_str_map.o elf.o to_string.o to_string.cc libdwarf++.so.* libdwarf++.so libdwarf++.pc
make[1]: Leaving directory '/home/gfg/git/uprofile/ext/libelfin/dwarf'
gfg@rom ~/git/uprofile/ext/libelfin $ cd elf
gfg@rom ~/git/uprofile/ext/libelfin/elf $ make LDFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address CXX=g++-7
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o elf.o elf.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o mmap_loader.o mmap_loader.cc
python3 enum-print.py -u --hex --no-type --mask shf --mask pf \
	-x loos -x hios -x loproc -x hiproc < data.hh >> to_string.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o to_string.o to_string.cc
ar rcs libelf++.a elf.o mmap_loader.o to_string.o
ln -s libelf++.so.0 libelf++.so
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC -fsanitize=address -shared -Wl,-soname,libelf++.so.0 -o libelf++.so.0 elf.o mmap_loader.o to_string.o
gfg@rom ~/git/uprofile/ext/libelfin/elf $ cd ../dwarf
gfg@rom ~/git/uprofile/ext/libelfin/dwarf $ make LDFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address CXX=g++-7
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o dwarf.o dwarf.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o cursor.o cursor.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o die.o die.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o value.o value.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o abbrev.o abbrev.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o expr.o expr.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o rangelist.o rangelist.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o line.o line.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o attrs.o attrs.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o die_str_map.o die_str_map.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o elf.o elf.cc
python3 ../elf/enum-print.py < dwarf++.hh >> to_string.cc
python3 ../elf/enum-print.py -s _ -u --hex -x hi_user -x lo_user < data.hh >> to_string.cc
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC   -c -o to_string.o to_string.cc
ar rcs libdwarf++.a dwarf.o cursor.o die.o value.o abbrev.o expr.o rangelist.o line.o attrs.o die_str_map.o elf.o to_string.o
g++-7 -fsanitize=address -std=c++0x -Wall -fPIC -fsanitize=address -shared -Wl,-soname,libdwarf++.so.0 -o libdwarf++.so.0 dwarf.o cursor.o die.o value.o abbrev.o expr.o rangelist.o line.o attrs.o die_str_map.o elf.o to_string.o
ln -s libdwarf++.so.0 libdwarf++.so
gfg@rom ~/git/uprofile/ext/libelfin/dwarf $ cd ..

Then just run the tests:

gfg@rom ~/git/uprofile/ext/libelfin $ make check LDFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address CXX=g++-7
cd test && ./test.sh
FAIL dump-sections golden-gcc-4.9.2/example
	failed: exit status 1
	--- golden-gcc-4.9.2/sections	2019-04-24 18:26:21.146740912 -0700
	+++ /tmp/libelfin.QNDlEwzNUP.out	2019-05-14 13:04:42.896855383 -0700
	@@ -56,17 +56,90 @@
	        0000000000000039 0000000000000001 (shf)0x30       undef    0     1

<snip>

	+SUMMARY: AddressSanitizer: 8460 byte(s) leaked in 66 allocation(s).
6 test(s) failed
Makefile:14: recipe for target 'check' failed
make: *** [check] Error 1
gfg@rom ~/git/uprofile/ext/libelfin $ 

Sorting sections?

Hi. Thank you for library, it is really easy to use it. However i dont understand one thing. How to sort sections vector returned by elf::sections() method? Getting error, when i using std::sort() like this:

bool compare_sections_name(const elf::section & section1, const elf::section & section2)
{
  return section1.get_name() < section2.get_name();
}

// later in main
elf::elf f(elf::create_mmap_loader(fd));
auto sorted = f.sections();
std::sort(sorted.begin(), sorted.end(), compare_sections_by_name);

AFAIK it happens because elf::section class must implement assignment operator and it does not. So i suggest to add line to class declaration (and probably do same for segment class):
section & operator = (section const &) = default;

The only my idea how to do sorting now is to get vector of pointers sections and sort pointers, but i dont like such workaround.

Is this project still being developed?

Hi. As you might have seen, I am considering to include this library into Debian, as a dependency for the Coz profiler. But the old pull request with not followup for almost a year and the old issue with no reply since December last year make me worried. Is this library still being developed?

The reason is that it is a lot more work to take over a library with no active development than it is to just package a well maintained software system for Debian.

build failure with LLVM 10

fails with LLVM 10, works with LLVM 9:

$ cat x.cpp
#include <elf/elf++.hh>
int main(int argc, char *argv[]) { return 0; }

$ clang++ -std=c++11 -I/usr/include/libelfin -c x.cpp
In file included from x.cpp:1:
In file included from /usr/include/libelfin/elf/elf++.hh:9:
/usr/include/libelfin/elf/data.hh:558:22: error: cannot assign to non-static data member within const member function 'set_binding'
info = (info & 0xF) | ((unsigned char)v << 4);
~~~~ ^
/usr/include/libelfin/elf/data.hh:556:14: note: member function 'elf::Sym<elf::Elf64, Order>::set_binding' is declared const here
void set_binding(stb v) const
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

resolve_indirect() does not resolve indirect encodings

DW_FORM form;

In function value::resolve_indirect(DW_AT name) a local variable DW_FORM form is defined, so the resolve is performed on this local variable. The attribute DW_FORM form in class Value is not changed at all.

Due to this, I see an issue that when the form is indirect, it throws exception in function value::as_reference():
throw value_type_mismatch("cannot read " + to_string(typ) + " as reference");

Potential security issue

Hey there!

I belong to an open source security research community, and a member (@hdthky) has found an issue, but doesn’t know the best way to disclose it.

If not a hassle, might you kindly add a SECURITY.md file with an email, or another contact method? GitHub recommends this best practice to ensure security issues are responsibly disclosed, and it would serve as a simple instruction for security researchers in the future.

Thank you for your consideration, and I look forward to hearing from you!

(cc @huntr-helper)

Please add self-testing to build process

It would be great if the library build process included some kind of self testing to ensure it work. It would ensure broken architectures are discovered early. This is relevant on Debian where we build automatically on 20 architectures and it can take a while before anyone come around to test every one of the 50,000 binary packages in the archive on every architecture. In such setting it is best if the package test itself during build to notify the package maintainer early if there is a problem.

It would be best if 'make check' triggered such self test, as it is the way the automated tools will try to run a check automatically.

SEGV in function elf::Shdr::from at elf/data.hh:299

Description

Whilst experimenting with Libelfin, built from commit 946dde5, we are able to induce a vulnerability in function elf::Shdr::from(elf/data.hh:299), using a harness compiled from examples/dump-segments.cc.

A segmentation fault will be triggered when the software encounters a malformed file, which could induce denial of service.

Environment

Ubuntu 20.04 LTS x86_64

gcc 10.3.0

Proof of Concept

The POC is: poc

The reproducing process is:

# build with address sanitizer
cd examples && CXX=g++ CFLAGS="-g -fsanitize=address" LDFLAGS="-g -fsanitize=address" make -j8
# disable some features of address sanitizer to avoid false positives
export ASAN_OPTIONS=detect_leaks=0
# trigger the crash
./dump-segments poc

The ASAN report is:

=================================================================
==128086==ERROR: AddressSanitizer: SEGV on unknown address 0x7ffff44c3e80 (pc 0x555555558100 bp 0x7fffffffe3f0 sp 0x7fffffffe3b0 T0)
==128086==The signal is caused by a READ memory access.
    #0 0x555555558100 in void elf::Shdr<elf::Elf64, (elf::byte_order)0>::from<elf::Shdr<elf::Elf64, (elf::byte_order)1> >(elf::Shdr<elf::Elf64, (elf::byte_order)1> const&) /work/libraries/libelfin/elf/data.hh:299
    #1 0x555555558100 in void elf::canon_hdr<elf::Shdr>(elf::Shdr<elf::Elf64, (elf::byte_order)0>*, void const*, elf::elfclass, elf::elfdata) /work/libraries/libelfin/elf/elf.cc:31
    #2 0x555555558100 in elf::section::section(elf::elf const&, void const*) /work/libraries/libelfin/elf/elf.cc:236
    #3 0x555555558af2 in elf::elf::elf(std::shared_ptr<elf::loader> const&) /work/libraries/libelfin/elf/elf.cc:111
    #4 0x555555556d04 in main /work/libraries/libelfin/examples/dump-segments.cc:22
    #5 0x7ffff70900b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #6 0x555555556f5d in _start (/work/libraries/libelfin/examples/dump-segments+0x2f5d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /work/libraries/libelfin/elf/data.hh:299 in void elf::Shdr<elf::Elf64, (elf::byte_order)0>::from<elf::Shdr<elf::Elf64, (elf::byte_order)1> >(elf::Shdr<elf::Elf64, (elf::byte_order)1> const&)
==128086==ABORTING

Impact

This vulnerability is capable of inducing denial of service.

Provide shared libraries?

Hi.

It would be nice for the Debian packaging effort if the libelfin libraries are available as shared libraries. It make sure all packages using the libelfil library do not need to be rebuilt every time the libelfin library is modified, and make life for both release managers and the security team a lot easier.

Can you please provide .so files as well as the .a files? And preferably with a SONAME versioning scheme that ensures backward compatiblity?

make error

when I try to make, but failured, there is some thing error about to_string.cc
image
how can I make success

Tag new release

Please tag current master for a new release, so latest fixes can be included in Debian.

SEGV in expr.cc from small_vector.hh

Sounds good.
Seeing a segmentation fault in small_vector.hh when performing the push_back at line 167. This is creating issues at the ELF parser level.
In expr.cc, line 42:

stack.reserve(arguments.size());
for (const taddr *elt = arguments.end() - 1;
elt >= arguments.begin(); elt--)
stack.push_back(*elt); // <- The value of elt is 0xfffffffffffffff8, which means the loop should be auto, despite which the seg fault occurs.

Which uses small_vector.hh's:

void push_back(const T& x)
{
        reserve(size() + 1);
        new (end) T(x);
        end++;
}

How can I fix this and can anyone provide an ELF file they have tested with?
On my end, I also changed the loop and I threw in an expression error and I actually got "empty stack while initializing DWARF expression" multiple times. Wondering why the small_vector stack becomes empty and the seg fault happens?
stack.reserve(arguments.size());
for (auto elt = arguments.begin(); elt != arguments.end(); ++elt)
stack.push_back(*elt);
// Check if the stack is empty before using stack.back()
if (stack.empty()) {
throw expr_error("empty stack while initializing DWARF expression");
}
This also looks similar to this issue: #36

SEGV in function elf::swizzle at elf/common.hh:73

Description

Whilst experimenting with Libelfin, built from commit 946dde5, we are able to induce a vulnerability in function elf::swizzle(elf/common.hh:73), using a harness compiled from examples/dump-segments.cc.

A segmentation fault will be triggered when the software encounters a malformed file, which could induce denial of service.

Environment

Ubuntu 20.04 LTS x86_64

gcc 10.3.0

Proof of Concept

The POC is: poc

The reproducing process is:

# build with address sanitizer
cd examples && CXX=g++ CFLAGS="-g -fsanitize=address" LDFLAGS="-g -fsanitize=address" make -j8
# disable some features of address sanitizer to avoid false positives
export ASAN_OPTIONS=detect_leaks=0
# trigger the crash
./dump-segments poc

The ASAN report is:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==97242==ERROR: AddressSanitizer: SEGV on unknown address 0x7ffff44c2f07 (pc 0x555555558090 bp 0x7fffffffe3f0 sp 0x7fffffffe3b0 T0)
==97242==The signal is caused by a READ memory access.
    #0 0x555555558090 in unsigned int elf::swizzle<unsigned int>(unsigned int, elf::byte_order, elf::byte_order) /work/libraries/libelfin/elf/common.hh:73
    #1 0x555555558090 in void elf::Shdr<elf::Elf64, (elf::byte_order)0>::from<elf::Shdr<elf::Elf64, (elf::byte_order)2> >(elf::Shdr<elf::Elf64, (elf::byte_order)2> const&) /work/libraries/libelfin/elf/data.hh:299
    #2 0x555555558090 in void elf::canon_hdr<elf::Shdr>(elf::Shdr<elf::Elf64, (elf::byte_order)0>*, void const*, elf::elfclass, elf::elfdata) /work/libraries/libelfin/elf/elf.cc:34
    #3 0x555555558090 in elf::section::section(elf::elf const&, void const*) /work/libraries/libelfin/elf/elf.cc:236
    #4 0x555555558af2 in elf::elf::elf(std::shared_ptr<elf::loader> const&) /work/libraries/libelfin/elf/elf.cc:111
    #5 0x555555556d04 in main /work/libraries/libelfin/examples/dump-segments.cc:22
    #6 0x7ffff70900b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #7 0x555555556f5d in _start (/work/libraries/libelfin/examples/dump-segments+0x2f5d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /work/libraries/libelfin/elf/common.hh:73 in unsigned int elf::swizzle<unsigned int>(unsigned int, elf::byte_order, elf::byte_order)
==97242==ABORTING

Impact

This vulnerability is capable of inducing denial of service.

SEGV in function elf::segment::segment at elf/elf.cc:180

Hi,

I am running some experiments for AFLAPI and it has found a SEGV in function elf::segment::segment at elf/elf.cc:180. This bug may allows attackers to cause DoS, so I report it here.

Environment: Ubuntu 18.04 + Clang 6.0

Test target: examples/dump-lines

Testcase here: badelf.zip

To reproduce:
• Complie the hole project and examples with ASAN

You can use like this: ./dump-lines badelf

ASAN says:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==83554==ERROR: AddressSanitizer: SEGV on unknown address 0x7f7351aeefff (pc 0x0000005fba70 bp 0x7ffe73841ea0 sp 0x7ffe73841df0 T0)
==83554==The signal is caused by a READ memory access.
#0 0x5fba6f in elf::segment::segment(elf::elf const&, void const*) /home/ubuntu/libelfin/elf/elf.cc:180
#1 0x5fc54d in elf::(elf)::elf(std::shared_ptrelf::loader const&) /home/ubuntu/libelfin/elf/elf.cc:100
#2 0x519098 in main /home/ubuntu/libelfin/examples/dump-lines.cc:36:18
#3 0x7f735067cc86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
#4 0x41bf29 in _start (/home/ubuntu/libelfin/examples/dump-lines+0x41bf29)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/ubuntu/libelfin/elf/elf.cc:180 in elf::segment::segment(elf::elf const&, void const*)
==83554==ABORTING

Impact:
An attacker can exploit this vulnerability by submitting a malicious elf file that exploits this bug which will result in a DoS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.