]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/binfmt_elf.c
Deprecate a.out ELF interpreters
[linux-2.6-omap-h63xx.git] / fs / binfmt_elf.c
index fa8ea33ab0be1ef56ff78b5908a691676d815e27..66cd711a6b1a392733187b4c72d8e6dc5cc6b919 100644 (file)
@@ -52,7 +52,7 @@ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, i
  * don't even try.
  */
 #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file);
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
 #else
 #define elf_core_dump  NULL
 #endif
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        elf_addr_t *elf_info;
        int ei_index = 0;
        struct task_struct *tsk = current;
+       struct vm_area_struct *vma;
 
        /*
         * If this architecture has a platform capability string, copy it
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        sp = (elf_addr_t __user *)bprm->p;
 #endif
 
+
+       /*
+        * Grow the stack manually; some architectures have a limit on how
+        * far ahead a user-space access may be in order to grow the stack.
+        */
+       vma = find_extend_vma(current->mm, bprm->p);
+       if (!vma)
+               return -EFAULT;
+
        /* Now, let's put argc (and argv, envp if appropriate) on the stack */
        if (__put_user(argc, sp++))
                return -EFAULT;
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                size_t len;
                if (__put_user((elf_addr_t)p, argv++))
                        return -EFAULT;
-               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+               len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return 0;
                p += len;
        }
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                size_t len;
                if (__put_user((elf_addr_t)p, envp++))
                        return -EFAULT;
-               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-               if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+               len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
                        return 0;
                p += len;
        }
@@ -720,6 +730,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        /* Some simple consistency checks for the interpreter */
        if (elf_interpreter) {
+               static int warn;
                interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 
                /* Now figure out which format our binary is */
@@ -731,6 +742,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
                        interpreter_type &= ~INTERPRETER_ELF;
 
+               if (interpreter_type == INTERPRETER_AOUT && warn < 10) {
+                       printk(KERN_WARNING "a.out ELF interpreter %s is "
+                               "deprecated and will not be supported "
+                               "after Linux 2.6.25\n", elf_interpreter);
+                       warn++;
+               }
+
                retval = -ELIBBAD;
                if (!interpreter_type)
                        goto out_free_dentry;
@@ -777,10 +795,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        }
 
        /* OK, This is the point of no return */
-       current->mm->start_data = 0;
-       current->mm->end_data = 0;
-       current->mm->end_code = 0;
-       current->mm->mmap = NULL;
        current->flags &= ~PF_FORKNOEXEC;
        current->mm->def_flags = def_flags;
 
@@ -988,9 +1002,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
        compute_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
-       create_elf_tables(bprm, &loc->elf_ex,
+       retval = create_elf_tables(bprm, &loc->elf_ex,
                          (interpreter_type == INTERPRETER_AOUT),
                          load_addr, interp_load_addr);
+       if (retval < 0) {
+               send_sig(SIGKILL, current, 0);
+               goto out;
+       }
        /* N.B. passed_fileno might not be initialized? */
        if (interpreter_type == INTERPRETER_AOUT)
                current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -1189,7 +1207,7 @@ static int dump_seek(struct file *file, loff_t off)
  *
  * I think we should skip something. But I am not sure how. H.J.
  */
-static int maydump(struct vm_area_struct *vma)
+static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
 {
        /* The vma can be set up to tell us the answer directly.  */
        if (vma->vm_flags & VM_ALWAYSDUMP)
@@ -1199,15 +1217,19 @@ static int maydump(struct vm_area_struct *vma)
        if (vma->vm_flags & (VM_IO | VM_RESERVED))
                return 0;
 
-       /* Dump shared memory only if mapped from an anonymous file. */
-       if (vma->vm_flags & VM_SHARED)
-               return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
+       /* By default, dump shared memory if mapped from an anonymous file. */
+       if (vma->vm_flags & VM_SHARED) {
+               if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0)
+                       return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
+               else
+                       return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
+       }
 
-       /* If it hasn't been written to, don't write it out */
+       /* By default, if it hasn't been written to, don't write it out. */
        if (!vma->anon_vma)
-               return 0;
+               return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
 
-       return 1;
+       return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
 }
 
 /* An ELF note in memory */
