Bug 5645 - SIGKILL with page-aligned, empty ELF segments
Summary: SIGKILL with page-aligned, empty ELF segments
Status: REJECTED INSUFFICIENT_DATA
Alias: None
Product: Other
Classification: Unclassified
Component: Other (show other bugs)
Hardware: i386 Linux
: P2 normal
Assignee: process_other
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-23 08:45 UTC by Enrico Scholz
Modified: 2007-03-07 15:16 UTC (History)
2 users (show)

See Also:
Kernel Version: 2.6.14.2
Subsystem:
Regression: ---
Bisected commit-id:


Attachments

Description Enrico Scholz 2005-11-23 08:45:08 UTC
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;
                }
Comment 1 Enrico Scholz 2005-11-23 10:07:31 UTC
[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
Comment 2 Enrico Scholz 2005-12-20 02:55:02 UTC
accordingly LSB spec, it is allowed for ELF segments to be empty.

Therefore, the kernel is the guilty party.
Comment 3 Andrew Morton 2007-01-31 00:59:21 UTC
I seem to recall adding a patch to handle empty elf segments.  Is this
problem resolved in 2.6.20-rc7?
Comment 4 Adrian Bunk 2007-03-07 15:16:37 UTC
Please reopen this bug if it's still present with kernel 2.6.20.

Note You need to log in before you can comment on or make changes to this bug.