Merge tag 'v3.10.97' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / binfmt_elf.c
index f8a0b0efda44078c7debba07e2287e91c84405ac..b308a2c47f3461f7c1770897c0091d3c77d82cfe 100644 (file)
@@ -552,11 +552,12 @@ out:
 
 static unsigned long randomize_stack_top(unsigned long stack_top)
 {
-       unsigned int random_variable = 0;
+       unsigned long random_variable = 0;
 
        if ((current->flags & PF_RANDOMIZE) &&
                !(current->personality & ADDR_NO_RANDOMIZE)) {
-               random_variable = get_random_int() & STACK_RND_MASK;
+               random_variable = (unsigned long) get_random_int();
+               random_variable &= STACK_RND_MASK;
                random_variable <<= PAGE_SHIFT;
        }
 #ifdef CONFIG_STACK_GROWSUP
@@ -681,16 +682,16 @@ static int load_elf_binary(struct linux_binprm *bprm)
                         */
                        would_dump(bprm, interpreter);
 
-                       retval = kernel_read(interpreter, 0, bprm->buf,
-                                            BINPRM_BUF_SIZE);
-                       if (retval != BINPRM_BUF_SIZE) {
+                       /* Get the exec headers */
+                       retval = kernel_read(interpreter, 0,
+                                            (void *)&loc->interp_elf_ex,
+                                            sizeof(loc->interp_elf_ex));
+                       if (retval != sizeof(loc->interp_elf_ex)) {
                                if (retval >= 0)
                                        retval = -EIO;
                                goto out_free_dentry;
                        }
 
-                       /* Get the exec headers */
-                       loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
                        break;
                }
                elf_ppnt++;
@@ -755,6 +756,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
            i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
                int elf_prot = 0, elf_flags;
                unsigned long k, vaddr;
+               unsigned long total_size = 0;
 
                if (elf_ppnt->p_type != PT_LOAD)
                        continue;
@@ -819,10 +821,16 @@ static int load_elf_binary(struct linux_binprm *bprm)
 #else
                        load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #endif
+                       total_size = total_mapping_size(elf_phdata,
+                                                       loc->elf_ex.e_phnum);
+                       if (!total_size) {
+                               retval = -EINVAL;
+                               goto out_free_dentry;
+                       }
                }
 
                error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
-                               elf_prot, elf_flags, 0);
+                               elf_prot, elf_flags, total_size);
                if (BAD_ADDR(error)) {
                        send_sig(SIGKILL, current, 0);
                        retval = IS_ERR((void *)error) ?
@@ -1097,6 +1105,11 @@ out:
  * Jeremy Fitzhardinge <jeremy@sw.oz.au>
  */
 
+#ifdef CONFIG_MTK_EXTMEM
+extern bool extmem_in_mspace(struct vm_area_struct *vma);
+extern unsigned long get_virt_from_mspace(unsigned long pa);
+#endif
+
 /*
  * The purpose of always_dump_vma() is to make sure that special kernel mappings
  * that are useful for post-mortem analysis are included in every core dump.
@@ -1117,6 +1130,11 @@ static bool always_dump_vma(struct vm_area_struct *vma)
        if (arch_vma_name(vma))
                return true;
 
+#ifdef CONFIG_MTK_EXTMEM
+       if (extmem_in_mspace(vma)) {
+               return true;
+       }       
+#endif
        return false;
 }
 
@@ -1415,7 +1433,7 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
  *   long file_ofs
  * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
  */
-static void fill_files_note(struct memelfnote *note)
+static int fill_files_note(struct memelfnote *note)
 {
        struct vm_area_struct *vma;
        unsigned count, size, names_ofs, remaining, n;
@@ -1430,11 +1448,11 @@ static void fill_files_note(struct memelfnote *note)
        names_ofs = (2 + 3 * count) * sizeof(data[0]);
  alloc:
        if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
-               goto err;
+               return -EINVAL;
        size = round_up(size, PAGE_SIZE);
        data = vmalloc(size);
        if (!data)
-               goto err;
+               return -ENOMEM;
 
        start_end_ofs = data + 2;
        name_base = name_curpos = ((char *)data) + names_ofs;
@@ -1487,7 +1505,7 @@ static void fill_files_note(struct memelfnote *note)
 
        size = name_curpos - (char *)data;
        fill_note(note, "CORE", NT_FILE, size, data);
err: ;
      return 0;
 }
 
 #ifdef CORE_DUMP_USE_REGSET
@@ -1688,8 +1706,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        fill_auxv_note(&info->auxv, current->mm);
        info->size += notesize(&info->auxv);
 
-       fill_files_note(&info->files);
-       info->size += notesize(&info->files);
+       if (fill_files_note(&info->files) == 0)
+               info->size += notesize(&info->files);
 
        return 1;
 }
