media: adv7180: Add init_cfg pad operation
[linux-2.6-microblaze.git] / fs / binfmt_elf.c
index ecd8d26..f4713ea 100644 (file)
@@ -97,7 +97,7 @@ static struct linux_binfmt elf_format = {
        .min_coredump   = ELF_EXEC_PAGESIZE,
 };
 
-#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
+#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE))
 
 static int set_brk(unsigned long start, unsigned long end, int prot)
 {
@@ -161,9 +161,11 @@ static int padzero(unsigned long elf_bss)
 #endif
 
 static int
-create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
-               unsigned long load_addr, unsigned long interp_load_addr)
+create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
+               unsigned long load_addr, unsigned long interp_load_addr,
+               unsigned long e_entry)
 {
+       struct mm_struct *mm = current->mm;
        unsigned long p = bprm->p;
        int argc = bprm->argc;
        int envc = bprm->envc;
@@ -176,7 +178,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        unsigned char k_rand_bytes[16];
        int items;
        elf_addr_t *elf_info;
-       int ei_index = 0;
+       int ei_index;
        const struct cred *cred = current_cred();
        struct vm_area_struct *vma;
 
@@ -226,12 +228,12 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                return -EFAULT;
 
        /* Create the ELF interpreter info */
-       elf_info = (elf_addr_t *)current->mm->saved_auxv;
+       elf_info = (elf_addr_t *)mm->saved_auxv;
        /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
 #define NEW_AUX_ENT(id, val) \
        do { \
-               elf_info[ei_index++] = id; \
-               elf_info[ei_index++] = val; \
+               *elf_info++ = id; \
+               *elf_info++ = val; \
        } while (0)
 
 #ifdef ARCH_DLINFO
@@ -251,7 +253,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
        NEW_AUX_ENT(AT_BASE, interp_load_addr);
        NEW_AUX_ENT(AT_FLAGS, 0);
-       NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
+       NEW_AUX_ENT(AT_ENTRY, e_entry);
        NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
        NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
        NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
@@ -275,12 +277,13 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        }
 #undef NEW_AUX_ENT
        /* AT_NULL is zero; clear the rest too */
-       memset(&elf_info[ei_index], 0,
-              sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]);
+       memset(elf_info, 0, (char *)mm->saved_auxv +
+                       sizeof(mm->saved_auxv) - (char *)elf_info);
 
        /* And advance past the AT_NULL entry.  */
-       ei_index += 2;
+       elf_info += 2;
 
+       ei_index = elf_info - (elf_addr_t *)mm->saved_auxv;
        sp = STACK_ADD(p, ei_index);
 
        items = (argc + 1) + (envc + 1) + 1;
@@ -299,7 +302,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
         * 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);
+       vma = find_extend_vma(mm, bprm->p);
        if (!vma)
                return -EFAULT;
 
@@ -308,7 +311,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
                return -EFAULT;
 
        /* Populate list of argv pointers back to argv strings. */
-       p = current->mm->arg_end = current->mm->arg_start;
+       p = mm->arg_end = mm->arg_start;
        while (argc-- > 0) {
                size_t len;
                if (__put_user((elf_addr_t)p, sp++))
@@ -320,10 +323,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        }
        if (__put_user(0, sp++))
                return -EFAULT;
-       current->mm->arg_end = p;
+       mm->arg_end = p;
 
        /* Populate list of envp pointers back to envp strings. */
-       current->mm->env_end = current->mm->env_start = p;
+       mm->env_end = mm->env_start = p;
        while (envc-- > 0) {
                size_t len;
                if (__put_user((elf_addr_t)p, sp++))
@@ -335,10 +338,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
        }
        if (__put_user(0, sp++))
                return -EFAULT;
-       current->mm->env_end = p;
+       mm->env_end = p;
 
        /* Put the elf_info on the stack in the right place.  */
-       if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)))
+       if (copy_to_user(sp, mm->saved_auxv, ei_index * sizeof(elf_addr_t)))
                return -EFAULT;
        return 0;
 }