@@ -1397,7 +1419,7 @@ struct elf_thread_status
        elf_fpregset_t fpu;             /* NT_PRFPREG */
        struct task_struct *thread;
 #ifdef ELF_CORE_COPY_XFPREGS
-       elf_fpxregset_t xfpu;           /* NT_PRXFPREG */
+       elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
 #endif
        struct memelfnote notes[3];
        int num_notes;
@@ -1432,8 +1454,8 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
 
 #ifdef ELF_CORE_COPY_XFPREGS
        if (elf_core_copy_task_xfpregs(p, &t->xfpu)) {
-               fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu),
-                         &t->xfpu);
+               fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE,
+                         sizeof(t->xfpu), &t->xfpu);
                t->num_notes++;
                sz += notesize(&t->notes[2]);
        }
@@ -1474,7 +1496,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
+static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
 {
 #define        NUM_NOTES       6
        int has_dumped = 0;
@@ -1485,7 +1507,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
        struct vm_area_struct *vma, *gate_vma;
        struct elfhdr *elf = NULL;
        loff_t offset = 0, dataoff, foffset;
-       unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
        int numnote;
        struct memelfnote *notes = NULL;
        struct elf_prstatus *prstatus = NULL;   /* NT_PRSTATUS */
@@ -1499,6 +1520,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 #endif
        int thread_status_size = 0;
        elf_addr_t *auxv;
+       unsigned long mm_flags;
 
        /*
         * We no longer stop all VM operations.
@@ -1606,7 +1628,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 #ifdef ELF_CORE_COPY_XFPREGS
        if (elf_core_copy_task_xfpregs(current, xfpu))
                fill_note(notes + numnote++,
-                         "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu);
+                         "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
 #endif 
   
        fs = get_fs();
@@ -1627,9 +1649,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                
                sz += thread_status_size;
 
-#ifdef ELF_CORE_WRITE_EXTRA_NOTES
-               sz += ELF_CORE_EXTRA_NOTES_SIZE;
-#endif
+               sz += elf_coredump_extra_notes_size();
 
                fill_elf_note_phdr(&phdr, sz, offset);
                offset += sz;
@@ -1638,6 +1658,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
+       /*
+        * We must use the same mm->flags while dumping core to avoid
+        * inconsistency between the program headers and bodies, otherwise an
+        * unusable core file can be generated.
+        */
+       mm_flags = current->mm->flags;
+
        /* Write program headers for segments dump */
        for (vma = first_vma(current, gate_vma); vma != NULL;
                        vma = next_vma(vma, gate_vma)) {
@@ -1650,7 +1677,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                phdr.p_offset = offset;
                phdr.p_vaddr = vma->vm_start;
                phdr.p_paddr = 0;
-               phdr.p_filesz = maydump(vma) ? sz : 0;
+               phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0;
                phdr.p_memsz = sz;
                offset += phdr.p_filesz;
                phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1672,9 +1699,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                if (!writenote(notes + i, file, &foffset))
                        goto end_coredump;
 
-#ifdef ELF_CORE_WRITE_EXTRA_NOTES
-       ELF_CORE_WRITE_EXTRA_NOTES;
-#endif
+       if (elf_coredump_extra_notes_write(file, &foffset))
+               goto end_coredump;
 
        /* write out the thread status notes section */
        list_for_each(t, &thread_list) {
@@ -1693,7 +1719,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                        vma = next_vma(vma, gate_vma)) {
                unsigned long addr;
 
-               if (!maydump(vma))
+               if (!maydump(vma, mm_flags))
                        continue;
 
                for (addr = vma->vm_start;
@@ -1706,7 +1732,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
                                                &page, &vma) <= 0) {
                                DUMP_SEEK(PAGE_SIZE);
                        } else {
-                               if (page == ZERO_PAGE(addr)) {
+                               if (page == ZERO_PAGE(0)) {
                                        if (!dump_seek(file, PAGE_SIZE)) {
                                                page_cache_release(page);
                                                goto end_coredump;