Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / fs / binfmt_elf.c
index 6884e19..16f7354 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <asm/param.h>
 #include <asm/page.h>
+#include <asm/exec.h>
 
 static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(struct file *);
@@ -66,12 +67,11 @@ static int elf_core_dump(struct coredump_params *cprm);
 #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
 
 static struct linux_binfmt elf_format = {
-               .module         = THIS_MODULE,
-               .load_binary    = load_elf_binary,
-               .load_shlib     = load_elf_library,
-               .core_dump      = elf_core_dump,
-               .min_coredump   = ELF_EXEC_PAGESIZE,
-               .hasvdso        = 1
+       .module         = THIS_MODULE,
+       .load_binary    = load_elf_binary,
+       .load_shlib     = load_elf_library,
+       .core_dump      = elf_core_dump,
+       .min_coredump   = ELF_EXEC_PAGESIZE,
 };
 
 #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
@@ -82,9 +82,7 @@ static int set_brk(unsigned long start, unsigned long end)
        end = ELF_PAGEALIGN(end);
        if (end > start) {
                unsigned long addr;
-               down_write(&current->mm->mmap_sem);
-               addr = do_brk(start, end - start);
-               up_write(&current->mm->mmap_sem);
+               addr = vm_brk(start, end - start);
                if (BAD_ADDR(addr))
                        return addr;
        }
@@ -316,8 +314,6 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        return 0;
 }
 
-#ifndef elf_map
-
 static unsigned long elf_map(struct file *filep, unsigned long addr,
                struct elf_phdr *eppnt, int prot, int type,
                unsigned long total_size)
@@ -354,8 +350,6 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
        return(map_addr);
 }
 
-#endif /* !elf_map */
-
 static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
 {
        int i, first_idx = -1, last_idx = -1;
@@ -421,7 +415,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                goto out;
 
        retval = kernel_read(interpreter, interp_elf_ex->e_phoff,
-                            (char *)elf_phdata,size);
+                            (char *)elf_phdata, size);
        error = -EIO;
        if (retval != size) {
                if (retval < 0)
@@ -518,9 +512,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
 
                /* Map the last of the bss segment */
-               down_write(&current->mm->mmap_sem);
-               error = do_brk(elf_bss, last_bss - elf_bss);
-               up_write(&current->mm->mmap_sem);
+               error = vm_brk(elf_bss, last_bss - elf_bss);
                if (BAD_ADDR(error))
                        goto out_close;
        }
@@ -575,7 +567,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        unsigned long elf_entry;
        unsigned long interp_load_addr = 0;
        unsigned long start_code, end_code, start_data, end_data;
