patch-2.4.11-dontuse linux/fs/binfmt_elf.c
Next file: linux/fs/block_dev.c
Previous file: linux/fs/binfmt_aout.c
Back to the patch index
Back to the overall index
- Lines: 179
- Date:
Fri Oct 5 12:19:45 2001
- Orig file:
v2.4.10/linux/fs/binfmt_elf.c
- Orig date:
Sun Sep 23 11:41:00 2001
diff -u --recursive --new-file v2.4.10/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
@@ -31,6 +31,8 @@
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/smp_lock.h>
+#include <linux/compiler.h>
+#include <linux/limits.h>
#include <asm/uaccess.h>
#include <asm/param.h>
@@ -75,6 +77,8 @@
NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
};
+#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
+
static void set_brk(unsigned long start, unsigned long end)
{
start = ELF_PAGEALIGN(start);
@@ -297,6 +301,8 @@
elf_type |= MAP_FIXED;
map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
+ if (BAD_ADDR(map_addr))
+ goto out_close;
if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
load_addr = map_addr - ELF_PAGESTART(vaddr);
@@ -408,7 +414,6 @@
char * elf_interpreter = 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;
@@ -440,9 +445,11 @@
/* Now read in all of the header information */
retval = -ENOMEM;
- size = ((unsigned int)elf_ex.e_phentsize) * elf_ex.e_phnum;
- if (size > 65536)
+ if (elf_ex.e_phentsize != sizeof(struct elf_phdr))
+ goto out;
+ if (elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
goto out;
+ size = elf_ex.e_phnum * sizeof(struct elf_phdr);
elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
@@ -468,16 +475,14 @@
for (i = 0; i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
- retval = -EINVAL;
- if (elf_interpreter)
- goto out_free_dentry;
-
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/
retval = -ENOMEM;
+ if (elf_ppnt->p_filesz > PATH_MAX)
+ goto out_free_file;
elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL);
if (!elf_interpreter)
@@ -532,6 +537,7 @@
/* Get the exec headers */
interp_ex = *((struct exec *) bprm->buf);
interp_elf_ex = *((struct elfhdr *) bprm->buf);
+ break;
}
elf_ppnt++;
}
@@ -609,8 +615,6 @@
the image should be loaded at fixed address, not at a variable
address. */
- 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;
@@ -618,6 +622,22 @@
if (elf_ppnt->p_type != PT_LOAD)
continue;
+ if (unlikely (elf_brk > elf_bss)) {
+ unsigned long nbyte;
+
+ /* There was a PT_LOAD segment with p_memsz > p_filesz
+ before this one. Map anonymous pages, if needed,
+ and clear the area. */
+ set_brk (elf_bss + load_bias, elf_brk + load_bias);
+ nbyte = ELF_PAGEOFFSET(elf_bss);
+ if (nbyte) {
+ nbyte = ELF_MIN_ALIGN - nbyte;
+ if (nbyte > elf_brk - elf_bss)
+ nbyte = elf_brk - elf_bss;
+ clear_user((void *) elf_bss + load_bias, nbyte);
+ }
+ }
+
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;
@@ -635,6 +655,8 @@
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
+ if (BAD_ADDR(error))
+ continue;
if (!load_addr_set) {
load_addr_set = 1;
@@ -661,7 +683,6 @@
if (k > elf_brk)
elf_brk = k;
}
- set_fs(old_fs);
elf_entry += load_bias;
elf_bss += load_bias;
@@ -684,7 +705,7 @@
fput(interpreter);
kfree(elf_interpreter);
- if (elf_entry == ~0UL) {
+ if (BAD_ADDR(elf_entry)) {
printk(KERN_ERR "Unable to load interpreter\n");
kfree(elf_phdata);
send_sig(SIGSEGV, current, 0);
@@ -786,7 +807,7 @@
static int load_elf_library(struct file *file)
{
struct elf_phdr *elf_phdata;
- unsigned long elf_bss = 0, bss, len, k;
+ unsigned long elf_bss, bss, len;
int retval, error, i, j;
struct elfhdr elf_ex;
@@ -806,19 +827,18 @@
/* Now read in all of the header information */
j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
- if (j > ELF_MIN_ALIGN)
- goto out;
+ /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */
error = -ENOMEM;
elf_phdata = (struct elf_phdr *) kmalloc(j, GFP_KERNEL);
if (!elf_phdata)
goto out;
- /* N.B. check for error return?? */
- retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum);
-
error = -ENOEXEC;
+ retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata, j);
+ if (retval != j)
+ goto out_free_ph;
+
for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
if ((elf_phdata + i)->p_type == PT_LOAD) j++;
if (j != 1)
@@ -840,9 +860,7 @@
if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
goto out_free_ph;
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
+ elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz;
padzero(elf_bss);
len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)