[PATCH] binfmt_elf cleanups

Matthew Wilcox (Matthew.Wilcox@genedata.com)
Sat, 28 Aug 1999 04:43:32 +0200


I've cleaned up the binfmt_elf handling a bit. I think more needs to
be done to it, but this is a start. This patch is against 2.3.15 --
testers appreciated.

--- fs/binfmt_elf.c.linus Tue Aug 3 19:18:39 1999
+++ fs/binfmt_elf.c Sat Aug 28 04:26:20 1999
@@ -214,9 +214,9 @@
unsigned long load_addr = 0;
int load_addr_set = 0;
unsigned long last_bss = 0, elf_bss = 0;
- unsigned long error = ~0UL;
int elf_exec_fileno;
int retval, i, size;
+ unsigned long error = ~0UL;

/* First of all, some simple consistency checks */
if (interp_elf_ex->e_type != ET_EXEC &&
@@ -246,11 +246,9 @@

retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
(char *) elf_phdata, size, 1);
- error = retval;
if (retval < 0)
goto out_free;

- error = ~0UL;
elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
if (elf_exec_fileno < 0)
goto out_free;
@@ -258,55 +256,57 @@

eppnt = elf_phdata;
for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- unsigned long k, map_addr;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- vaddr = eppnt->p_vaddr;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
+ int elf_type, elf_prot;
+ unsigned long vaddr;
+ unsigned long k, map_addr;
+
+ if (eppnt->p_type != PT_LOAD)
+ continue;
+
+ elf_prot = 0;
+ if (eppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+ if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
+ vaddr = eppnt->p_vaddr;
+
+ elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+ elf_type |= MAP_FIXED;
#ifdef __sparc__
- } else {
- load_addr = get_unmapped_area(0, eppnt->p_filesz +
+ } else {
+ load_addr = get_unmapped_area(0, eppnt->p_filesz +
ELF_PAGEOFFSET(vaddr));
#endif
- }
+ }
+
+ map_addr = do_mmap(file, load_addr + ELF_PAGESTART(vaddr),
+ eppnt->p_filesz + ELF_PAGEOFFSET(vaddr),
+ elf_prot, elf_type,
+ eppnt->p_offset - ELF_PAGEOFFSET(vaddr));
+ if (map_addr > -1024UL) /* Real error */
+ goto out_close;

- map_addr = do_mmap(file,
- load_addr + ELF_PAGESTART(vaddr),
- eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
- if (map_addr > -1024UL) /* Real error */
- goto out_close;
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = map_addr - ELF_PAGESTART(vaddr);
- load_addr_set = 1;
- }
-
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss)
- last_bss = k;
- }
+ if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+ load_addr = map_addr - ELF_PAGESTART(vaddr);
+ load_addr_set = 1;
+ }
+
+ /*
+ * Find the end of the file mapping for this phdr, and keep
+ * track of the largest address we see for this.
+ */
+ k = load_addr + vaddr + eppnt->p_filesz;
+ if (k > elf_bss)
+ elf_bss = k;
+
+ /*
+ * Do the same thing for the memory mapping - between
+ * elf_bss and last_bss is the bss section.
+ */
+ k = load_addr + vaddr + eppnt->p_memsz;
+ if (k > last_bss)
+ last_bss = k;
}

/* Now use mmap to map the library into memory. */
@@ -394,13 +394,13 @@
struct dentry *interpreter_dentry = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias;
int load_addr_set = 0;
- char * elf_interpreter = NULL;
+ char * interpreter_name = NULL;
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter = 0;
mm_segment_t old_fs;
unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
- unsigned long elf_bss, k, elf_brk;
+ unsigned long elf_bss, elf_brk;
int elf_exec_fileno;
int retval, size, i;
unsigned long elf_entry, interp_load_addr = 0;
@@ -415,8 +415,7 @@

retval = -ENOEXEC;
/* First of all, some simple consistency checks */
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;

if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
@@ -464,112 +463,87 @@
end_code = 0;
end_data = 0;

