Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Kernel v2.4.11 /fs/binfmt_elf.c

Filename:/fs/binfmt_elf.c
Lines Added:39
Lines Deleted:21
Also changed in: (Previous) 2.4.11-pre6  2.4.11-pre5  2.4.11-pre4  2.4.11-pre3  2.4.11-pre2  2.4.10-ac10 
(Following) 2.4.12-ac1  2.4.12-ac2  2.4.12-ac3  2.4.12-ac4  2.4.12-ac5  2.4.12-ac6 

Location
[  2.4.11
  [  fs
     o  binfmt_elf.c

Patch

diff -u --recursive --new-file v2.4.10/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.4.10/linux/fs/binfmt_elf.c   Sun Sep 23 11:41:00 2001
+++ linux/fs/binfmt_elf.c   Fri Oct  5 12:19:45 2001
@@ -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);


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.