Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f47aef55 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds
Browse files

[PATCH] i386 vDSO: use VM_ALWAYSDUMP



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: default avatarRoland 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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e5b97dde
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -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)) {
@@ -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;
+35 −3
Original line number Diff line number Diff line
@@ -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
 *
@@ -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;
@@ -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 */

@@ -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;

@@ -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))
+0 −44
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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);