- for (i = 0; i < elf_ex.e_phnum; i++) {
- if (elf_ppnt->p_type == PT_INTERP) {
- retval = -EINVAL;
- if (elf_interpreter)
- goto out_free_interp;
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- retval = -ENOMEM;
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
- if (!elf_interpreter)
- goto out_free_file;
-
- retval = read_exec(bprm->dentry, elf_ppnt->p_offset,
- elf_interpreter,
- elf_ppnt->p_filesz, 1);
- if (retval < 0)
- goto out_free_interp;
- /* If the program interpreter is one of these two,
- * then assume an iBCS2 image. Otherwise assume
- * a native linux image.
- */
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
+ for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+ if (elf_ppnt->p_type != PT_INTERP)
+ continue;
+
+ /* Only one PT_INTERP section is permitted per binary */
+ retval = -EINVAL;
+ if (interpreter_name != NULL)
+ goto out_free_interp;
+
+ /* This is the program interpreter used for shared libraries */
+ retval = -ENOMEM;
+ interpreter_name = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL);
+ if (interpreter_name == NULL)
+ goto out_free_file;
+
+ retval = read_exec(bprm->dentry, elf_ppnt->p_offset,
+ interpreter_name, elf_ppnt->p_filesz, 1);
+ if (retval < 0)
+ goto out_free_interp;
+
+ /* If the program interpreter is one of these two,
+ * then assume an iBCS2 image. Otherwise assume
+ * a native linux image.
+ */
+ if (strcmp(interpreter_name,"/usr/lib/libc.so.1") == 0 ||
+ strcmp(interpreter_name,"/usr/lib/ld.so.1") == 0)
ibcs2_interpreter = 1;
#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
+ printk("Using ELF interpreter %s\n", interpreter_name);
#endif
- old_fs = get_fs(); /* This could probably be optimized */
- set_fs(get_ds());
+ old_fs = get_fs(); /* This could probably be optimized */
+ set_fs(get_ds());
#ifdef __sparc__
- if (ibcs2_interpreter) {
- unsigned long old_pers = current->personality;
-
- current->personality = PER_SVR4;
- interpreter_dentry = open_namei(elf_interpreter,
- 0, 0);
- current->personality = old_pers;
- } else
+ if (ibcs2_interpreter) {
+ unsigned long old_pers = current->personality;
+ current->personality = PER_SVR4;
+ interpreter_dentry = open_namei(interpreter_name, 0, 0);
+ current->personality = old_pers;
+ } else
#endif
- interpreter_dentry = open_namei(elf_interpreter,
- 0, 0);
- set_fs(old_fs);
- retval = PTR_ERR(interpreter_dentry);
- if (IS_ERR(interpreter_dentry))
- goto out_free_interp;
- retval = permission(interpreter_dentry->d_inode, MAY_EXEC);
- if (retval < 0)
- goto out_free_dentry;
- retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1);
- if (retval < 0)
- goto out_free_dentry;
-
- /* Get the exec headers */
- interp_ex = *((struct exec *) bprm->buf);
- interp_elf_ex = *((struct elfhdr *) bprm->buf);
- }
- elf_ppnt++;
+ interpreter_dentry = open_namei(interpreter_name, 0, 0);
+ set_fs(old_fs);
+ retval = PTR_ERR(interpreter_dentry);
+ if (IS_ERR(interpreter_dentry))
+ goto out_free_interp;
+ retval = permission(interpreter_dentry->d_inode, MAY_EXEC);
+ if (retval < 0)
+ goto out_free_dentry;
+ retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1);
+ if (retval < 0)
+ goto out_free_dentry;
+
+ /* Get the exec headers */
+ interp_ex = *((struct exec *) bprm->buf);
+ interp_elf_ex = *((struct elfhdr *) bprm->buf);
}

/* Some simple consistency checks for the interpreter */
- if (elf_interpreter) {
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
+ if (interpreter_name) {
/* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
retval = -ELIBBAD;
- if (!interpreter_type)
- goto out_free_dentry;
-
- /* Make sure only one type was selected */
- if ((interpreter_type & INTERPRETER_ELF) &&
- interpreter_type != INTERPRETER_ELF) {
- printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
+ if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) == 0) {
interpreter_type = INTERPRETER_ELF;
+ } else if (!N_BADMAG(interp_ex)) {
+ interpreter_type = INTERPRETER_AOUT;
+ } else {
+ goto out_free_dentry;
}
}

/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */

- if (!bprm->sh_bang) {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- retval = copy_strings_kernel(1,&passed_p,bprm);
+ if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) {
+ sprintf(passed_fileno, "%d", elf_exec_fileno);
+ if (interpreter_name) {
+ char * passed_p = passed_fileno;
+ retval = copy_strings_kernel(1,&passed_p,bprm);
if (retval)
goto out_free_dentry;
- bprm->argc++;
- }
+ bprm->argc++;
}
}

@@ -609,48 +583,48 @@
old_fs = get_fs();
set_fs(get_ds());
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
- int elf_prot = 0, elf_flags;
- unsigned long vaddr;
+ int elf_prot, elf_flags;
+ unsigned long vaddr, k;

if (elf_ppnt->p_type != PT_LOAD)
continue;

+ elf_prot = 0;
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;

elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
-
- vaddr = elf_ppnt->p_vaddr;
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
}

