Bug 115913

Summary: (FS BINFMT_ELF)binfmt_elf reserves too many page frames for sparse PT_LOADs
Product: [Fedora] Fedora Reporter: John Reiser <jreiser>
Component: kernelAssignee: Dave Jones <davej>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: rawhideCC: pfrields
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2004-11-19 03:43:45 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
elfbug.c source which generates interesting a.elf executable none

Description John Reiser 2004-02-16 23:47:34 UTC
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().

Comment 1 John Reiser 2004-02-16 23:49:26 UTC
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.

Comment 2 Jakub Jelinek 2004-02-17 09:55:56 UTC
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.