@@ -1721,7 +1739,8 @@ static int write_note_info(struct elf_note_info *info,
                        return 0;
                if (first && !writenote(&info->auxv, file, foffset))
                        return 0;
-               if (first && !writenote(&info->files, file, foffset))
+               if (first && info->files.data &&
+                               !writenote(&info->files, file, foffset))
                        return 0;
 
                for (i = 1; i < info->thread_notes; ++i)
@@ -1808,6 +1827,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
 
 struct elf_note_info {
        struct memelfnote *notes;
+       struct memelfnote *notes_files;
        struct elf_prstatus *prstatus;  /* NT_PRSTATUS */
        struct elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
        struct list_head thread_list;
@@ -1898,9 +1918,12 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 
        fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
        fill_auxv_note(info->notes + 3, current->mm);
-       fill_files_note(info->notes + 4);
+       info->numnote = 4;
 
-       info->numnote = 5;
+       if (fill_files_note(info->notes + info->numnote) == 0) {
+               info->notes_files = info->notes + info->numnote;
+               info->numnote++;
+       }
 
        /* Try to dump the FPU. */
        info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
@@ -1962,8 +1985,9 @@ static void free_note_info(struct elf_note_info *info)
                kfree(list_entry(tmp, struct elf_thread_status, list));
        }
 
-       /* Free data allocated by fill_files_note(): */
-       vfree(info->notes[4].data);
+       /* Free data possibly allocated by fill_files_note(): */
+       if (info->notes_files)
+               vfree(info->notes_files->data);
 
        kfree(info->prstatus);
        kfree(info->psinfo);
@@ -2046,12 +2070,14 @@ static int elf_core_dump(struct coredump_params *cprm)
        struct vm_area_struct *vma, *gate_vma;
        struct elfhdr *elf = NULL;
        loff_t offset = 0, dataoff, foffset;
-       struct elf_note_info info;
+       struct elf_note_info info = { };
        struct elf_phdr *phdr4note = NULL;
        struct elf_shdr *shdr4extnum = NULL;
        Elf_Half e_phnum;
        elf_addr_t e_shoff;
 
+       printk(KERN_WARNING "coredump(%d): start\n", current->pid);
+
        /*
         * We no longer stop all VM operations.
         * 
@@ -2180,6 +2206,8 @@ static int elf_core_dump(struct coredump_params *cprm)
        if (!dump_seek(cprm->file, dataoff - foffset))
                goto end_coredump;
 
+       printk(KERN_WARNING "coredump(%d): write output program header and notes\n", current->pid);
+
        for (vma = first_vma(current, gate_vma); vma != NULL;
                        vma = next_vma(vma, gate_vma)) {
                unsigned long addr;
@@ -2187,6 +2215,24 @@ static int elf_core_dump(struct coredump_params *cprm)
 
                end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
 
+#ifdef CONFIG_MTK_EXTMEM
+               if (extmem_in_mspace(vma)) {
+                       void *extmem_va = (void *)get_virt_from_mspace(vma->vm_pgoff << PAGE_SHIFT);
+                       for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE, extmem_va += PAGE_SIZE) {
+                               int stop;
+                               int dump_write_ret = dump_write(cprm->file, extmem_va, PAGE_SIZE);
+                               stop = ((size += PAGE_SIZE) > cprm->limit) || (!dump_write_ret);
+                               if (stop) {
+                                       printk(KERN_WARNING "[EXT_MEM]stop addr:0x%lx, size:%zx, limit:0x%lx, dump_write_ret:%d\n", 
+                                                       addr, size, cprm->limit, dump_write_ret);
+                                       goto end_coredump;
+                               }
+                       }
+                       continue;
+               }
+#endif
+
+               //printk(KERN_WARNING "coredump(%d): write out load vm start:%08lx, end:%08lx\n", current->pid, vma->vm_start, end);
                for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
                        struct page *page;
                        int stop;
@@ -2199,13 +2245,22 @@ static int elf_core_dump(struct coredump_params *cprm)
                                                    PAGE_SIZE);
                                kunmap(page);
                                page_cache_release(page);
-                       } else
+                               if (stop) {
+                                       printk(KERN_WARNING "coredump(%d): failed to write core dump\n", current->pid);
+                               }
+                       } else {
                                stop = !dump_seek(cprm->file, PAGE_SIZE);
+                               if (stop) {
+                                       printk(KERN_WARNING "coredump(%d): failed to seek core dump\n", current->pid);
+                               }
+                       }
                        if (stop)
                                goto end_coredump;
                }
        }
 
+       printk(KERN_WARNING "coredump(%d): write loads\n", current->pid);
+
        if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
                goto end_coredump;
 
@@ -2217,6 +2272,8 @@ static int elf_core_dump(struct coredump_params *cprm)
                        goto end_coredump;
        }
 
+       printk(KERN_WARNING "coredump(%d): write out completed %lld\n", current->pid, offset);
+
 end_coredump:
        set_fs(fs);