+ vaddr = elf_ppnt->p_vaddr;
+
error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr),
- (elf_ppnt->p_filesz +
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot, elf_flags, (elf_ppnt->p_offset -
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+ (elf_ppnt->p_filesz + ELF_PAGEOFFSET(vaddr)),
+ elf_prot, elf_flags,
+ (elf_ppnt->p_offset - ELF_PAGEOFFSET(vaddr)));

if (!load_addr_set) {
load_addr_set = 1;
- load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
+ load_addr = (vaddr - elf_ppnt->p_offset);
if (elf_ex.e_type == ET_DYN) {
- load_bias += error -
- ELF_PAGESTART(load_bias + vaddr);
+ load_bias += error - ELF_PAGESTART(load_bias + vaddr);
load_addr += error;
}
}
- k = elf_ppnt->p_vaddr;
- if (k < start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+ if (vaddr < start_code) {
+ start_code = vaddr;
+ }
+ k = vaddr + elf_ppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
- if ((elf_ppnt->p_flags & PF_X) && end_code < k)
+ if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k;
if (end_data < k)
end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+ k = vaddr + elf_ppnt->p_memsz;
if (k > elf_brk)
elf_brk = k;
}
@@ -664,7 +638,7 @@
end_code += load_bias;
end_data += load_bias;

- if (elf_interpreter) {
+ if (interpreter_name) {
if (interpreter_type == INTERPRETER_AOUT)
elf_entry = load_aout_interp(&interp_ex,
interpreter_dentry);
@@ -674,7 +648,7 @@
&interp_load_addr);

dput(interpreter_dentry);
- kfree(elf_interpreter);
+ kfree(interpreter_name);

if (elf_entry == ~0UL) {
printk(KERN_ERR "Unable to load interpreter\n");
@@ -686,7 +660,7 @@

kfree(elf_phdata);

- if (interpreter_type != INTERPRETER_AOUT)
+ if (interpreter_type == INTERPRETER_ELF)
sys_close(elf_exec_fileno);

if (current->exec_domain && current->exec_domain->module)
@@ -700,19 +674,13 @@
if (current->binfmt && current->binfmt->module)
__MOD_INC_USE_COUNT(current->binfmt->module);

-#ifndef VM_STACK_FLAGS
- current->executable = dget(bprm->dentry);
-#endif
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
- bprm->p = (unsigned long)
- create_elf_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
+ bprm->p = (unsigned long) create_elf_tables((char *)bprm->p,
+ bprm->argc, bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr, load_bias,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+ load_addr, load_bias, interp_load_addr,
+ (interpreter_type == INTERPRETER_ELF ? 1 : 0));
/* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -770,8 +738,8 @@
out_free_dentry:
dput(interpreter_dentry);
out_free_interp:
- if (elf_interpreter)
- kfree(elf_interpreter);
+ if (interpreter_name)
+ kfree(interpreter_name);
out_free_file:
fput(file);
sys_close(elf_exec_fileno);
@@ -801,7 +769,7 @@
struct dentry * dentry;
struct inode * inode;
struct elf_phdr *elf_phdata;
- unsigned long elf_bss = 0, bss, len, k;
+ unsigned long elf_bss, bss, len, vaddr;
int retval, error, i, j;
struct elfhdr elf_ex;
loff_t offset = 0;
@@ -823,8 +791,7 @@
if (retval != sizeof(elf_ex))
goto out_putf;

- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_putf;

/* First of all, some simple consistency checks */
@@ -848,34 +815,37 @@
retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);

+ /* Find the loadable segment. Only one segment is permitted to be loadable. */
error = -ENOEXEC;
- for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
- if ((elf_phdata + i)->p_type == PT_LOAD) j++;
- if (j != 1)
+ j = -1;
+ for (i = 0; i<elf_ex.e_phnum; i++) {
+ if ((elf_phdata + i)->p_type != PT_LOAD)
+ continue;
+ if (j != -1)
+ goto out_free_ph;
+ j = i;
+ }
+ if (j == -1)
goto out_free_ph;
+ elf_phdata += j;

- while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
+ vaddr = elf_phdata->p_vaddr;

/* Now use mmap to map the library into memory. */
error = do_mmap(file,
- ELF_PAGESTART(elf_phdata->p_vaddr),
- (elf_phdata->p_filesz +
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
+ ELF_PAGESTART(vaddr),
+ elf_phdata->p_filesz + ELF_PAGEOFFSET(vaddr),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
- (elf_phdata->p_offset -
- ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
- if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
+ elf_phdata->p_offset - ELF_PAGEOFFSET(vaddr));
+ if (error != ELF_PAGESTART(vaddr))
goto out_free_ph;

- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
+ elf_bss = vaddr + elf_phdata->p_filesz;
padzero(elf_bss);

- len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr +
- ELF_EXEC_PAGESIZE - 1);
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+ len = ELF_PAGESTART(vaddr + elf_phdata->p_filesz + ELF_EXEC_PAGESIZE - 1);
+ bss = vaddr + elf_phdata->p_memsz;
if (bss > len)
do_brk(len, bss - len);
error = 0;

-- 
Matthew Wilcox <willy@bofh.ai>
"Windows and MacOS are products, contrived by engineers in the service of
specific companies. Unix, by contrast, is not so much a product as it is a
painstakingly compiled oral history of the hacker subculture." - N Stephenson

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/