Bug 56886 - binfmt_elf: bad entry address for ET_EXEC PT_INTERP
Summary: binfmt_elf: bad entry address for ET_EXEC PT_INTERP
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: kernel
Version: 9
Hardware: i386
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Arjan van de Ven
QA Contact: Brock Organ
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2001-11-29 15:55 UTC by John Reiser
Modified: 2008-08-01 16:22 UTC (History)
0 users

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2004-09-30 15:39:18 UTC
Embargoed:


Attachments (Terms of Use)

Description John Reiser 2001-11-29 15:55:51 UTC
From Bugzilla Helper:
User-Agent: Mozilla/4.75 [en] (X11; U; Linux 2.2.19-6.2.1perf2.0 i586)

Description of problem:
If an ELF main executable specifies a PT_INTERP program interpreter
which has ET_EXEC format, and if the the program interpreter has
an unusual PT_LOAD/.bss configuration, then the kernel starts
the process at the wrong entry address.  fs/binfmt_elf.c has a bug
in RedHat 7.2 (kernel 2.4.9-7) that worked correctly in RedHat 7.1
(kernel 2.4.3-12).


Version-Release number of selected component (if applicable):
Red Hat Linux release 7.2 (Enigma)
2.4.9-7 i386 [i686]

How reproducible:
Always

Steps to Reproduce:
1. Compile and run the program below to generate files "a.elf" and
  "pt_interp" with one of the bad configurations.  Both a.elf and
   pt_interp exit(0) immediately [3 instructions].
2. Set ulimit to allow a core file.  Run the ./a.elf file and
   observe SIGSEGV, and get a core file.
3. Inspect the core file (gdb will work here) to see a PC of 0x40,
   which is an address that is nowhere specified in either
   the a.elf or pt_interp files.

-----elfbug.c
#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int
main(void)
{
	char const code[]={
		0xb8,1,0,0,0,   /* movl $__NR_exit,%eax */
		0xbb,0,0,0,0,   /* movl $0,%ebx */
		0xcd,0x80       /* syscall */
	};
	int fd;
	static char const pt_interp[]="pt_interp";
	Elf32_Ehdr ehdr;
	Elf32_Phdr phdr[2];

	memset(&ehdr, 0, sizeof(ehdr));
	ehdr.e_ident[0]=ELFMAG0;
	ehdr.e_ident[1]=ELFMAG1;
	ehdr.e_ident[2]=ELFMAG2;
	ehdr.e_ident[3]=ELFMAG3;
	ehdr.e_ident[EI_CLASS]=ELFCLASS32;
	ehdr.e_ident[EI_DATA]=ELFDATA2LSB;
	ehdr.e_ident[EI_VERSION]=EV_CURRENT;
	ehdr.e_ident[EI_ABIVERSION]=0;
	ehdr.e_type=ET_EXEC;
	ehdr.e_machine=EM_386;
	ehdr.e_version=EV_CURRENT;
	ehdr.e_entry=0x4200000+sizeof(ehdr)+sizeof(phdr);
	ehdr.e_phoff=sizeof(ehdr);
	ehdr.e_shoff=0;
	ehdr.e_flags=0;
	ehdr.e_ehsize=sizeof(Elf32_Ehdr);
	ehdr.e_phentsize=sizeof(Elf32_Phdr);
	ehdr.e_phnum=2;
	ehdr.e_shentsize=0;
	ehdr.e_shnum=0;
	ehdr.e_shstrndx=0;

	phdr[0].p_type=PT_LOAD;
	phdr[0].p_offset=0;
	phdr[0].p_vaddr=0x4200000;
	phdr[0].p_paddr=0x4200000;
	phdr[0].p_filesz=sizeof(ehdr)+sizeof(phdr)+sizeof(pt_interp)+
		sizeof(code) ;
	phdr[0].p_memsz=phdr[0].p_filesz;
	phdr[0].p_flags=PF_X | PF_R;
	phdr[0].p_align=1<<12;

	phdr[1] = phdr[0];
	phdr[1].p_type=PT_INTERP;
	phdr[1].p_offset = sizeof(ehdr) + sizeof(phdr) + sizeof(code);
	phdr[1].p_vaddr += phdr[1].p_offset;
	phdr[1].p_paddr += phdr[1].p_offset;
	phdr[1].p_filesz=sizeof(pt_interp);
	phdr[1].p_memsz=phdr[0].p_filesz;
	phdr[1].p_flags=PF_R;
	phdr[1].p_align=1;

	fd=open("a.elf", O_CREAT | O_WRONLY, 0755);
	write(fd, &ehdr, sizeof(ehdr));
	write(fd, &phdr, sizeof(phdr));
	write(fd, &code, sizeof(code));
	write(fd, &pt_interp[0], sizeof(pt_interp));
	close(fd);

	ehdr.e_entry += 0x84000 - 0x4200000;
	phdr[0].p_vaddr=0x84000;
	phdr[0].p_paddr=0x84000;
	phdr[0].p_filesz=sizeof(ehdr)+sizeof(phdr)+sizeof(code);
	phdr[0].p_memsz=phdr[0].p_filesz;
	phdr[0].p_flags=PF_X|PF_R|PF_W;

	phdr[1].p_type = PT_LOAD;
	phdr[1].p_offset = (1<<12) + phdr[0].p_filesz;
	phdr[1].p_vaddr = 0;
	phdr[1].p_paddr = 0;
	phdr[1].p_filesz = 0;
	phdr[1].p_memsz = 0;
	phdr[1].p_flags = 0;
	phdr[1].p_align=1;
	fd=open(pt_interp, O_CREAT | O_WRONLY, 0755);
	write(fd, &ehdr, sizeof(ehdr));
	write(fd, &phdr, sizeof(phdr));
	write(fd, &code, sizeof(code));
	close(fd);

	return 0;
}
-----

Actual Results:  $ gcc -o elfbug elfbug.c
$ ./elfbug
$ ulimit -c 1000
$ ./a.elf
Segmentation fault (core dumped)
$ gdb a.elf core
GNU gdb 5.0
Copyright 2000 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-pc-linux-gnu"..."a.elf": not in executable
format: File format not recognized
   ### gdb is too picky about Elf32_Shdr, but it doesn't matter here

Core was generated by `./a.elf'.
Program terminated with signal 11, Segmentation fault.
#0  0x40 in ?? ()
(gdb) info reg
eax            0x0	0
ecx            0x0	0
edx            0x0	0
ebx            0x0	0
esp            0xbffffa80	0xbffffa80
ebp            0x0	0x0
esi            0x0	0
edi            0x0	0
eip            0x40	0x40     ### garbage address
eflags         0x10246	66118
cs             0x23	35
ss             0x2b	43
ds             0x2b	43
es             0x2b	43
fs             0x2b	43
gs             0x2b	43
fctrl          0x0	0
fstat          0x0	0
ftag           0x0	0
fiseg          0x0	0
fioff          0x0	0
foseg          0x0	0
fooff          0x0	0
fop            0x0	0
(gdb) q


Expected Results:  $ ./a.elf
$ echo $?
0
$ 


Additional info:

Comment 1 Bugzilla owner 2004-09-30 15:39:18 UTC
Thanks for the bug report. However, Red Hat no longer maintains this version of
the product. Please upgrade to the latest version and open a new bug if the problem
persists.

The Fedora Legacy project (http://fedoralegacy.org/) maintains some older releases, 
and if you believe this bug is interesting to them, please report the problem in
the bug tracker at: http://bugzilla.fedora.us/



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