-       unsigned long reloc_func_desc = 0;
+       unsigned long reloc_func_desc __maybe_unused = 0;
        int executable_stack = EXSTACK_DEFAULT;
        unsigned long def_flags = 0;
        struct {
@@ -601,7 +593,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto out;
        if (!elf_check_arch(&loc->elf_ex))
                goto out;
-       if (!bprm->file->f_op||!bprm->file->f_op->mmap)
+       if (!bprm->file->f_op || !bprm->file->f_op->mmap)
                goto out;
 
        /* Now read in all of the header information */
@@ -673,8 +665,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                         * mm->dumpable = 0 regardless of the interpreter's
                         * permissions.
                         */
-                       if (file_permission(interpreter, MAY_READ) < 0)
-                               bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+                       would_dump(bprm, interpreter);
 
                        retval = kernel_read(interpreter, 0, bprm->buf,
                                             BINPRM_BUF_SIZE);
@@ -718,7 +709,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto out_free_dentry;
 
        /* OK, This is the point of no return */
-       current->flags &= ~PF_FORKNOEXEC;
        current->mm->def_flags = def_flags;
 
        /* Do this immediately, since STACK_TOP as used in setup_arg_pages
@@ -761,8 +751,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                        /* There was a PT_LOAD segment with p_memsz > p_filesz
                           before this one. Map anonymous pages, if needed,
                           and clear the area.  */
-                       retval = set_brk (elf_bss + load_bias,
-                                         elf_brk + load_bias);
+                       retval = set_brk(elf_bss + load_bias,
+                                        elf_brk + load_bias);
                        if (retval) {
                                send_sig(SIGKILL, current, 0);
                                goto out_free_dentry;
@@ -800,8 +790,17 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                         * default mmap base, as well as whatever program they
                         * might try to exec.  This is because the brk will
                         * follow the loader, and is not movable.  */
-#if defined(CONFIG_X86) || defined(CONFIG_ARM)
-                       load_bias = 0;
+#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
+                       /* Memory randomization might have been switched off
+                        * in runtime via sysctl.
+                        * If that is the case, retain the original non-zero
+                        * load_bias value in order to establish proper
+                        * non-randomized mappings.
+                        */
+                       if (current->flags & PF_RANDOMIZE)
+                               load_bias = 0;
+                       else
+                               load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #else
                        load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
 #endif
@@ -931,7 +930,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
        retval = create_elf_tables(bprm, &loc->elf_ex,
                          load_addr, interp_load_addr);
        if (retval < 0) {
@@ -946,9 +944,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        current->mm->start_stack = bprm->p;
 
 #ifdef arch_randomize_brk
-       if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
+       if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
                current->mm->brk = current->mm->start_brk =
                        arch_randomize_brk(current->mm);
+#ifdef CONFIG_COMPAT_BRK
+               current->brk_randomized = 1;
+#endif
+       }
 #endif
 
        if (current->personality & MMAP_PAGE_ZERO) {
@@ -956,10 +958,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                   and some applications "depend" upon this behavior.
                   Since we do not have the power to recompile these, we
                   emulate the SVr4 behavior. Sigh. */
-               down_write(&current->mm->mmap_sem);
-               error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
+               error = vm_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE, 0);
-               up_write(&current->mm->mmap_sem);
        }
 
 #ifdef ELF_PLAT_INIT
@@ -1044,8 +1044,7 @@ static int load_elf_library(struct file *file)
                eppnt++;
 
        /* Now use mmap to map the library into memory. */
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap(file,
+       error = vm_mmap(file,
                        ELF_PAGESTART(eppnt->p_vaddr),
                        (eppnt->p_filesz +
                         ELF_PAGEOFFSET(eppnt->p_vaddr)),
@@ -1053,7 +1052,6 @@ static int load_elf_library(struct file *file)
                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
                        (eppnt->p_offset -
                         ELF_PAGEOFFSET(eppnt->p_vaddr)));
-       up_write(&current->mm->mmap_sem);
        if (error != ELF_PAGESTART(eppnt->p_vaddr))
                goto out_free_ph;
 
@@ -1066,11 +1064,8 @@ static int load_elf_library(struct file *file)
        len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
                            ELF_MIN_ALIGN - 1);
        bss = eppnt->p_memsz + eppnt->p_vaddr;
-       if (bss > len) {
-               down_write(&current->mm->mmap_sem);
-               do_brk(len, bss - len);
-               up_write(&current->mm->mmap_sem);
-       }
+       if (bss > len)
+               vm_brk(len, bss - len);
        error = 0;
 
 out_free_ph:
@@ -1088,6 +1083,29 @@ out:
  */
 
 /*
+ * 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.
+ * In that way we ensure that the core dump is fully interpretable later
+ * without matching up the same kernel and hardware config to see what PC values
+ * meant. These special mappings include - vDSO, vsyscall, and other
+ * architecture specific mappings
+ */
+static bool always_dump_vma(struct vm_area_struct *vma)
+{
+       /* Any vsyscall mappings? */
+       if (vma == get_gate_vma(vma->vm_mm))
+               return true;
+       /*
+        * arch_vma_name() returns non-NULL for special architecture mappings,
+        * such as vDSO sections.
+        */
+       if (arch_vma_name(vma))
+               return true;
+
+       return false;
+}
+
+/*
  * Decide what to dump of a segment, part, all or none.
  */
 static unsigned long vma_dump_size(struct vm_area_struct *vma,
@@ -1095,10 +1113,13 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
 {
 #define FILTER(type)   (mm_flags & (1UL << MMF_DUMP_##type))
 
-       /* The vma can be set up to tell us the answer directly.  */
-       if (vma->vm_flags & VM_ALWAYSDUMP)
+       /* always dump the vdso and vsyscall sections */
+       if (always_dump_vma(vma))
                goto whole;
 
+       if (vma->vm_flags & VM_NODUMP)
+               return 0;
+
        /* Hugetlb memory check */
        if (vma->vm_flags & VM_HUGETLB) {
                if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
@@ -1383,6 +1404,22 @@ static void do_thread_regset_writeback(struct task_struct *task,
                regset->writeback(task, regset, 1);
 }
 
+#ifndef PR_REG_SIZE
+#define PR_REG_SIZE(S) sizeof(S)
+#endif
+
+#ifndef PRSTATUS_SIZE
+#define PRSTATUS_SIZE(S) sizeof(S)
+#endif
+
+#ifndef PR_REG_PTR
+#define PR_REG_PTR(S) (&((S)->pr_reg))
+#endif
+
+#ifndef SET_PR_FPVALID
+#define SET_PR_FPVALID(S, V) ((S)->pr_fpvalid = (V))
+#endif
+
 static int fill_thread_core_info(struct elf_thread_core_info *t,
                                 const struct user_regset_view *view,
                                 long signr, size_t *total)
@@ -1397,11 +1434,11 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
         */
        fill_prstatus(&t->prstatus, t->task, signr);
        (void) view->regsets[0].get(t->task, &view->regsets[0],
-                                   0, sizeof(t->prstatus.pr_reg),
-                                   &t->prstatus.pr_reg, NULL);
+                                   0, PR_REG_SIZE(t->prstatus.pr_reg),
+                                   PR_REG_PTR(&t->prstatus), NULL);
 
        fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
-                 sizeof(t->prstatus), &t->prstatus);
+                 PRSTATUS_SIZE(t->prstatus), &t->prstatus);
        *total += notesize(&t->notes[0]);
 
        do_thread_regset_writeback(t->task, &view->regsets[0]);
@@ -1414,7 +1451,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
        for (i = 1; i < view->n; ++i) {
                const struct user_regset *regset = &view->regsets[i];
                do_thread_regset_writeback(t->task, regset);
-               if (regset->core_note_type &&
+               if (regset->core_note_type && regset->get &&
                    (!regset->active || regset->active(t->task, regset))) {
                        int ret;
                        size_t size = regset->n * regset->size;
@@ -1431,7 +1468,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
                                                  regset->core_note_type,
                                                  size, data);
                                else {
-                                       t->prstatus.pr_fpvalid = 1;
+                                       SET_PR_FPVALID(&t->prstatus, 1);
                                        fill_note(&t->notes[i], "CORE",
                                                  NT_PRFPREG, size, data);
                                }
@@ -1911,7 +1948,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        segs = current->mm->map_count;
        segs += elf_core_extra_phdrs();
 
-       gate_vma = get_gate_vma(current);
+       gate_vma = get_gate_vma(current->mm);
        if (gate_vma != NULL)
                segs++;
 
@@ -2070,7 +2107,8 @@ out:
 
 static int __init init_elf_binfmt(void)
 {
-       return register_binfmt(&elf_format);
+       register_binfmt(&elf_format);
+       return 0;
 }
 
 static void __exit exit_elf_binfmt(void)