coredump: refactor page range dumping into common helper
authorJann Horn <jannh@google.com>
Fri, 16 Oct 2020 03:12:46 +0000 (20:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Oct 2020 18:11:21 +0000 (11:11 -0700)
Both fs/binfmt_elf.c and fs/binfmt_elf_fdpic.c need to dump ranges of
pages into the coredump file.  Extract that logic into a common helper.

Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: "Eric W . Biederman" <ebiederm@xmission.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Link: http://lkml.kernel.org/r/20200827114932.3572699-4-jannh@google.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/coredump.c
include/linux/coredump.h

index 96370e3e368720484720c1d8bd38d740c8c04400..cf956edf05eff409380e9eaa4311c4685aee5ce8 100644 (file)
@@ -2444,26 +2444,8 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
                        vma = next_vma(vma, gate_vma)) {
-               unsigned long addr;
-               unsigned long end;
-
-               end = vma->vm_start + vma_filesz[i++];
-
-               for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
-                       struct page *page;
-                       int stop;
-
-                       page = get_dump_page(addr);
-                       if (page) {
-                               void *kaddr = kmap(page);
-                               stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
-                               kunmap(page);
-                               put_page(page);
-                       } else
-                               stop = !dump_skip(cprm, PAGE_SIZE);
-                       if (stop)
-                               goto end_coredump;
-               }
+               if (!dump_user_range(cprm, vma->vm_start, vma_filesz[i++]))
+                       goto end_coredump;
        }
        dump_truncate(cprm);
 
index a53f83830986ab1a43cfaa0b7d3c9a06604dd989..76e8c0defdc85a28f7c28b691d63f49f3e6d6e41 100644 (file)
@@ -1534,21 +1534,9 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm)
                if (!maydump(vma, cprm->mm_flags))
                        continue;
 
-               for (addr = vma->vm_start; addr < vma->vm_end;
-                                                       addr += PAGE_SIZE) {
-                       bool res;
-                       struct page *page = get_dump_page(addr);
-                       if (page) {
-                               void *kaddr = kmap(page);
-                               res = dump_emit(cprm, kaddr, PAGE_SIZE);
-                               kunmap(page);
-                               put_page(page);
-                       } else {
-                               res = dump_skip(cprm, PAGE_SIZE);
-                       }
-                       if (!res)
-                               return false;
-               }
+               if (!dump_user_range(cprm, vma->vm_start,
+                                    vma->vma_end - vma->vm_start))
+                       return false;
        }
        return true;
 }
index 5e24c06092c984de6ca044d5217111297e2c70a6..6042d15acd51f682e8f3e9148e3cbcd969489723 100644 (file)
@@ -876,6 +876,40 @@ int dump_skip(struct coredump_params *cprm, size_t nr)
 }
 EXPORT_SYMBOL(dump_skip);
 
+#ifdef CONFIG_ELF_CORE
+int dump_user_range(struct coredump_params *cprm, unsigned long start,
+                   unsigned long len)
+{
+       unsigned long addr;
+
+       for (addr = start; addr < start + len; addr += PAGE_SIZE) {
+               struct page *page;
+               int stop;
+
+               /*
+                * To avoid having to allocate page tables for virtual address
+                * ranges that have never been used yet, and also to make it
+                * easy to generate sparse core files, use a helper that returns
+                * NULL when encountering an empty page table entry that would
+                * otherwise have been filled with the zero page.
+                */
+               page = get_dump_page(addr);
+               if (page) {
+                       void *kaddr = kmap(page);
+
+                       stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
+                       kunmap(page);
+                       put_page(page);
+               } else {
+                       stop = !dump_skip(cprm, PAGE_SIZE);
+               }
+               if (stop)
+                       return 0;
+       }
+       return 1;
+}
+#endif
+
 int dump_align(struct coredump_params *cprm, int align)
 {
        unsigned mod = cprm->pos & (align - 1);
index 7a899e83835d5dcf7ea5cbbf2ba3ebe7e4366a5f..f0b71a74d0bccf11d43e6bdb3a26d1c8daba994c 100644 (file)
@@ -16,6 +16,8 @@ extern int dump_skip(struct coredump_params *cprm, size_t nr);
 extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
 extern int dump_align(struct coredump_params *cprm, int align);
 extern void dump_truncate(struct coredump_params *cprm);
+int dump_user_range(struct coredump_params *cprm, unsigned long start,
+                   unsigned long len);
 #ifdef CONFIG_COREDUMP
 extern void do_coredump(const kernel_siginfo_t *siginfo);
 #else