Red Hat Bugzilla – Bug 115913
(FS BINFMT_ELF)binfmt_elf reserves too many page frames for sparse PT_LOADs
Last modified: 2015-01-04 17:04:41 EST
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1)
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
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
----- 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):
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.
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:
(even also with aligning .dynamic) generates the same state.