Skip to content

Commit

Permalink
[PATCH] i386 vDSO: use VM_ALWAYSDUMP
Browse files Browse the repository at this point in the history
This patch fixes core dumps to include the vDSO vma, which is left out now.
It removes the special-case core writing macros, which were not doing the
right thing for the vDSO vma anyway.  Instead, it uses VM_ALWAYSDUMP in the
vma; there is no need for the fixmap page to be installed.  It handles the
CONFIG_COMPAT_VDSO case by making elf_core_dump use the fake vma from
get_gate_vma after real vmas in the same way the /proc/PID/maps code does.

This changes core dumps so they no longer include the non-PT_LOAD phdrs from
the vDSO.  I made the change to add them in the first place, but in turned out
that nothing ever wanted them there since the advent of NT_AUXV.  It's cleaner
to leave them out, and just let the phdrs inside the vDSO image speak for
themselves.

Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Roland McGrath authored and Linus Torvalds committed Jan 26, 2007
1 parent e5b97dd commit f47aef5
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 52 deletions.
12 changes: 7 additions & 5 deletions arch/i386/kernel/sysenter.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ int __init sysenter_setup(void)
#ifdef CONFIG_COMPAT_VDSO
__set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
#else
/*
* In the non-compat case the ELF coredumping code needs the fixmap:
*/
__set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
#endif

if (!boot_cpu_has(X86_FEATURE_SEP)) {
Expand Down Expand Up @@ -147,6 +142,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
vma->vm_end = addr + PAGE_SIZE;
/* MAYWRITE to allow gdb to COW and set breakpoints */
vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
/*
* Make sure the vDSO gets into every core dump.
* Dumping its contents makes post-mortem fully interpretable later
* without matching up the same kernel and hardware config to see
* what PC values meant.
*/
vma->vm_flags |= VM_ALWAYSDUMP;
vma->vm_flags |= mm->def_flags;
vma->vm_page_prot = protection_map[vma->vm_flags & 7];
vma->vm_ops = &syscall_vm_ops;
Expand Down
38 changes: 35 additions & 3 deletions fs/binfmt_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,32 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
return sz;
}

static struct vm_area_struct *first_vma(struct task_struct *tsk,
struct vm_area_struct *gate_vma)
{
struct vm_area_struct *ret = tsk->mm->mmap;

if (ret)
return ret;
return gate_vma;
}
/*
* Helper function for iterating across a vma list. It ensures that the caller
* will visit `gate_vma' prior to terminating the search.
*/
static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
struct vm_area_struct *gate_vma)
{
struct vm_area_struct *ret;

ret = this_vma->vm_next;
if (ret)
return ret;
if (this_vma == gate_vma)
return NULL;
return gate_vma;
}

/*
* Actual dumper
*
Expand All @@ -1443,7 +1469,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
int segs;
size_t size = 0;
int i;
struct vm_area_struct *vma;
struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff, foffset;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
Expand Down Expand Up @@ -1529,6 +1555,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
segs += ELF_CORE_EXTRA_PHDRS;
#endif

gate_vma = get_gate_vma(current);
if (gate_vma != NULL)
segs++;

/* Set up header */
fill_elf_header(elf, segs + 1); /* including notes section */

Expand Down Expand Up @@ -1596,7 +1626,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);

/* Write program headers for segments dump */
for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
size_t sz;

Expand Down Expand Up @@ -1645,7 +1676,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
/* Align to page */
DUMP_SEEK(dataoff - foffset);

for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long addr;

if (!maydump(vma))
Expand Down
44 changes: 0 additions & 44 deletions include/asm-i386/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,50 +168,6 @@ do if (vdso_enabled) { \
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
} while (0)

/*
* These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
* extra segments containing the vsyscall DSO contents. Dumping its
* contents makes post-mortem fully interpretable later without matching up
* the same kernel and hardware config to see what PC values meant.
* Dumping its extra ELF program headers includes all the other information
* a debugger needs to easily find how the vsyscall DSO was being used.
*/
#define ELF_CORE_EXTRA_PHDRS (VDSO_HIGH_EHDR->e_phnum)
#define ELF_CORE_WRITE_EXTRA_PHDRS \
do { \
const struct elf_phdr *const vsyscall_phdrs = \
(const struct elf_phdr *) (VDSO_HIGH_BASE \
+ VDSO_HIGH_EHDR->e_phoff); \
int i; \
Elf32_Off ofs = 0; \
for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
struct elf_phdr phdr = vsyscall_phdrs[i]; \
if (phdr.p_type == PT_LOAD) { \
BUG_ON(ofs != 0); \
ofs = phdr.p_offset = offset; \
phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz); \
phdr.p_filesz = phdr.p_memsz; \
offset += phdr.p_filesz; \
} \
else \
phdr.p_offset += ofs; \
phdr.p_paddr = 0; /* match other core phdrs */ \
DUMP_WRITE(&phdr, sizeof(phdr)); \
} \
} while (0)
#define ELF_CORE_WRITE_EXTRA_DATA \
do { \
const struct elf_phdr *const vsyscall_phdrs = \
(const struct elf_phdr *) (VDSO_HIGH_BASE \
+ VDSO_HIGH_EHDR->e_phoff); \
int i; \
for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
if (vsyscall_phdrs[i].p_type == PT_LOAD) \
DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \
PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
} \
} while (0)

#endif

#endif
7 changes: 7 additions & 0 deletions mm/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -2608,6 +2608,13 @@ static int __init gate_vma_init(void)
gate_vma.vm_end = FIXADDR_USER_END;
gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
gate_vma.vm_page_prot = __P101;
/*
* Make sure the vDSO gets into every core dump.
* Dumping its contents makes post-mortem fully interpretable later
* without matching up the same kernel and hardware config to see
* what PC values meant.
*/
gate_vma.vm_flags |= VM_ALWAYSDUMP;
return 0;
}
__initcall(gate_vma_init);
Expand Down

0 comments on commit f47aef5

Please sign in to comment.