mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
coredump: Snapshot the vmas in do_coredump
commit 95c5436a48
upstream.
Move the call of dump_vma_snapshot and kvfree(vma_meta) out of the
individual coredump routines into do_coredump itself. This makes
the code less error prone and easier to maintain.
Make the vma snapshot available to the coredump routines
in struct coredump_params. This makes it easier to
change and update what is captures in the vma snapshot
and will be needed for fixing fill_file_notes.
Reviewed-by: Jann Horn <jannh@google.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5318cdf4fd
commit
936c8be4d1
5 changed files with 39 additions and 46 deletions
|
@ -2166,8 +2166,7 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
|
||||||
static int elf_core_dump(struct coredump_params *cprm)
|
static int elf_core_dump(struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
int has_dumped = 0;
|
int has_dumped = 0;
|
||||||
int vma_count, segs, i;
|
int segs, i;
|
||||||
size_t vma_data_size;
|
|
||||||
struct elfhdr elf;
|
struct elfhdr elf;
|
||||||
loff_t offset = 0, dataoff;
|
loff_t offset = 0, dataoff;
|
||||||
struct elf_note_info info = { };
|
struct elf_note_info info = { };
|
||||||
|
@ -2175,16 +2174,12 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
struct elf_shdr *shdr4extnum = NULL;
|
struct elf_shdr *shdr4extnum = NULL;
|
||||||
Elf_Half e_phnum;
|
Elf_Half e_phnum;
|
||||||
elf_addr_t e_shoff;
|
elf_addr_t e_shoff;
|
||||||
struct core_vma_metadata *vma_meta;
|
|
||||||
|
|
||||||
if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The number of segs are recored into ELF header as 16bit value.
|
* The number of segs are recored into ELF header as 16bit value.
|
||||||
* Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
|
* Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
|
||||||
*/
|
*/
|
||||||
segs = vma_count + elf_core_extra_phdrs();
|
segs = cprm->vma_count + elf_core_extra_phdrs();
|
||||||
|
|
||||||
/* for notes section */
|
/* for notes section */
|
||||||
segs++;
|
segs++;
|
||||||
|
@ -2222,7 +2217,7 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
|
|
||||||
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
|
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
|
||||||
|
|
||||||
offset += vma_data_size;
|
offset += cprm->vma_data_size;
|
||||||
offset += elf_core_extra_data_size();
|
offset += elf_core_extra_data_size();
|
||||||
e_shoff = offset;
|
e_shoff = offset;
|
||||||
|
|
||||||
|
@ -2242,8 +2237,8 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
/* Write program headers for segments dump */
|
/* Write program headers for segments dump */
|
||||||
for (i = 0; i < vma_count; i++) {
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
struct core_vma_metadata *meta = vma_meta + i;
|
struct core_vma_metadata *meta = cprm->vma_meta + i;
|
||||||
struct elf_phdr phdr;
|
struct elf_phdr phdr;
|
||||||
|
|
||||||
phdr.p_type = PT_LOAD;
|
phdr.p_type = PT_LOAD;
|
||||||
|
@ -2280,8 +2275,8 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
if (!dump_skip(cprm, dataoff - cprm->pos))
|
if (!dump_skip(cprm, dataoff - cprm->pos))
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
for (i = 0; i < vma_count; i++) {
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
struct core_vma_metadata *meta = vma_meta + i;
|
struct core_vma_metadata *meta = cprm->vma_meta + i;
|
||||||
|
|
||||||
if (!dump_user_range(cprm, meta->start, meta->dump_size))
|
if (!dump_user_range(cprm, meta->start, meta->dump_size))
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
@ -2299,7 +2294,6 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
end_coredump:
|
end_coredump:
|
||||||
free_note_info(&info);
|
free_note_info(&info);
|
||||||
kfree(shdr4extnum);
|
kfree(shdr4extnum);
|
||||||
kvfree(vma_meta);
|
|
||||||
kfree(phdr4note);
|
kfree(phdr4note);
|
||||||
return has_dumped;
|
return has_dumped;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1479,7 +1479,7 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm,
|
||||||
static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
int has_dumped = 0;
|
int has_dumped = 0;
|
||||||
int vma_count, segs;
|
int segs;
|
||||||
int i;
|
int i;
|
||||||
struct elfhdr *elf = NULL;
|
struct elfhdr *elf = NULL;
|
||||||
loff_t offset = 0, dataoff;
|
loff_t offset = 0, dataoff;
|
||||||
|
@ -1494,8 +1494,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
elf_addr_t e_shoff;
|
elf_addr_t e_shoff;
|
||||||
struct core_thread *ct;
|
struct core_thread *ct;
|
||||||
struct elf_thread_status *tmp;
|
struct elf_thread_status *tmp;
|
||||||
struct core_vma_metadata *vma_meta = NULL;
|
|
||||||
size_t vma_data_size;
|
|
||||||
|
|
||||||
/* alloc memory for large data structures: too large to be on stack */
|
/* alloc memory for large data structures: too large to be on stack */
|
||||||
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
|
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
|
||||||
|
@ -1505,9 +1503,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
if (!psinfo)
|
if (!psinfo)
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size))
|
|
||||||
goto end_coredump;
|
|
||||||
|
|
||||||
for (ct = current->mm->core_state->dumper.next;
|
for (ct = current->mm->core_state->dumper.next;
|
||||||
ct; ct = ct->next) {
|
ct; ct = ct->next) {
|
||||||
tmp = elf_dump_thread_status(cprm->siginfo->si_signo,
|
tmp = elf_dump_thread_status(cprm->siginfo->si_signo,
|
||||||
|
@ -1527,7 +1522,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
tmp->next = thread_list;
|
tmp->next = thread_list;
|
||||||
thread_list = tmp;
|
thread_list = tmp;
|
||||||
|
|
||||||
segs = vma_count + elf_core_extra_phdrs();
|
segs = cprm->vma_count + elf_core_extra_phdrs();
|
||||||
|
|
||||||
/* for notes section */
|
/* for notes section */
|
||||||
segs++;
|
segs++;
|
||||||
|
@ -1572,7 +1567,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
/* Page-align dumped data */
|
/* Page-align dumped data */
|
||||||
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
|
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
|
||||||
|
|
||||||
offset += vma_data_size;
|
offset += cprm->vma_data_size;
|
||||||
offset += elf_core_extra_data_size();
|
offset += elf_core_extra_data_size();
|
||||||
e_shoff = offset;
|
e_shoff = offset;
|
||||||
|
|
||||||
|
@ -1592,8 +1587,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
/* write program headers for segments dump */
|
/* write program headers for segments dump */
|
||||||
for (i = 0; i < vma_count; i++) {
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
struct core_vma_metadata *meta = vma_meta + i;
|
struct core_vma_metadata *meta = cprm->vma_meta + i;
|
||||||
struct elf_phdr phdr;
|
struct elf_phdr phdr;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
||||||
|
@ -1643,7 +1638,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
if (!dump_skip(cprm, dataoff - cprm->pos))
|
if (!dump_skip(cprm, dataoff - cprm->pos))
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count))
|
if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count))
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
if (!elf_core_write_extra_data(cprm))
|
if (!elf_core_write_extra_data(cprm))
|
||||||
|
@ -1667,7 +1662,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
thread_list = thread_list->next;
|
thread_list = thread_list->next;
|
||||||
kfree(tmp);
|
kfree(tmp);
|
||||||
}
|
}
|
||||||
kvfree(vma_meta);
|
|
||||||
kfree(phdr4note);
|
kfree(phdr4note);
|
||||||
kfree(elf);
|
kfree(elf);
|
||||||
kfree(psinfo);
|
kfree(psinfo);
|
||||||
|
|
|
@ -53,6 +53,8 @@
|
||||||
|
|
||||||
#include <trace/events/sched.h>
|
#include <trace/events/sched.h>
|
||||||
|
|
||||||
|
static bool dump_vma_snapshot(struct coredump_params *cprm);
|
||||||
|
|
||||||
int core_uses_pid;
|
int core_uses_pid;
|
||||||
unsigned int core_pipe_limit;
|
unsigned int core_pipe_limit;
|
||||||
char core_pattern[CORENAME_MAX_SIZE] = "core";
|
char core_pattern[CORENAME_MAX_SIZE] = "core";
|
||||||
|
@ -602,6 +604,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
||||||
* by any locks.
|
* by any locks.
|
||||||
*/
|
*/
|
||||||
.mm_flags = mm->flags,
|
.mm_flags = mm->flags,
|
||||||
|
.vma_meta = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
audit_core_dumps(siginfo->si_signo);
|
audit_core_dumps(siginfo->si_signo);
|
||||||
|
@ -807,9 +810,13 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
||||||
pr_info("Core dump to |%s disabled\n", cn.corename);
|
pr_info("Core dump to |%s disabled\n", cn.corename);
|
||||||
goto close_fail;
|
goto close_fail;
|
||||||
}
|
}
|
||||||
|
if (!dump_vma_snapshot(&cprm))
|
||||||
|
goto close_fail;
|
||||||
|
|
||||||
file_start_write(cprm.file);
|
file_start_write(cprm.file);
|
||||||
core_dumped = binfmt->core_dump(&cprm);
|
core_dumped = binfmt->core_dump(&cprm);
|
||||||
file_end_write(cprm.file);
|
file_end_write(cprm.file);
|
||||||
|
kvfree(cprm.vma_meta);
|
||||||
}
|
}
|
||||||
if (ispipe && core_pipe_limit)
|
if (ispipe && core_pipe_limit)
|
||||||
wait_for_dump_helpers(cprm.file);
|
wait_for_dump_helpers(cprm.file);
|
||||||
|
@ -1085,14 +1092,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
|
* Under the mmap_lock, take a snapshot of relevant information about the task's
|
||||||
* VMAs.
|
* VMAs.
|
||||||
*/
|
*/
|
||||||
int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
|
static bool dump_vma_snapshot(struct coredump_params *cprm)
|
||||||
struct core_vma_metadata **vma_meta,
|
|
||||||
size_t *vma_data_size_ptr)
|
|
||||||
{
|
{
|
||||||
struct vm_area_struct *vma, *gate_vma;
|
struct vm_area_struct *vma, *gate_vma;
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
int i;
|
int i;
|
||||||
size_t vma_data_size = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Once the stack expansion code is fixed to not change VMA bounds
|
* Once the stack expansion code is fixed to not change VMA bounds
|
||||||
|
@ -1100,20 +1104,21 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
|
||||||
* mmap_lock in read mode.
|
* mmap_lock in read mode.
|
||||||
*/
|
*/
|
||||||
if (mmap_write_lock_killable(mm))
|
if (mmap_write_lock_killable(mm))
|
||||||
return -EINTR;
|
return false;
|
||||||
|
|
||||||
|
cprm->vma_data_size = 0;
|
||||||
gate_vma = get_gate_vma(mm);
|
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);
|
cprm->vma_meta = kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta), GFP_KERNEL);
|
||||||
if (!*vma_meta) {
|
if (!cprm->vma_meta) {
|
||||||
mmap_write_unlock(mm);
|
mmap_write_unlock(mm);
|
||||||
return -ENOMEM;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
|
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
|
||||||
vma = next_vma(vma, gate_vma), i++) {
|
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->start = vma->vm_start;
|
||||||
m->end = vma->vm_end;
|
m->end = vma->vm_end;
|
||||||
|
@ -1123,13 +1128,14 @@ int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
|
||||||
|
|
||||||
mmap_write_unlock(mm);
|
mmap_write_unlock(mm);
|
||||||
|
|
||||||
if (WARN_ON(i != *vma_count)) {
|
if (WARN_ON(i != cprm->vma_count)) {
|
||||||
kvfree(*vma_meta);
|
kvfree(cprm->vma_meta);
|
||||||
return -EFAULT;
|
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) {
|
if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) {
|
||||||
char elfmag[SELFMAG];
|
char elfmag[SELFMAG];
|
||||||
|
@ -1142,9 +1148,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 true;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,9 @@ struct coredump_params {
|
||||||
unsigned long mm_flags;
|
unsigned long mm_flags;
|
||||||
loff_t written;
|
loff_t written;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
|
int vma_count;
|
||||||
|
size_t vma_data_size;
|
||||||
|
struct core_vma_metadata *vma_meta;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -24,9 +24,6 @@ extern int dump_align(struct coredump_params *cprm, int align);
|
||||||
extern void dump_truncate(struct coredump_params *cprm);
|
extern void dump_truncate(struct coredump_params *cprm);
|
||||||
int dump_user_range(struct coredump_params *cprm, unsigned long start,
|
int dump_user_range(struct coredump_params *cprm, unsigned long start,
|
||||||
unsigned long len);
|
unsigned long len);
|
||||||
int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count,
|
|
||||||
struct core_vma_metadata **vma_meta,
|
|
||||||
size_t *vma_data_size_ptr);
|
|
||||||
#ifdef CONFIG_COREDUMP
|
#ifdef CONFIG_COREDUMP
|
||||||
extern void do_coredump(const kernel_siginfo_t *siginfo);
|
extern void do_coredump(const kernel_siginfo_t *siginfo);
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in a new issue