#215·blink

Blink rejects an ELF that Linux accepts and runs

Author: matheusmoreiraCreated Jul 24, 2026Updated Jul 24, 2026

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
asm
  .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 0x1050

Assemble 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
127