coredump: Snapshot the vmas in do_coredump
[linux-block.git] / fs / coredump.c
index b73817712dd250659a8005f9e462e88767202803..88ac67994d03d4b1e780fe715096a4147aa79c29 100644 (file)
@@ -54,6 +54,8 @@
 
 #include <trace/events/sched.h>
 
+static bool dump_vma_snapshot(struct coredump_params *cprm);
+
 static int core_uses_pid;
 static unsigned int core_pipe_limit;
 static char core_pattern[CORENAME_MAX_SIZE] = "core";
@@ -532,6 +534,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
                 * by any locks.
                 */
                .mm_flags = mm->flags,
+               .vma_meta = NULL,
        };
 
        audit_core_dumps(siginfo->si_signo);
@@ -746,6 +749,9 @@ void do_coredump(const kernel_siginfo_t *siginfo)
                        pr_info("Core dump to |%s disabled\n", cn.corename);
                        goto close_fail;
                }
+               if (!dump_vma_snapshot(&cprm))
+                       goto close_fail;
+
                file_start_write(cprm.file);
                core_dumped = binfmt->core_dump(&cprm);
                /*
@@ -759,6 +765,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
                        dump_emit(&cprm, "", 1);
                }
                file_end_write(cprm.file);
+               kvfree(cprm.vma_meta);
        }
        if (ispipe && core_pipe_limit)
                wait_for_dump_helpers(cprm.file);
@@ -1096,14 +1103,11 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
  * Under the mmap_lock, take a snapshot of relevant information about the task's
  * VMAs.
  */
-int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
-                     struct core_vma_metadata **vma_meta,
-                     size_t *vma_data_size_ptr)
+static bool dump_vma_snapshot(struct coredump_params *cprm)
 {
        struct vm_area_struct *vma, *gate_vma;
        struct mm_struct *mm = current->mm;
        int i;
-       size_t vma_data_size = 0;
 
        /*
         * Once the stack expansion code is fixed to not change VMA bounds
@@ -1111,20 +1115,21 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
         * mmap_lock in read mode.
         */
        if (mmap_write_lock_killable(mm))
-               return -EINTR;
+               return false;
 
+       cprm->vma_data_size = 0;
        gate_vma = get_gate_vma(mm);
-       *vma_count = mm->map_count + (gate_vma ? 1 : 0);
+       cprm->vma_count = mm->map_count + (gate_vma ? 1 : 0);
 
-       *vma_meta = kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL);
-       if (!*vma_meta) {
+       cprm->vma_meta = kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta), GFP_KERNEL);
+       if (!cprm->vma_meta) {
                mmap_write_unlock(mm);
-               return -ENOMEM;
+               return false;
        }
 
        for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
                        vma = next_vma(vma, gate_vma), i++) {
-               struct core_vma_metadata *m = (*vma_meta) + i;
+               struct core_vma_metadata *m = cprm->vma_meta + i;
 
                m->start = vma->vm_start;
                m->end = vma->vm_end;
@@ -1134,13 +1139,14 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
 
        mmap_write_unlock(mm);
 
-       if (WARN_ON(i != *vma_count)) {
-               kvfree(*vma_meta);
-               return -EFAULT;
+       if (WARN_ON(i != cprm->vma_count)) {
+               kvfree(cprm->vma_meta);
+               return false;
        }
 
-       for (i = 0; i < *vma_count; i++) {
-               struct core_vma_metadata *m = (*vma_meta) + i;
+
+       for (i = 0; i < cprm->vma_count; i++) {
+               struct core_vma_metadata *m = cprm->vma_meta + i;
 
                if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) {
                        char elfmag[SELFMAG];
@@ -1153,9 +1159,8 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
                        }
                }
 
-               vma_data_size += m->dump_size;
+               cprm->vma_data_size += m->dump_size;
        }
 
-       *vma_data_size_ptr = vma_data_size;
-       return 0;
+       return true;
 }