Most recent kernel where this bug did not occur: 2.6.14.2 Distribution: - Hardware Environment: i386, arm Software Environment: i386: FC4, binutils-2.15.94.0.2.2 arm: binutils-2.16.91.0.3 Problem Description: The kernel kills certain ELF binaries with SIGKILL. AFAIS, the triggers are: * two program headers * second header has a size of PAGE_SIZE or multiplies of it; e.g.: | ELF Header: | Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 | Class: ELF32 | Data: 2's complement, little endian | Version: 1 (current) | OS/ABI: ARM | ABI Version: 0 | Type: EXEC (Executable file) | Machine: ARM | Version: 0x1 | Entry point address: 0x8074 | Start of program headers: 52 (bytes into file) | Start of section headers: 4128 (bytes into file) | Flags: 0x0 | Size of this header: 52 (bytes) | Size of program headers: 32 (bytes) | Number of program headers: 2 | Size of section headers: 40 (bytes) | Number of section headers: 5 | Section header string table index: 4 | | Section Headers: | [Nr] Name Type Addr Off Size ES Flg Lk Inf Al | [ 0] NULL 00000000 000000 000000 00 0 0 0 | [ 1] .text PROGBITS 00008074 000074 000000 00 AX 0 0 4 | [ 2] .rodata PROGBITS 00008074 000074 000f00 00 A 0 0 1 | [ 3] .bss NOBITS 00011000 001000 000100 00 WA 0 0 1 | [ 4] .shstrtab STRTAB 00000000 001000 00001e 00 0 0 1 | Key to Flags: | W (write), A (alloc), X (execute), M (merge), S (strings) | I (info), L (link order), G (group), x (unknown) | O (extra OS processing required) o (OS specific), p (processor specific) | | There are no section groups in this file. | | Program Headers: | Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align | LOAD 0x000000 0x00008000 0x00008000 0x00f74 0x00f74 R E 0x8000 | LOAD 0x001000 0x00011000 0x00011000 0x00000 0x00100 RW 0x8000 | | Section to Segment mapping: | Segment Sections... | 00 .rodata | 01 .bss | | There is no dynamic section in this file. | | There are no relocations in this file. | | There are no unwind sections in this file. | | No version information found in this file. Adding some debug code to the kernel (see below) gives out | a.out | fs/binfmt_elf.c:848, file=c3ccb294, load_bias=0, vaddr=00008000, elf_ppnt=c05a9bb8, elf_prot=5, elf_flags=1812, error=32768 | fs/binfmt_elf.c:848, file=c3ccb294, load_bias=0, vaddr=00011000, elf_ppnt=c05a9bd8, elf_prot=3, elf_flags=1812, error=-22 | SIGKILL -> p_filesz=00000000, p_offset=00001000, vaddr=00011000, | Killed Working binaries (a '.=+0xe00' instead of '.=0xf00') are producing | # a.out | fs/binfmt_elf.c:848, file=c3ca58e8, load_bias=0, vaddr=00008000, elf_ppnt=c05a9660, elf_prot=5, elf_flags=1812, error=32768 | fs/binfmt_elf.c:848, file=c3ca58e8, load_bias=0, vaddr=00010e74, elf_ppnt=c05a9680, elf_prot=3, elf_flags=1812, error=65536 | Segmentation fault | # Steps to reproduce: Please note, that a segfault is the intended effect of the code below. But it creates a SIGKILL in the kernel. 1. cat >foo.S <<EOF .text .global _start _start: .section .rodata .=+0x0f00 .section .bss .=+0x0100 EOF 2. as foo.S -o foo.o 3. ld foo.o 4. ./a.out OR (requires dietlibc (http://www.fefe.de/dietlibc/) and this code triggers the error on the ARM platform only) 1. cat >foo.c <<EOF char const data[0x1f00] = { }; int main() { } EOF 2. diet foo.c 3. ./a.out Used debug-code: diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -842,7 +844,12 @@ static int load_elf_binary(struct linux_ } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); + printk("%s:%u, file=%p, load_bias=%lu, vaddr=%08lx, elf_ppnt=%p, elf_prot=%u, elf_flags=%04x, error=%li\n", + __FILE__, __LINE__, bprm->file, load_bias, vaddr, elf_ppnt, elf_prot, elf_flags, error); + if (BAD_ADDR(error)) { + printk("SIGKILL -> p_filesz=%p, p_offset=%p, vaddr=%p,\n", + elf_ppnt->p_filesz, elf_ppnt->p_offset, elf_ppnt->p_vaddr); send_sig(SIGKILL, current, 0); goto out_free_dentry; }
[Moving into 'Other' category because 'Process Management' does not apply] Exact trigger is 'filesz==0 && VirtAddr%PAGE_SIZE==0' | Program Headers: | Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align | ... | LOAD 0x001000 0x00011000 0x00011000 0x00000 0x00100 RW 0x8000 ~~~~~~~~~~ ~~~~~~~ Then, the | static unsigned long elf_map( | ... | map_addr = do_mmap(filep, ELF_PAGESTART(addr), | eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, | eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); calls do_mmap() with a len-parameter of '0'. Possible guilty parties are: * the kernel, because it handles this case wrong, or * 'ld' from binutils because it generates such ELF headers, or * dietlibc because it let 'ld' generate such ELF headers
accordingly LSB spec, it is allowed for ELF segments to be empty. Therefore, the kernel is the guilty party.
I seem to recall adding a patch to handle empty elf segments. Is this problem resolved in 2.6.20-rc7?
Please reopen this bug if it's still present with kernel 2.6.20.