From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225 Description of problem: If the PT_LOAD do not describe contiguous address space, then binfmt_elf forgets to un-reserve the "holes". For example: ----- readelf --segments a.elf Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align DYNAMIC 0x0000a2 0x080400a2 0x080400a2 0x00008 0x00008 RW 0x4 LOAD 0x000000 0x08040000 0x08040000 0x0000e 0x0000e RWE 0x1000 LOAD 0x000001 0x09000001 0x09000001 0x00000 0x00000 0x1000 ----- results in ----- cat /proc/PID/maps 08040000-09000000 rwxp 00000000 03:05 3850275 /home/jreiser/a.elf 09000000-09001000 ---p 00000000 03:05 3850275 /home/jreiser/a.elf bffff000-c0000000 rwxp 00000000 00:00 0 ffffe000-fffff000 ---p 00000000 00:00 0 ----- which has no hole from 0x08041000 to 0x09000000. The correct result is obtained under RH9: ----- 08040000-08041000 rwxp 00000000 03:07 2796288 /home/jreiser/a.elf 09000000-09001000 ---p 00000000 03:07 2796288 /home/jreiser/a.elf bfffe000-c0000000 rwxp fffff000 00:00 0 ----- which has "no mapping" from 0x08041000 to 0x09000000. Version-Release number of selected component (if applicable): kernel-2.6.2-1.81 How reproducible: Always Steps to Reproduce: 1. Compile and run attached elfbug.c to generate a.elf of interest. 2. "readelf --segments a.elf" to see PT_LOAD layout. 3. "gdb a.elf; run; ^C; shell cat /proc/PID/maps" to see address space. Actual Results: Pages allocated to cover convex hull of all PT_LOAD as a group. Expected Results: Minimal page cover of each individual PT_LOAD. Additional info: After reserving the page interval which covers from lowest .p_vaddr to highest (.p_memsz + .p_vaddr), which makes sure that all the PT_LOAD can be satisfied, then if the pages implied by consecutive pairs of PT_LOAD were not adjacent and increasing, then binfmt_elf should munmap() the whole interval before going back to perform the actual mmap()s from the file. This heuristic (checking that consecutive PT_LOAD imply adjacent pages) is inexpensive to compute, and inexpensive to execute because most PT_LOAD will be adjacent, hence the "extra" munmap() is needed only for unusual cases. The munmap() for cases that are not contiguous is safe because there can be no contention for address space after "the point of no return" in execve().
Created attachment 97718 [details] elfbug.c source which generates interesting a.elf executable Generated a.elf is mapped correctly under RH9, but not under FC2test1.
The image is buggy, in that no PT_LOAD segment covers the .dynamic range nor the code itself. But something like: - phdr[1].p_filesz=sizeof(code); + phdr[1].p_filesz=sizeof(code)+sizeof(Elf32_Ehdr)+3*sizeof(Elf32_Phdr)+sizeof(Elf32_Dyn); (even also with aligning .dynamic) generates the same state.