@@ -689,15 +692,17 @@ static int load_elf_binary(struct linux_binprm *bprm)
        int bss_prot = 0;
        int retval, i;
        unsigned long elf_entry;
+       unsigned long e_entry;
        unsigned long interp_load_addr = 0;
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long reloc_func_desc __maybe_unused = 0;
        int executable_stack = EXSTACK_DEFAULT;
+       struct elfhdr *elf_ex = (struct elfhdr *)bprm->buf;
        struct {
-               struct elfhdr elf_ex;
                struct elfhdr interp_elf_ex;
        } *loc;
        struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
+       struct mm_struct *mm;
        struct pt_regs *regs;
 
        loc = kmalloc(sizeof(*loc), GFP_KERNEL);
@@ -705,30 +710,27 @@ static int load_elf_binary(struct linux_binprm *bprm)
                retval = -ENOMEM;
                goto out_ret;
        }
-       
-       /* Get the exec-header */
-       loc->elf_ex = *((struct elfhdr *)bprm->buf);
 
        retval = -ENOEXEC;
        /* First of all, some simple consistency checks */
-       if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+       if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0)
                goto out;
 
-       if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
+       if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN)
                goto out;
-       if (!elf_check_arch(&loc->elf_ex))
+       if (!elf_check_arch(elf_ex))
                goto out;
-       if (elf_check_fdpic(&loc->elf_ex))
+       if (elf_check_fdpic(elf_ex))
                goto out;
        if (!bprm->file->f_op->mmap)
                goto out;
 
-       elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
+       elf_phdata = load_elf_phdrs(elf_ex, bprm->file);
        if (!elf_phdata)
                goto out;
 
        elf_ppnt = elf_phdata;
-       for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
+       for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) {
                char *elf_interpreter;
 
                if (elf_ppnt->p_type != PT_INTERP)
@@ -782,7 +784,7 @@ out_free_interp:
        }
 
        elf_ppnt = elf_phdata;
