arm64: Add MIDR value for KRYO2XX gold/silver CPU cores
[linux-2.6-microblaze.git] / fs / binfmt_elf.c
index cf956ed..b6b3d05 100644 (file)
@@ -310,7 +310,10 @@ create_elf_tables(struct linux_binprm *bprm, const 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.
         */
+       if (mmap_read_lock_killable(mm))
+               return -EINTR;
        vma = find_extend_vma(mm, bprm->p);
+       mmap_read_unlock(mm);
        if (!vma)
                return -EFAULT;
 
@@ -1414,126 +1417,6 @@ out:
  * Jeremy Fitzhardinge <jeremy@sw.oz.au>
  */
 
-/*
- * 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;
-
-       /*
-        * Assume that all vmas with a .name op should always be dumped.
-        * If this changes, a new vm_ops field can easily be added.
-        */
-       if (vma->vm_ops && vma->vm_ops->name && vma->vm_ops->name(vma))
-               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,
-                                  unsigned long mm_flags)
-{
-#define FILTER(type)   (mm_flags & (1UL << MMF_DUMP_##type))
-
-       /* always dump the vdso and vsyscall sections */
-       if (always_dump_vma(vma))
-               goto whole;
-
-       if (vma->vm_flags & VM_DONTDUMP)
-               return 0;
-
-       /* support for DAX */
-       if (vma_is_dax(vma)) {
-               if ((vma->vm_flags & VM_SHARED) && FILTER(DAX_SHARED))
-                       goto whole;
-               if (!(vma->vm_flags & VM_SHARED) && FILTER(DAX_PRIVATE))
-                       goto whole;
-               return 0;
-       }
-
-       /* Hugetlb memory check */
-       if (is_vm_hugetlb_page(vma)) {
-               if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
-                       goto whole;
-               if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE))
-                       goto whole;
-               return 0;
-       }
-
-       /* Do not dump I/O mapped devices or special mappings */
-       if (vma->vm_flags & VM_IO)
-               return 0;
-
-       /* By default, dump shared memory if mapped from an anonymous file. */
-       if (vma->vm_flags & VM_SHARED) {
-               if (file_inode(vma->vm_file)->i_nlink == 0 ?
-                   FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED))
-                       goto whole;
-               return 0;
-       }
-
-       /* Dump segments that have been written to.  */
-       if (vma->anon_vma && FILTER(ANON_PRIVATE))
-               goto whole;
-       if (vma->vm_file == NULL)
-               return 0;
-
-       if (FILTER(MAPPED_PRIVATE))
-               goto whole;
-
-       /*
-        * If this looks like the beginning of a DSO or executable mapping,
-        * check for an ELF header.  If we find one, dump the first page to
-        * aid in determining what was mapped here.
-        */
-       if (FILTER(ELF_HEADERS) &&
-           vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
-               u32 __user *header = (u32 __user *) vma->vm_start;
-               u32 word;
-               /*
-                * Doing it this way gets the constant folded by GCC.
-                */
-               union {
-                       u32 cmp;
-                       char elfmag[SELFMAG];
-               } magic;
-               BUILD_BUG_ON(SELFMAG != sizeof word);
-               magic.elfmag[EI_MAG0] = ELFMAG0;
-               magic.elfmag[EI_MAG1] = ELFMAG1;
-               magic.elfmag[EI_MAG2] = ELFMAG2;
-               magic.elfmag[EI_MAG3] = ELFMAG3;
-               if (unlikely(get_user(word, header)))
-                       word = 0;
-               if (word == magic.cmp)
-                       return PAGE_SIZE;
-       }
-
-#undef FILTER
-
-       return 0;
-
-whole:
-       return vma->vm_end - vma->vm_start;
-}
-
 /* An ELF note in memory */
 struct memelfnote
 {
@@ -2245,32 +2128,6 @@ static void free_note_info(struct elf_note_info *info)
 
 #endif
 
-static struct vm_area_struct *first_vma(struct task_struct *tsk,
-                                       struct vm_area_struct *gate_vma)
-{
-       struct vm_area_struct *ret = tsk->mm->mmap;
-
-       if (ret)
-               return ret;
-       return gate_vma;
-}
-/*
- * Helper function for iterating across a vma list.  It ensures that the caller
- * will visit `gate_vma' prior to terminating the search.
- */
-static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
-                                       struct vm_area_struct *gate_vma)
-{
-       struct vm_area_struct *ret;
-
-       ret = this_vma->vm_next;
-       if (ret)
-               return ret;
-       if (this_vma == gate_vma)
-               return NULL;
-       return gate_vma;
-}
-
 static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
                             elf_addr_t e_shoff, int segs)
 {
@@ -2297,9 +2154,8 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
 static int elf_core_dump(struct coredump_params *cprm)
 {
        int has_dumped = 0;
-       int segs, i;
-       size_t vma_data_size = 0;
-       struct vm_area_struct *vma, *gate_vma;
+       int vma_count, segs, i;
+       size_t vma_data_size;
        struct elfhdr elf;
        loff_t offset = 0, dataoff;
        struct elf_note_info info = { };
@@ -2307,30 +2163,16 @@ static int elf_core_dump(struct coredump_params *cprm)
        struct elf_shdr *shdr4extnum = NULL;
        Elf_Half e_phnum;
        elf_addr_t e_shoff;
-       elf_addr_t *vma_filesz = NULL;
+       struct core_vma_metadata *vma_meta;
+
+       if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
+               return 0;
 
-       /*
-        * We no longer stop all VM operations.
-        * 
-        * This is because those proceses that could possibly change map_count
-        * or the mmap / vma pages are now blocked in do_exit on current
-        * finishing this core dump.
-        *
-        * Only ptrace can touch these memory addresses, but it doesn't change
-        * the map_count or the pages allocated. So no possibility of crashing
-        * exists while dumping the mm->vm_next areas to the core file.
-        */
-  
        /*
         * The number of segs are recored into ELF header as 16bit value.
         * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
         */
-       segs = current->mm->map_count;
-       segs += elf_core_extra_phdrs();
-
-       gate_vma = get_gate_vma(current->mm);
-       if (gate_vma != NULL)
-               segs++;
+       segs = vma_count + elf_core_extra_phdrs();
 
        /* for notes section */
        segs++;
@@ -2368,24 +2210,6 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
-       /*
-        * 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 (!vma_filesz)
-               goto end_coredump;
-
-       for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
-                       vma = next_vma(vma, gate_vma)) {
-               unsigned long dump_size;
-
-               dump_size = vma_dump_size(vma, cprm->mm_flags);
-               vma_filesz[i++] = dump_size;
-               vma_data_size += dump_size;
-       }
-
        offset += vma_data_size;
        offset += elf_core_extra_data_size();
        e_shoff = offset;
@@ -2406,21 +2230,23 @@ static int elf_core_dump(struct coredump_params *cprm)
                goto end_coredump;
 
        /* Write program headers for segments dump */
-       for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
-                       vma = next_vma(vma, gate_vma)) {
+       for (i = 0; i < vma_count; i++) {
+               struct core_vma_metadata *meta = vma_meta + i;
                struct elf_phdr phdr;
 
                phdr.p_type = PT_LOAD;
                phdr.p_offset = offset;
-               phdr.p_vaddr = vma->vm_start;
+               phdr.p_vaddr = meta->start;
                phdr.p_paddr = 0;
-               phdr.p_filesz = vma_filesz[i++];
-               phdr.p_memsz = vma->vm_end - vma->vm_start;
+               phdr.p_filesz = meta->dump_size;
+               phdr.p_memsz = meta->end - meta->start;
                offset += phdr.p_filesz;
-               phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
-               if (vma->vm_flags & VM_WRITE)
+               phdr.p_flags = 0;
+               if (meta->flags & VM_READ)
+                       phdr.p_flags |= PF_R;
+               if (meta->flags & VM_WRITE)
                        phdr.p_flags |= PF_W;
-               if (vma->vm_flags & VM_EXEC)
+               if (meta->flags & VM_EXEC)
                        phdr.p_flags |= PF_X;
                phdr.p_align = ELF_EXEC_PAGESIZE;
 
@@ -2442,9 +2268,10 @@ static int elf_core_dump(struct coredump_params *cprm)
        if (!dump_skip(cprm, dataoff - cprm->pos))
                goto end_coredump;
 
-       for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
-                       vma = next_vma(vma, gate_vma)) {
-               if (!dump_user_range(cprm, vma->vm_start, vma_filesz[i++]))
+       for (i = 0; i < vma_count; i++) {
+               struct core_vma_metadata *meta = vma_meta + i;
+
+               if (!dump_user_range(cprm, meta->start, meta->dump_size))
                        goto end_coredump;
        }
        dump_truncate(cprm);
@@ -2460,7 +2287,7 @@ static int elf_core_dump(struct coredump_params *cprm)
 end_coredump:
        free_note_info(&info);
        kfree(shdr4extnum);
-       kvfree(vma_filesz);
+       kvfree(vma_meta);
        kfree(phdr4note);
        return has_dumped;
 }