failed reading "Smallest x86 ELF Hello World"

Mark Wielaard mark@klomp.org
Wed Oct 4 18:55:00 GMT 2017


On Thu, 2017-09-28 at 12:06 -0700, Josh Stone wrote:
> From http://timelessname.com/elfbin/
> 
> Elfutils completely fails to read the file:
> 
> $ eu-readelf --version
> eu-readelf (elfutils) 0.169
> Copyright [...]
> $ eu-readelf -a hello
> eu-readelf: failed reading 'hello': invalid file descriptor
> 
> It's not clear that we should care, since that page even says it's "a
> completely corrupted x86 ELF Binary that still runs."  But since it's
> good enough for the kernel to run it, I'd hope for *something* from
> tools.
> 
> It also seems weird to get the message "invalid file descriptor",
> from ELF_E_INVALID_FILE, which makes it sound like more like
> EBADF.  The file descriptor itself is fine - it just doesn't like the
> ELF within.

At first I though it was because eu-readelf uses libdwfl to get more
information about the ELF file. To get all the data about the
Dwfl_Modules we might hit some error that might not be relevant for the
initial showing of data. But that isn't really it in this case.

The first issue is indeed that almost anything that goes wrong when
setting up the initial Elf handle ends up being described as
ELF_E_INVALID_FILE. Which is not always the correct error code. So I
introduced ELF_E_INVALID_ELF which indicates it is bad ELF data being
encountered and not just the inability to read the data from the file
descriptor. Also in a couple of cases we didn't explicitly set the
libelf errno to indicate what really went wrong. I made sure we always
do now.

  libelf: Add ELF_E_INVALID_ELF error value.

This at least gives a nicer error message:

  eu-readelf: failed reading './hello': invalid ELF file data

But while auditing this code it is clear we go out of our way to get
the section (count) making sure we don't touch any bad data. If there
is a change we might read anything bad from the (mmapped) file then we
explicitly set the elf->state.elf[64|32].scns.cnt to zero. Which is
respected throughout libelf whenever we try to touch section headers.
Except... during the initial read we double check e_shoff is sane and
error out early. Even though the code right below it explicitly doesn't
use it when scncnt is zero. So we can fix this sanity check.

  libelf: Don't error out when sanity checking e_shoff if scncnt is
zero.

This then gives similar output to binutils readelf:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 48 69 20 57 6f 72 6c 64 0a
  Class:                             ELF32
  Data:                              2's complement, little endian
  Ident Version:                     1 (current)
  OS/ABI:                            <unknown>: 72
  ABI Version:                       105
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           1 (current)
  Entry point address:               0x8048080
  Start of program headers:          52 (bytes into file)
  Start of section headers:          309248 (bytes into file)
  Flags:                             0x80cd0000
  Size of this header:               22763 (bytes)
  Size of program header entries:    32 (bytes)
  Number of program headers entries: 2
  Size of section header entries:    40 (bytes)
  Number of section headers entries: 5
  Section header string table index: 4

Section Headers:
[Nr] Name                 Type         Addr     Off    Size   ES Flags Lk Inf Al

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x0000a2 0x0000a2 R E 0x1000
  LOAD           0x0000a4 0x080490a4 0x080490a4 0x000009 0x000009  W  0x9007b900

 Section to Segment mapping:
  Segment Sections...
   00     
   01     

Maybe it could be improved a little more by adding a warning that 5
section [headers] were expected, but none could be read. But I leave it
at this for now.

Cheers,

Mark


More information about the Elfutils-devel mailing list