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