aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJungseung Lee <js07.lee@gmail.com>2014-12-10 18:52:16 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-10 20:41:12 -0500
commit52f5592e549c013feb9bb71cab3e6fd624633577 (patch)
tree55bdcdd7e82121f8c8e071562917ce9dbc964efe
parentf7e1ad1a1e23af97419cd8d5adff67fedf7cf169 (diff)
fs/binfmt_elf.c: fix internal inconsistency relating to vma dump size
vma_dump_size() has been used several times on actual dumper and it is supposed to return the same value for the same vma. But vma_dump_size() could return different values for same vma. The known problem case is concurrent shared memory removal. If a vma is used for a shared memory and that shared memory is removed between writing program header and dumping vma memory, this will result in a dump file which is internally consistent. To fix the problem, we set baseline to get dump size and store the size into vma_filesz and always use the same vma dump size which is stored in vma_filsz. The consistnecy with reality is not actually guranteed, but it's tolerable since that is fully consistent with base line. Signed-off-by: Jungseung Lee <js07.lee@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/binfmt_elf.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index d8fc0605b9d2..3a6175fe10c0 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1994,18 +1994,6 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
1994 shdr4extnum->sh_info = segs; 1994 shdr4extnum->sh_info = segs;
1995} 1995}
1996 1996
1997static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma,
1998 unsigned long mm_flags)
1999{
2000 struct vm_area_struct *vma;
2001 size_t size = 0;
2002
2003 for (vma = first_vma(current, gate_vma); vma != NULL;
2004 vma = next_vma(vma, gate_vma))
2005 size += vma_dump_size(vma, mm_flags);
2006 return size;
2007}
2008
2009/* 1997/*
2010 * Actual dumper 1998 * Actual dumper
2011 * 1999 *
@@ -2017,7 +2005,8 @@ static int elf_core_dump(struct coredump_params *cprm)
2017{ 2005{
2018 int has_dumped = 0; 2006 int has_dumped = 0;
2019 mm_segment_t fs; 2007 mm_segment_t fs;
2020 int segs; 2008 int segs, i;
2009 size_t vma_data_size = 0;
2021 struct vm_area_struct *vma, *gate_vma; 2010 struct vm_area_struct *vma, *gate_vma;
2022 struct elfhdr *elf = NULL; 2011 struct elfhdr *elf = NULL;
2023 loff_t offset = 0, dataoff; 2012 loff_t offset = 0, dataoff;
@@ -2026,6 +2015,7 @@ static int elf_core_dump(struct coredump_params *cprm)
2026 struct elf_shdr *shdr4extnum = NULL; 2015 struct elf_shdr *shdr4extnum = NULL;
2027 Elf_Half e_phnum; 2016 Elf_Half e_phnum;
2028 elf_addr_t e_shoff; 2017 elf_addr_t e_shoff;
2018 elf_addr_t *vma_filesz = NULL;
2029 2019
2030 /* 2020 /*
2031 * We no longer stop all VM operations. 2021 * We no longer stop all VM operations.
@@ -2093,7 +2083,20 @@ static int elf_core_dump(struct coredump_params *cprm)
2093 2083
2094 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); 2084 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
2095 2085
2096 offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags); 2086 vma_filesz = kmalloc_array(segs - 1, sizeof(*vma_filesz), GFP_KERNEL);
2087 if (!vma_filesz)
2088 goto end_coredump;
2089
2090 for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
2091 vma = next_vma(vma, gate_vma)) {
2092 unsigned long dump_size;
2093
2094 dump_size = vma_dump_size(vma, cprm->mm_flags);
2095 vma_filesz[i++] = dump_size;
2096 vma_data_size += dump_size;
2097 }
2098
2099 offset += vma_data_size;
2097 offset += elf_core_extra_data_size(); 2100 offset += elf_core_extra_data_size();
2098 e_shoff = offset; 2101 e_shoff = offset;
2099 2102
@@ -2113,7 +2116,7 @@ static int elf_core_dump(struct coredump_params *cprm)
2113 goto end_coredump; 2116 goto end_coredump;
2114 2117
2115 /* Write program headers for segments dump */ 2118 /* Write program headers for segments dump */
2116 for (vma = first_vma(current, gate_vma); vma != NULL; 2119 for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
2117 vma = next_vma(vma, gate_vma)) { 2120 vma = next_vma(vma, gate_vma)) {
2118 struct elf_phdr phdr; 2121 struct elf_phdr phdr;
2119 2122
@@ -2121,7 +2124,7 @@ static int elf_core_dump(struct coredump_params *cprm)
2121 phdr.p_offset = offset; 2124 phdr.p_offset = offset;
2122 phdr.p_vaddr = vma->vm_start; 2125 phdr.p_vaddr = vma->vm_start;
2123 phdr.p_paddr = 0; 2126 phdr.p_paddr = 0;
2124 phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags); 2127 phdr.p_filesz = vma_filesz[i++];
2125 phdr.p_memsz = vma->vm_end - vma->vm_start; 2128 phdr.p_memsz = vma->vm_end - vma->vm_start;
2126 offset += phdr.p_filesz; 2129 offset += phdr.p_filesz;
2127 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; 2130 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -2149,12 +2152,12 @@ static int elf_core_dump(struct coredump_params *cprm)
2149 if (!dump_skip(cprm, dataoff - cprm->written)) 2152 if (!dump_skip(cprm, dataoff - cprm->written))
2150 goto end_coredump; 2153 goto end_coredump;
2151 2154
2152 for (vma = first_vma(current, gate_vma); vma != NULL; 2155 for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
2153 vma = next_vma(vma, gate_vma)) { 2156 vma = next_vma(vma, gate_vma)) {
2154 unsigned long addr; 2157 unsigned long addr;
2155 unsigned long end; 2158 unsigned long end;
2156 2159
2157 end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags); 2160 end = vma->vm_start + vma_filesz[i++];
2158 2161
2159 for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { 2162 for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
2160 struct page *page; 2163 struct page *page;
@@ -2187,6 +2190,7 @@ end_coredump:
2187cleanup: 2190cleanup:
2188 free_note_info(&info); 2191 free_note_info(&info);
2189 kfree(shdr4extnum); 2192 kfree(shdr4extnum);
2193 kfree(vma_filesz);
2190 kfree(phdr4note); 2194 kfree(phdr4note);
2191 kfree(elf); 2195 kfree(elf);
2192out: 2196out: