Blink rejects an ELF that Linux accepts and runs
I have an ELF editor and just discovered a bug where it would emit PT_LOAD segments that extend past EOF. This is wrong and will be fixed on my end.
However, it is notable that Linux not only accepts these mangled ELFs but also runs them correctly: the missing file regions just get mmapped in anyway, zero filled.
Blink currently rejects the ELF, prints "corrupt elf program header" and exits with code 127. Since Blink is a x86_64 Linux emulator and behavior diverges from Linux, I felt it was important to raise the issue to your attention.
https://github.com/jart/blink/blob/f006a4fc6f9b8de9272504fdff0dbbe5ce5dc580/blink/loader.c#L137-L140
The Linux kernel never enforces offset + filesz <= imagesize. The final page of the offending segment is file backed up to the end of the file, and the remaining extent is zero filled.
The following ELF will reproduce the issue:
bad.s .code64
.set VADDR1, 0x400000 # code page load address
.set VADDR2, 0x401000 # "embedded" page load address
.section .elf, "ax"
ehdr:
.byte 0x7f, 'E', 'L', 'F', 2, 1, 1, 0 # e_ident magic, ELFCLASS64, ELFDATA2LSB, EV_CURRENT, SYSV
.quad 0 # e_ident padding
.short 2 # e_type ET_EXEC
.short 0x3e # e_machine EM_X86_64
.long 1 # e_version
.quad VADDR1 + (_start - ehdr) # e_entry
.quad phdr - ehdr # e_phoff
.quad 0 # e_shoff
.long 0 # e_flags
.short 64 # e_ehsize
.short 56 # e_phentsize
.short 2 # e_phnum
.short 0 # e_shentsize
.short 0 # e_shnum
.short 0 # e_shstrndx
phdr:
.long 1 # [0] p_type PT_LOAD
.long 5 # p_flags R | X
.quad 0 # p_offset
.quad VADDR1 # p_vaddr
.quad VADDR1 # p_paddr
.quad 0x1000 # p_filesz
.quad 0x1000 # p_memsz
.quad 0x1000 # p_align
.long 1 # [1] p_type PT_LOAD "embedded" page
.long 4 # p_flags R
.quad 0x1000 # p_offset second page in the file
.quad VADDR2 # p_vaddr
.quad VADDR2 # p_paddr
.quad 0x1000 # p_filesz <= file size ...
.quad 0x1000 # p_memsz
.quad 0x1000 # p_align ... but p_offset + p_filesz > EOF
_start:
mov $60, %eax # SYS_exit
mov $42, %edi # status 42
syscall
.fill 0x1000 - (. - ehdr), 1, 0 # pad the code page out to a full page
.fill 0x50, 1, 0 # PT_LOAD #2: 0x50 real bytes, then EOF, file size 0x1050Assemble and test it with:
as -o bad.o bad.s
objcopy -O binary -j .elf bad.o bad.elf
chmod +x bad.elf
./bad.elf; echo $?
42
blink ./bad.elf; echo $?
corrupt elf program header
127Source: jart/blink