-       for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
+       for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++)
                switch (elf_ppnt->p_type) {
                case PT_GNU_STACK:
                        if (elf_ppnt->p_flags & PF_X)
@@ -792,7 +794,7 @@ out_free_interp:
                        break;
 
                case PT_LOPROC ... PT_HIPROC:
-                       retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt,
+                       retval = arch_elf_pt_proc(elf_ex, elf_ppnt,
                                                  bprm->file, false,
                                                  &arch_state);
                        if (retval)
@@ -836,7 +838,7 @@ out_free_interp:
         * still possible to return an error to the code that invoked
         * the exec syscall.
         */
-       retval = arch_check_elf(&loc->elf_ex,
+       retval = arch_check_elf(elf_ex,
                                !!interpreter, &loc->interp_elf_ex,
                                &arch_state);
        if (retval)
@@ -849,8 +851,8 @@ out_free_interp:
 
        /* Do this immediately, since STACK_TOP as used in setup_arg_pages
           may depend on the personality.  */
-       SET_PERSONALITY2(loc->elf_ex, &arch_state);
-       if (elf_read_implies_exec(loc->elf_ex, executable_stack))
+       SET_PERSONALITY2(*elf_ex, &arch_state);
+       if (elf_read_implies_exec(*elf_ex, executable_stack))
                current->personality |= READ_IMPLIES_EXEC;
 
        if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
@@ -877,7 +879,7 @@ out_free_interp:
        /* Now we do a little grungy work by mmapping the ELF image into
           the correct location in memory. */
        for(i = 0, elf_ppnt = elf_phdata;
-           i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
+           i < elf_ex->e_phnum; i++, elf_ppnt++) {
                int elf_prot, elf_flags;
                unsigned long k, vaddr;
                unsigned long total_size = 0;
@@ -921,9 +923,9 @@ out_free_interp:
                 * If we are loading ET_EXEC or we have already performed
                 * the ET_DYN load_addr calculations, proceed normally.
                 */
-               if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
+               if (elf_ex->e_type == ET_EXEC || load_addr_set) {
                        elf_flags |= MAP_FIXED;
-               } else if (loc->elf_ex.e_type == ET_DYN) {
+               } else if (elf_ex->e_type == ET_DYN) {
                        /*
                         * This logic is run once for the first LOAD Program
                         * Header for ET_DYN binaries to calculate the
@@ -972,7 +974,7 @@ out_free_interp:
                        load_bias = ELF_PAGESTART(load_bias - vaddr);
 
                        total_size = total_mapping_size(elf_phdata,
-                                                       loc->elf_ex.e_phnum);
+                                                       elf_ex->e_phnum);
                        if (!total_size) {
                                retval = -EINVAL;
                                goto out_free_dentry;
@@ -990,7 +992,7 @@ out_free_interp:
                if (!load_addr_set) {
                        load_addr_set = 1;
                        load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
-                       if (loc->elf_ex.e_type == ET_DYN) {
+                       if (elf_ex->e_type == ET_DYN) {
                                load_bias += error -
                                             ELF_PAGESTART(load_bias + vaddr);
                                load_addr += load_bias;
@@ -998,7 +1000,7 @@ out_free_interp:
                        }
                }
                k = elf_ppnt->p_vaddr;
-               if (k < start_code)
+               if ((elf_ppnt->p_flags & PF_X) && k < start_code)
                        start_code = k;
                if (start_data < k)
                        start_data = k;
@@ -1031,7 +1033,7 @@ out_free_interp:
                }
        }
 
-       loc->elf_ex.e_entry += load_bias;
+       e_entry = elf_ex->e_entry + load_bias;
        elf_bss += load_bias;
        elf_brk += load_bias;
        start_code += load_bias;
@@ -1074,7 +1076,7 @@ out_free_interp:
                allow_write_access(interpreter);
                fput(interpreter);
        } else {
-               elf_entry = loc->elf_ex.e_entry;
+               elf_entry = e_entry;
                if (BAD_ADDR(elf_entry)) {
                        retval = -EINVAL;
                        goto out_free_dentry;
@@ -1092,15 +1094,17 @@ out_free_interp:
                goto out;
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
-       retval = create_elf_tables(bprm, &loc->elf_ex,
-                         load_addr, interp_load_addr);
+       retval = create_elf_tables(bprm, elf_ex,
+                         load_addr, interp_load_addr, e_entry);
        if (retval < 0)
                goto out;
-       current->mm->end_code = end_code;
-       current->mm->start_code = start_code;
-       current->mm->start_data = start_data;
-       current->mm->end_data = end_data;
-       current->mm->start_stack = bprm->p;
+
+       mm = current->mm;
+       mm->end_code = end_code;
+       mm->start_code = start_code;
+       mm->start_data = start_data;
+       mm->end_data = end_data;
+       mm->start_stack = bprm->p;
 
        if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
                /*
@@ -1111,12 +1115,11 @@ out_free_interp:
                 * growing down), and into the unused ELF_ET_DYN_BASE region.
                 */
                if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
-                   loc->elf_ex.e_type == ET_DYN && !interpreter)
-                       current->mm->brk = current->mm->start_brk =
-                               ELF_ET_DYN_BASE;
+                   elf_ex->e_type == ET_DYN && !interpreter) {
+                       mm->brk = mm->start_brk = ELF_ET_DYN_BASE;
+               }
 
-               current->mm->brk = current->mm->start_brk =
-                       arch_randomize_brk(current->mm);
+               mm->brk = mm->start_brk = arch_randomize_brk(mm);
 #ifdef compat_brk_randomized
                current->brk_randomized = 1;
 #endif
@@ -1574,6 +1577,7 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
  */
 static int fill_files_note(struct memelfnote *note)
 {
+       struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        unsigned count, size, names_ofs, remaining, n;
        user_long_t *data;
@@ -1581,7 +1585,7 @@ static int fill_files_note(struct memelfnote *note)
        char *name_base, *name_curpos;
 
        /* *Estimated* file count and total data size needed */
-       count = current->mm->map_count;
+       count = mm->map_count;
        if (count > UINT_MAX / 64)
                return -EINVAL;
        size = count * 64;
@@ -1591,6 +1595,10 @@ static int fill_files_note(struct memelfnote *note)
        if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
                return -EINVAL;
        size = round_up(size, PAGE_SIZE);
+       /*
+        * "size" can be 0 here legitimately.
+        * Let it ENOMEM and omit NT_FILE section which will be empty anyway.
+        */
        data = kvmalloc(size, GFP_KERNEL);
        if (ZERO_OR_NULL_PTR(data))
                return -ENOMEM;
@@ -1599,7 +1607,7 @@ static int fill_files_note(struct memelfnote *note)
        name_base = name_curpos = ((char *)data) + names_ofs;
        remaining = size - names_ofs;
        count = 0;
-       for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+       for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
                struct file *file;
                const char *filename;
 
@@ -1633,10 +1641,10 @@ static int fill_files_note(struct memelfnote *note)
        data[0] = count;
        data[1] = PAGE_SIZE;
        /*
-        * Count usually is less than current->mm->map_count,
+        * Count usually is less than mm->map_count,
         * we need to move filenames down.
         */
-       n = current->mm->map_count - count;
+       n = mm->map_count - count;
        if (n != 0) {
                unsigned shift_bytes = n * 3 * sizeof(data[0]);
                memmove(name_base - shift_bytes, name_base,
@@ -2182,7 +2190,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        int segs, i;
        size_t vma_data_size = 0;
        struct vm_area_struct *vma, *gate_vma;
-       struct elfhdr *elf = NULL;
+       struct elfhdr elf;
        loff_t offset = 0, dataoff;
        struct elf_note_info info = { };
        struct elf_phdr *phdr4note = NULL;
@@ -2203,10 +2211,6 @@ static int elf_core_dump(struct coredump_params *cprm)
         * exists while dumping the mm->vm_next areas to the core file.
         */
   
-       /* alloc memory for large data structures: too large to be on stack */
-       elf = kmalloc(sizeof(*elf), GFP_KERNEL);
-       if (!elf)
-               goto out;
        /*
         * The number of segs are recored into ELF header as 16bit value.
         * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
@@ -2230,7 +2234,7 @@ static int elf_core_dump(struct coredump_params *cprm)
         * Collect all the non-memory information about the process for the
         * notes.  This also sets up the file header.
         */
-       if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs))
+       if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs))
                goto cleanup;
 
        has_dumped = 1;
@@ -2238,7 +2242,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        fs = get_fs();
        set_fs(KERNEL_DS);
 
-       offset += sizeof(*elf);                         /* Elf header */
+       offset += sizeof(elf);                          /* Elf header */
        offset += segs * sizeof(struct elf_phdr);       /* Program headers */
 
        /* Write notes phdr entry */
@@ -2257,11 +2261,13 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
-       if (segs - 1 > ULONG_MAX / sizeof(*vma_filesz))
-               goto end_coredump;
+       /*
+        * Zero vma process will get ZERO_SIZE_PTR here.
+        * Let coredump continue for register state at least.
+        */
        vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)),
                              GFP_KERNEL);
-       if (ZERO_OR_NULL_PTR(vma_filesz))
+       if (!vma_filesz)
                goto end_coredump;
 
        for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
@@ -2281,12 +2287,12 @@ static int elf_core_dump(struct coredump_params *cprm)
                shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
                if (!shdr4extnum)
                        goto end_coredump;
-               fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
+               fill_extnum_info(&elf, shdr4extnum, e_shoff, segs);
        }
 
        offset = dataoff;
 
-       if (!dump_emit(cprm, elf, sizeof(*elf)))
+       if (!dump_emit(cprm, &elf, sizeof(elf)))
                goto end_coredump;
 
        if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
@@ -2370,8 +2376,6 @@ cleanup:
        kfree(shdr4extnum);
        kvfree(vma_filesz);
        kfree(phdr4note);
-       kfree(elf);
-out:
        return has_dumped;
 }