Commit 9a7a9c33 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reduce stack size: elf_core_dump()

Patch from "Randy.Dunlap" <randy.dunlap@verizon.net>

This patch reduces stack size in elf_core_dump() from over 0x400 (0x4a4 e.g.)
to less than 0x100 (0xb0 on a P4 with gcc 2.96).
parent 6d29dc24
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/time.h> #include <linux/time.h>
...@@ -1175,41 +1175,62 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis ...@@ -1175,41 +1175,62 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis
*/ */
static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
{ {
#define NUM_NOTES 5
int has_dumped = 0; int has_dumped = 0;
mm_segment_t fs; mm_segment_t fs;
int segs; int segs;
size_t size = 0; size_t size = 0;
int i; int i;
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct elfhdr elf; struct elfhdr *elf = NULL;
off_t offset = 0, dataoff; off_t offset = 0, dataoff;
unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur; unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur;
int numnote = 5; int numnote = NUM_NOTES;
struct memelfnote notes[5]; struct memelfnote *notes = NULL;
struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */
struct task_struct *g, *p; struct task_struct *g, *p;
LIST_HEAD(thread_list); LIST_HEAD(thread_list);
struct list_head *t; struct list_head *t;
elf_fpregset_t fpu; elf_fpregset_t *fpu = NULL;
#ifdef ELF_CORE_COPY_XFPREGS elf_fpxregset_t *xfpu = NULL;
elf_fpxregset_t xfpu;
#endif
int thread_status_size = 0; int thread_status_size = 0;
/* We no longer stop all vm operations /*
* We no longer stop all VM operations.
* *
* This because those proceses that could possibly * This is because those proceses that could possibly change map_count or
* change map_count or the mmap / vma pages are now blocked in do_exit on current finishing * the mmap / vma pages are now blocked in do_exit on current finishing
* this core dump. * this core dump.
* *
* Only ptrace can touch these memory addresses, but it doesn't change * Only ptrace can touch these memory addresses, but it doesn't change
* the map_count or the pages allocated. So no possibility of crashing exists while dumping * the map_count or the pages allocated. So no possibility of crashing
* the mm->vm_next areas to the core file. * exists while dumping the mm->vm_next areas to the core file.
*
*/ */
/* capture the status of all other threads */ /* alloc memory for large data structures: too large to be on stack */
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
if (!elf)
goto cleanup;
prstatus = kmalloc(sizeof(*prstatus), GFP_KERNEL);
if (!prstatus)
goto cleanup;
psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
if (!psinfo)
goto cleanup;
notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL);
if (!notes)
goto cleanup;
fpu = kmalloc(sizeof(*fpu), GFP_KERNEL);
if (!fpu)
goto cleanup;
#ifdef ELF_CORE_COPY_XFPREGS
xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL);
if (!xfpu)
goto cleanup;
#endif
/* capture the status of all other threads */
if (signr) { if (signr) {
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
do_each_thread(g,p) do_each_thread(g,p)
...@@ -1226,14 +1247,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1226,14 +1247,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
} }
/* now collect the dump for the current */ /* now collect the dump for the current */
memset(&prstatus, 0, sizeof(prstatus)); memset(prstatus, 0, sizeof(*prstatus));
fill_prstatus(&prstatus, current, signr); fill_prstatus(prstatus, current, signr);
elf_core_copy_regs(&prstatus.pr_reg, regs); elf_core_copy_regs(&prstatus->pr_reg, regs);
segs = current->mm->map_count; segs = current->mm->map_count;
/* Set up header */ /* Set up header */
fill_elf_header(&elf, segs+1); /* including notes section*/ fill_elf_header(elf, segs+1); /* including notes section */
has_dumped = 1; has_dumped = 1;
current->flags |= PF_DUMPCORE; current->flags |= PF_DUMPCORE;
...@@ -1243,32 +1264,32 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1243,32 +1264,32 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
* with info from their /proc. * with info from their /proc.
*/ */
fill_note(&notes[0], "CORE", NT_PRSTATUS, sizeof(prstatus), &prstatus); fill_note(notes +0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus);
fill_psinfo(&psinfo, current->group_leader); fill_psinfo(psinfo, current->group_leader);
fill_note(&notes[1], "CORE", NT_PRPSINFO, sizeof(psinfo), &psinfo); fill_note(notes +1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
fill_note(&notes[2], "CORE", NT_TASKSTRUCT, sizeof(*current), current); fill_note(notes +2, "CORE", NT_TASKSTRUCT, sizeof(*current), current);
/* Try to dump the FPU. */ /* Try to dump the FPU. */
if ((prstatus.pr_fpvalid = elf_core_copy_task_fpregs(current, &fpu))) if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, fpu)))
fill_note(&notes[3], "CORE", NT_PRFPREG, sizeof(fpu), &fpu); fill_note(notes +3, "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
else else
--numnote; --numnote;
#ifdef ELF_CORE_COPY_XFPREGS #ifdef ELF_CORE_COPY_XFPREGS
if (elf_core_copy_task_xfpregs(current, &xfpu)) if (elf_core_copy_task_xfpregs(current, xfpu))
fill_note(&notes[4], "LINUX", NT_PRXFPREG, sizeof(xfpu), &xfpu); fill_note(notes +4, "LINUX", NT_PRXFPREG, sizeof(*xfpu), xfpu);
else else
--numnote; --numnote;
#else #else
numnote --; numnote--;
#endif #endif
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
DUMP_WRITE(&elf, sizeof(elf)); DUMP_WRITE(elf, sizeof(*elf));
offset += sizeof(elf); /* Elf header */ offset += sizeof(*elf); /* Elf header */
offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
/* Write notes phdr entry */ /* Write notes phdr entry */
...@@ -1276,8 +1297,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1276,8 +1297,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
struct elf_phdr phdr; struct elf_phdr phdr;
int sz = 0; int sz = 0;
for(i = 0; i < numnote; i++) for (i = 0; i < numnote; i++)
sz += notesize(&notes[i]); sz += notesize(notes + i);
sz += thread_status_size; sz += thread_status_size;
...@@ -1290,7 +1311,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1290,7 +1311,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
/* Write program headers for segments dump */ /* Write program headers for segments dump */
for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
struct elf_phdr phdr; struct elf_phdr phdr;
size_t sz; size_t sz;
...@@ -1312,8 +1333,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1312,8 +1333,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
} }
/* write out the notes section */ /* write out the notes section */
for(i = 0; i < numnote; i++) for (i = 0; i < numnote; i++)
if (!writenote(&notes[i], file)) if (!writenote(notes + i, file))
goto end_coredump; goto end_coredump;
/* write out the thread status notes section */ /* write out the thread status notes section */
...@@ -1326,7 +1347,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1326,7 +1347,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
DUMP_SEEK(dataoff); DUMP_SEEK(dataoff);
for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
unsigned long addr; unsigned long addr;
if (!maydump(vma)) if (!maydump(vma))
...@@ -1373,7 +1394,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) ...@@ -1373,7 +1394,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
kfree(list_entry(tmp, struct elf_thread_status, list)); kfree(list_entry(tmp, struct elf_thread_status, list));
} }
kfree(elf);
kfree(prstatus);
kfree(psinfo);
kfree(notes);
kfree(fpu);
kfree(xfpu);
return has_dumped; return has_dumped;
#undef NUM_NOTES
} }
#endif /* USE_ELF_CORE_DUMP */ #endif /* USE_ELF_CORE_DUMP */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment