Skip to content

Commit 84158b7

Browse files
thejhkees
authored andcommitted
coredump: Also dump first pages of non-executable ELF libraries
When I rewrote the VMA dumping logic for coredumps, I changed it to recognize ELF library mappings based on the file being executable instead of the mapping having an ELF header. But turns out, distros ship many ELF libraries as non-executable, so the heuristic goes wrong... Restore the old behavior where FILTER(ELF_HEADERS) dumps the first page of any offset-0 readable mapping that starts with the ELF magic. This fix is technically layer-breaking a bit, because it checks for something ELF-specific in fs/coredump.c; but since we probably want to share this between standard ELF and FDPIC ELF anyway, I guess it's fine? And this also keeps the change small for backporting. Cc: [email protected] Fixes: 429a22e ("coredump: rework elf/elf_fdpic vma_dump_size() into common helper") Reported-by: Bill Messmer <[email protected]> Signed-off-by: Jann Horn <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 10b1924 commit 84158b7

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

fs/coredump.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/path.h>
4343
#include <linux/timekeeping.h>
4444
#include <linux/sysctl.h>
45+
#include <linux/elf.h>
4546

4647
#include <linux/uaccess.h>
4748
#include <asm/mmu_context.h>
@@ -980,6 +981,8 @@ static bool always_dump_vma(struct vm_area_struct *vma)
980981
return false;
981982
}
982983

984+
#define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1
985+
983986
/*
984987
* Decide how much of @vma's contents should be included in a core dump.
985988
*/
@@ -1039,9 +1042,20 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
10391042
* dump the first page to aid in determining what was mapped here.
10401043
*/
10411044
if (FILTER(ELF_HEADERS) &&
1042-
vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ) &&
1043-
(READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0)
1044-
return PAGE_SIZE;
1045+
vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
1046+
if ((READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0)
1047+
return PAGE_SIZE;
1048+
1049+
/*
1050+
* ELF libraries aren't always executable.
1051+
* We'll want to check whether the mapping starts with the ELF
1052+
* magic, but not now - we're holding the mmap lock,
1053+
* so copy_from_user() doesn't work here.
1054+
* Use a placeholder instead, and fix it up later in
1055+
* dump_vma_snapshot().
1056+
*/
1057+
return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER;
1058+
}
10451059

10461060
#undef FILTER
10471061

@@ -1116,8 +1130,6 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
11161130
m->end = vma->vm_end;
11171131
m->flags = vma->vm_flags;
11181132
m->dump_size = vma_dump_size(vma, cprm->mm_flags);
1119-
1120-
vma_data_size += m->dump_size;
11211133
}
11221134

11231135
mmap_write_unlock(mm);
@@ -1127,6 +1139,23 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
11271139
return -EFAULT;
11281140
}
11291141

1142+
for (i = 0; i < *vma_count; i++) {
1143+
struct core_vma_metadata *m = (*vma_meta) + i;
1144+
1145+
if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) {
1146+
char elfmag[SELFMAG];
1147+
1148+
if (copy_from_user(elfmag, (void __user *)m->start, SELFMAG) ||
1149+
memcmp(elfmag, ELFMAG, SELFMAG) != 0) {
1150+
m->dump_size = 0;
1151+
} else {
1152+
m->dump_size = PAGE_SIZE;
1153+
}
1154+
}
1155+
1156+
vma_data_size += m->dump_size;
1157+
}
1158+
11301159
*vma_data_size_ptr = vma_data_size;
11311160
return 0;
11321161
}

0 commit comments

Comments
 (0)