Merge branch 'coredump-vma-snapshot-fix-for-v5.18' of https://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace into for-next/execve
- Fix missing mmap_lock in file_files_note (Eric W. Biederman)
This commit is contained in:
commit
2722ae9c94
6 changed files with 97 additions and 84 deletions
|
@ -1641,17 +1641,16 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
|
||||||
* long file_ofs
|
* long file_ofs
|
||||||
* followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
|
* followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
|
||||||
*/
|
*/
|
||||||
static int fill_files_note(struct memelfnote *note)
|
static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
struct mm_struct *mm = current->mm;
|
|
||||||
struct vm_area_struct *vma;
|
|
||||||
unsigned count, size, names_ofs, remaining, n;
|
unsigned count, size, names_ofs, remaining, n;
|
||||||
user_long_t *data;
|
user_long_t *data;
|
||||||
user_long_t *start_end_ofs;
|
user_long_t *start_end_ofs;
|
||||||
char *name_base, *name_curpos;
|
char *name_base, *name_curpos;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* *Estimated* file count and total data size needed */
|
/* *Estimated* file count and total data size needed */
|
||||||
count = mm->map_count;
|
count = cprm->vma_count;
|
||||||
if (count > UINT_MAX / 64)
|
if (count > UINT_MAX / 64)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
size = count * 64;
|
size = count * 64;
|
||||||
|
@ -1673,11 +1672,12 @@ static int fill_files_note(struct memelfnote *note)
|
||||||
name_base = name_curpos = ((char *)data) + names_ofs;
|
name_base = name_curpos = ((char *)data) + names_ofs;
|
||||||
remaining = size - names_ofs;
|
remaining = size - names_ofs;
|
||||||
count = 0;
|
count = 0;
|
||||||
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
|
struct core_vma_metadata *m = &cprm->vma_meta[i];
|
||||||
struct file *file;
|
struct file *file;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
|
||||||
file = vma->vm_file;
|
file = m->file;
|
||||||
if (!file)
|
if (!file)
|
||||||
continue;
|
continue;
|
||||||
filename = file_path(file, name_curpos, remaining);
|
filename = file_path(file, name_curpos, remaining);
|
||||||
|
@ -1697,9 +1697,9 @@ static int fill_files_note(struct memelfnote *note)
|
||||||
memmove(name_curpos, filename, n);
|
memmove(name_curpos, filename, n);
|
||||||
name_curpos += n;
|
name_curpos += n;
|
||||||
|
|
||||||
*start_end_ofs++ = vma->vm_start;
|
*start_end_ofs++ = m->start;
|
||||||
*start_end_ofs++ = vma->vm_end;
|
*start_end_ofs++ = m->end;
|
||||||
*start_end_ofs++ = vma->vm_pgoff;
|
*start_end_ofs++ = m->pgoff;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1710,7 +1710,7 @@ static int fill_files_note(struct memelfnote *note)
|
||||||
* Count usually is less than mm->map_count,
|
* Count usually is less than mm->map_count,
|
||||||
* we need to move filenames down.
|
* we need to move filenames down.
|
||||||
*/
|
*/
|
||||||
n = mm->map_count - count;
|
n = cprm->vma_count - count;
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
unsigned shift_bytes = n * 3 * sizeof(data[0]);
|
unsigned shift_bytes = n * 3 * sizeof(data[0]);
|
||||||
memmove(name_base - shift_bytes, name_base,
|
memmove(name_base - shift_bytes, name_base,
|
||||||
|
@ -1822,7 +1822,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
|
||||||
|
|
||||||
static int fill_note_info(struct elfhdr *elf, int phdrs,
|
static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
struct elf_note_info *info,
|
struct elf_note_info *info,
|
||||||
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
|
struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
struct task_struct *dump_task = current;
|
struct task_struct *dump_task = current;
|
||||||
const struct user_regset_view *view = task_user_regset_view(dump_task);
|
const struct user_regset_view *view = task_user_regset_view(dump_task);
|
||||||
|
@ -1894,7 +1894,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
* Now fill in each thread's information.
|
* Now fill in each thread's information.
|
||||||
*/
|
*/
|
||||||
for (t = info->thread; t != NULL; t = t->next)
|
for (t = info->thread; t != NULL; t = t->next)
|
||||||
if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size))
|
if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1903,13 +1903,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
|
fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
|
||||||
info->size += notesize(&info->psinfo);
|
info->size += notesize(&info->psinfo);
|
||||||
|
|
||||||
fill_siginfo_note(&info->signote, &info->csigdata, siginfo);
|
fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo);
|
||||||
info->size += notesize(&info->signote);
|
info->size += notesize(&info->signote);
|
||||||
|
|
||||||
fill_auxv_note(&info->auxv, current->mm);
|
fill_auxv_note(&info->auxv, current->mm);
|
||||||
info->size += notesize(&info->auxv);
|
info->size += notesize(&info->auxv);
|
||||||
|
|
||||||
if (fill_files_note(&info->files) == 0)
|
if (fill_files_note(&info->files, cprm) == 0)
|
||||||
info->size += notesize(&info->files);
|
info->size += notesize(&info->files);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2051,7 +2051,7 @@ static int elf_note_info_init(struct elf_note_info *info)
|
||||||
|
|
||||||
static int fill_note_info(struct elfhdr *elf, int phdrs,
|
static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
struct elf_note_info *info,
|
struct elf_note_info *info,
|
||||||
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
|
struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
struct core_thread *ct;
|
struct core_thread *ct;
|
||||||
struct elf_thread_status *ets;
|
struct elf_thread_status *ets;
|
||||||
|
@ -2072,13 +2072,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
list_for_each_entry(ets, &info->thread_list, list) {
|
list_for_each_entry(ets, &info->thread_list, list) {
|
||||||
int sz;
|
int sz;
|
||||||
|
|
||||||
sz = elf_dump_thread_status(siginfo->si_signo, ets);
|
sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets);
|
||||||
info->thread_status_size += sz;
|
info->thread_status_size += sz;
|
||||||
}
|
}
|
||||||
/* now collect the dump for the current */
|
/* now collect the dump for the current */
|
||||||
memset(info->prstatus, 0, sizeof(*info->prstatus));
|
memset(info->prstatus, 0, sizeof(*info->prstatus));
|
||||||
fill_prstatus(&info->prstatus->common, current, siginfo->si_signo);
|
fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
|
||||||
elf_core_copy_regs(&info->prstatus->pr_reg, regs);
|
elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs);
|
||||||
|
|
||||||
/* Set up header */
|
/* Set up header */
|
||||||
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
|
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
|
||||||
|
@ -2094,18 +2094,18 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
|
||||||
fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
|
fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
|
||||||
sizeof(*info->psinfo), info->psinfo);
|
sizeof(*info->psinfo), info->psinfo);
|
||||||
|
|
||||||
fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo);
|
fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo);
|
||||||
fill_auxv_note(info->notes + 3, current->mm);
|
fill_auxv_note(info->notes + 3, current->mm);
|
||||||
info->numnote = 4;
|
info->numnote = 4;
|
||||||
|
|
||||||
if (fill_files_note(info->notes + info->numnote) == 0) {
|
if (fill_files_note(info->notes + info->numnote, cprm) == 0) {
|
||||||
info->notes_files = info->notes + info->numnote;
|
info->notes_files = info->notes + info->numnote;
|
||||||
info->numnote++;
|
info->numnote++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to dump the FPU. */
|
/* Try to dump the FPU. */
|
||||||
info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
|
info->prstatus->pr_fpvalid =
|
||||||
info->fpu);
|
elf_core_copy_task_fpregs(current, cprm->regs, info->fpu);
|
||||||
if (info->prstatus->pr_fpvalid)
|
if (info->prstatus->pr_fpvalid)
|
||||||
fill_note(info->notes + info->numnote++,
|
fill_note(info->notes + info->numnote++,
|
||||||
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
|
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
|
||||||
|
@ -2191,8 +2191,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 = { };
|
||||||
|
@ -2200,16 +2199,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++;
|
||||||
|
@ -2223,7 +2218,7 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
* Collect all the non-memory information about the process for the
|
* Collect all the non-memory information about the process for the
|
||||||
* notes. This also sets up the file header.
|
* notes. This also sets up the file header.
|
||||||
*/
|
*/
|
||||||
if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs))
|
if (!fill_note_info(&elf, e_phnum, &info, cprm))
|
||||||
goto end_coredump;
|
goto end_coredump;
|
||||||
|
|
||||||
has_dumped = 1;
|
has_dumped = 1;
|
||||||
|
@ -2248,7 +2243,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;
|
||||||
|
|
||||||
|
@ -2268,8 +2263,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;
|
||||||
|
@ -2306,8 +2301,8 @@ static int elf_core_dump(struct coredump_params *cprm)
|
||||||
/* Align to page */
|
/* Align to page */
|
||||||
dump_skip_to(cprm, dataoff);
|
dump_skip_to(cprm, dataoff);
|
||||||
|
|
||||||
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;
|
||||||
|
@ -2324,7 +2319,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1465,7 +1465,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;
|
||||||
|
@ -1480,8 +1480,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);
|
||||||
|
@ -1491,9 +1489,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->signal->core_state->dumper.next;
|
for (ct = current->signal->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,
|
||||||
|
@ -1513,7 +1508,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++;
|
||||||
|
@ -1558,7 +1553,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;
|
||||||
|
|
||||||
|
@ -1578,8 +1573,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;
|
||||||
|
|
||||||
|
@ -1628,7 +1623,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
|
||||||
|
|
||||||
dump_skip_to(cprm, dataoff);
|
dump_skip_to(cprm, dataoff);
|
||||||
|
|
||||||
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))
|
||||||
|
@ -1652,7 +1647,6 @@ end_coredump:
|
||||||
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);
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <linux/flat.h>
|
#include <linux/flat.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/coredump.h>
|
||||||
|
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
@ -97,7 +98,9 @@ static int load_flat_shared_library(int id, struct lib_info *p);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int load_flat_binary(struct linux_binprm *);
|
static int load_flat_binary(struct linux_binprm *);
|
||||||
|
#ifdef CONFIG_COREDUMP
|
||||||
static int flat_core_dump(struct coredump_params *cprm);
|
static int flat_core_dump(struct coredump_params *cprm);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct linux_binfmt flat_format = {
|
static struct linux_binfmt flat_format = {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
|
@ -114,12 +117,14 @@ static struct linux_binfmt flat_format = {
|
||||||
* Currently only a stub-function.
|
* Currently only a stub-function.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_COREDUMP
|
||||||
static int flat_core_dump(struct coredump_params *cprm)
|
static int flat_core_dump(struct coredump_params *cprm)
|
||||||
{
|
{
|
||||||
pr_warn("Process %s:%d received signr %d and should have core dumped\n",
|
pr_warn("Process %s:%d received signr %d and should have core dumped\n",
|
||||||
current->comm, current->pid, cprm->siginfo->si_signo);
|
current->comm, current->pid, cprm->siginfo->si_signo);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -54,6 +54,9 @@
|
||||||
|
|
||||||
#include <trace/events/sched.h>
|
#include <trace/events/sched.h>
|
||||||
|
|
||||||
|
static bool dump_vma_snapshot(struct coredump_params *cprm);
|
||||||
|
static void free_vma_snapshot(struct coredump_params *cprm);
|
||||||
|
|
||||||
static int core_uses_pid;
|
static int core_uses_pid;
|
||||||
static unsigned int core_pipe_limit;
|
static unsigned int core_pipe_limit;
|
||||||
static char core_pattern[CORENAME_MAX_SIZE] = "core";
|
static char core_pattern[CORENAME_MAX_SIZE] = "core";
|
||||||
|
@ -532,6 +535,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);
|
||||||
|
@ -746,6 +750,9 @@ 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);
|
||||||
/*
|
/*
|
||||||
|
@ -759,6 +766,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
||||||
dump_emit(&cprm, "", 1);
|
dump_emit(&cprm, "", 1);
|
||||||
}
|
}
|
||||||
file_end_write(cprm.file);
|
file_end_write(cprm.file);
|
||||||
|
free_vma_snapshot(&cprm);
|
||||||
}
|
}
|
||||||
if (ispipe && core_pipe_limit)
|
if (ispipe && core_pipe_limit)
|
||||||
wait_for_dump_helpers(cprm.file);
|
wait_for_dump_helpers(cprm.file);
|
||||||
|
@ -1092,18 +1100,29 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
|
||||||
return gate_vma;
|
return gate_vma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_vma_snapshot(struct coredump_params *cprm)
|
||||||
|
{
|
||||||
|
if (cprm->vma_meta) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
|
struct file *file = cprm->vma_meta[i].file;
|
||||||
|
if (file)
|
||||||
|
fput(file);
|
||||||
|
}
|
||||||
|
kvfree(cprm->vma_meta);
|
||||||
|
cprm->vma_meta = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
|
@ -1111,36 +1130,37 @@ 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;
|
||||||
m->flags = vma->vm_flags;
|
m->flags = vma->vm_flags;
|
||||||
m->dump_size = vma_dump_size(vma, cprm->mm_flags);
|
m->dump_size = vma_dump_size(vma, cprm->mm_flags);
|
||||||
|
m->pgoff = vma->vm_pgoff;
|
||||||
|
|
||||||
|
m->file = vma->vm_file;
|
||||||
|
if (m->file)
|
||||||
|
get_file(m->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
mmap_write_unlock(mm);
|
mmap_write_unlock(mm);
|
||||||
|
|
||||||
if (WARN_ON(i != *vma_count)) {
|
for (i = 0; i < cprm->vma_count; i++) {
|
||||||
kvfree(*vma_meta);
|
struct core_vma_metadata *m = cprm->vma_meta + i;
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < *vma_count; i++) {
|
|
||||||
struct core_vma_metadata *m = (*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];
|
||||||
|
@ -1153,9 +1173,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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <uapi/linux/binfmts.h>
|
#include <uapi/linux/binfmts.h>
|
||||||
|
|
||||||
struct filename;
|
struct filename;
|
||||||
|
struct coredump_params;
|
||||||
|
|
||||||
#define CORENAME_MAX_SIZE 128
|
#define CORENAME_MAX_SIZE 128
|
||||||
|
|
||||||
|
@ -77,18 +78,6 @@ struct linux_binprm {
|
||||||
#define BINPRM_FLAGS_PRESERVE_ARGV0_BIT 3
|
#define BINPRM_FLAGS_PRESERVE_ARGV0_BIT 3
|
||||||
#define BINPRM_FLAGS_PRESERVE_ARGV0 (1 << BINPRM_FLAGS_PRESERVE_ARGV0_BIT)
|
#define BINPRM_FLAGS_PRESERVE_ARGV0 (1 << BINPRM_FLAGS_PRESERVE_ARGV0_BIT)
|
||||||
|
|
||||||
/* Function parameter for binfmt->coredump */
|
|
||||||
struct coredump_params {
|
|
||||||
const kernel_siginfo_t *siginfo;
|
|
||||||
struct pt_regs *regs;
|
|
||||||
struct file *file;
|
|
||||||
unsigned long limit;
|
|
||||||
unsigned long mm_flags;
|
|
||||||
loff_t written;
|
|
||||||
loff_t pos;
|
|
||||||
loff_t to_skip;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This structure defines the functions that are used to load the binary formats that
|
* This structure defines the functions that are used to load the binary formats that
|
||||||
* linux accepts.
|
* linux accepts.
|
||||||
|
|
|
@ -12,22 +12,34 @@ struct core_vma_metadata {
|
||||||
unsigned long start, end;
|
unsigned long start, end;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long dump_size;
|
unsigned long dump_size;
|
||||||
|
unsigned long pgoff;
|
||||||
|
struct file *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct coredump_params {
|
||||||
|
const kernel_siginfo_t *siginfo;
|
||||||
|
struct pt_regs *regs;
|
||||||
|
struct file *file;
|
||||||
|
unsigned long limit;
|
||||||
|
unsigned long mm_flags;
|
||||||
|
loff_t written;
|
||||||
|
loff_t pos;
|
||||||
|
loff_t to_skip;
|
||||||
|
int vma_count;
|
||||||
|
size_t vma_data_size;
|
||||||
|
struct core_vma_metadata *vma_meta;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are the only things you should do on a core-file: use only these
|
* These are the only things you should do on a core-file: use only these
|
||||||
* functions to write out all the necessary info.
|
* functions to write out all the necessary info.
|
||||||
*/
|
*/
|
||||||
struct coredump_params;
|
|
||||||
extern void dump_skip_to(struct coredump_params *cprm, unsigned long to);
|
extern void dump_skip_to(struct coredump_params *cprm, unsigned long to);
|
||||||
extern void dump_skip(struct coredump_params *cprm, size_t nr);
|
extern void 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_emit(struct coredump_params *cprm, const void *addr, int nr);
|
||||||
extern int dump_align(struct coredump_params *cprm, int align);
|
extern int dump_align(struct coredump_params *cprm, int align);
|
||||||
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);
|
|
||||||
extern void do_coredump(const kernel_siginfo_t *siginfo);
|
extern void do_coredump(const kernel_siginfo_t *siginfo);
|
||||||
#else
|
#else
|
||||||
static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
|
static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
|
||||||
|
|
Loading…
Add table
Reference in a new issue