rpms/kernel/devel linux-2.6-elf-core-sysctl.patch, NONE, 1.1 kernel-2.6.spec, 1.3297, 1.3298

Roland McGrath (roland) fedora-extras-commits at redhat.com
Thu Jul 12 01:34:05 UTC 2007


Author: roland

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv16384

Modified Files:
	kernel-2.6.spec 
Added Files:
	linux-2.6-elf-core-sysctl.patch 
Log Message:
core dump enhancement: include first page of ELF files, with sysctl control

linux-2.6-elf-core-sysctl.patch:

--- NEW FILE linux-2.6-elf-core-sysctl.patch ---
>From 1504394653a48c4e798bdd8dfdb11bdb48d07254 Mon Sep 17 00:00:00 2001
From: Roland McGrath <roland at redhat.com>
Date: Thu, 24 May 2007 19:09:53 -0700
Subject: [PATCH] Add sysctl controls on ELF core dump segments, dump first page of DSOs

This adds two sysctl items under fs.binfmt_elf for controlling how memory
segments are dumped in ELF core files.  The dump_whole_segments option can
be set to have private file mappings dumped in their entirety.

The dump_elf_headers option is the new default.  This dumps the first page
(only) of a read-only private file mapping if it appears to be a mapping of
an ELF file.  Including these pages in the core dump may give sufficient
identifying information to associate the original DSO and executable file
images and their debugging information with a core file in a generic way
just from its contents.

Signed-off-by: Roland McGrath <roland at redhat.com>
---
 fs/binfmt_elf.c |  152 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 128 insertions(+), 24 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index fa8ea33..af5537c 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/binfmts.h>
+#include <linux/sysctl.h>
 #include <linux/string.h>
 #include <linux/file.h>
 #include <linux/fcntl.h>
@@ -1151,6 +1152,10 @@ out:
  * Modelled on fs/exec.c:aout_core_dump()
  * Jeremy Fitzhardinge <jeremy at sw.oz.au>
  */
+
+static int dump_whole_segments = 0;
+static int dump_elf_headers = 1;
+
 /*
  * These are the only things you should do on a core-file: use only these
  * functions to write out all the necessary info.
@@ -1183,31 +1188,60 @@ static int dump_seek(struct file *file, loff_t off)
 }
 
 /*
- * Decide whether a segment is worth dumping; default is yes to be
- * sure (missing info is worse than too much; etc).
- * Personally I'd include everything, and use the coredump limit...
- *
- * I think we should skip something. But I am not sure how. H.J.
+ * Decide what to dump of a segment, part, all or none.
  */
-static int maydump(struct vm_area_struct *vma)
+static unsigned long vma_dump_size(struct vm_area_struct *vma)
 {
 	/* The vma can be set up to tell us the answer directly.  */
 	if (vma->vm_flags & VM_ALWAYSDUMP)
-		return 1;
+		goto whole;
 
 	/* Do not dump I/O mapped devices or special mappings */
 	if (vma->vm_flags & (VM_IO | VM_RESERVED))
 		return 0;
 
 	/* Dump shared memory only if mapped from an anonymous file. */
-	if (vma->vm_flags & VM_SHARED)
-		return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
-
-	/* If it hasn't been written to, don't write it out */
-	if (!vma->anon_vma)
+	if (vma->vm_flags & VM_SHARED) {
+		if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0)
+			goto whole;
 		return 0;
+	}
 
-	return 1;
+	/* Dump segments that have been written to.  */
+	if (vma->anon_vma)
+		goto whole;
+
+	if (dump_whole_segments)
+		goto whole;
+
+	/*
+	 * If this looks like the beginning of a DSO or executable mapping,
+	 * check for an ELF header.  If we find one, dump the first page to
+	 * aid in determining what was mapped here.
+	 */
+	if (dump_elf_headers && vma->vm_file != NULL && vma->vm_pgoff == 0) {
+		u32 __user *header = (u32 __user *) vma->vm_start;
+		u32 word;
+		/*
+		 * Doing it this way gets the constant folded by GCC.
+		 */
+		union {
+			u32 cmp;
+			char elfmag[SELFMAG];
+		} magic;
+		BUILD_BUG_ON(SELFMAG != sizeof word);
+		magic.elfmag[EI_MAG0] = ELFMAG0;
+		magic.elfmag[EI_MAG1] = ELFMAG1;
+		magic.elfmag[EI_MAG2] = ELFMAG2;
+		magic.elfmag[EI_MAG3] = ELFMAG3;
+		if (get_user(word, header) == 0 && word == magic.cmp)
+			return PAGE_SIZE;
+	}
+
+	return 0;
+
+whole:
+	return vma->vm_end - vma->vm_start;
 }
 
 /* An ELF note in memory */
@@ -1642,16 +1676,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		struct elf_phdr phdr;
-		size_t sz;
-
-		sz = vma->vm_end - vma->vm_start;
 
 		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
 		phdr.p_vaddr = vma->vm_start;
 		phdr.p_paddr = 0;
-		phdr.p_filesz = maydump(vma) ? sz : 0;
-		phdr.p_memsz = sz;
+		phdr.p_filesz = vma_dump_size(vma);
+		phdr.p_memsz = vma->vm_end - vma->vm_start;
 		offset += phdr.p_filesz;
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
 		if (vma->vm_flags & VM_WRITE)
@@ -1692,13 +1723,11 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		unsigned long addr;
+		unsigned long end;
 
-		if (!maydump(vma))
-			continue;
+		end = vma->vm_start + vma_dump_size(vma);
 
-		for (addr = vma->vm_start;
-		     addr < vma->vm_end;
-		     addr += PAGE_SIZE) {
+		for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
 			struct page *page;
 			struct vm_area_struct *vma;
 
@@ -1756,17 +1785,92 @@ cleanup:
 #undef NUM_NOTES
 }
 
+
+static ctl_table elf_core_dump_sysctls[] = {
+	{
+		.ctl_name = CTL_UNNUMBERED,
+		.procname = "core_dump_whole_segments",
+		.data = &dump_whole_segments,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec,
+	},
+	{
+		.ctl_name = CTL_UNNUMBERED,
+		.procname = "core_dump_elf_headers",
+		.data = &dump_elf_headers,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table binfmt_elf_sysctl_dir[] = {
+	{
+		.ctl_name = CTL_UNNUMBERED,
+		.procname = "binfmt_elf",
+		.mode = 0555,
+		.child = elf_core_dump_sysctls,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table binfmt_elf_sysctl_root[] = {
+	{
+		.ctl_name = CTL_FS,
+		.procname = "fs",
+		.mode = 0555,
+		.child = binfmt_elf_sysctl_dir,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header *core_dump_sysctl_table;
+
+static int register_core_dump_sysctl(void)
+{
+	core_dump_sysctl_table = register_sysctl_table(binfmt_elf_sysctl_root);
+	if (core_dump_sysctl_table == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void unregister_core_dump_sysctl(void)
+{
+	unregister_sysctl_table(core_dump_sysctl_table);
+	core_dump_sysctl_table = NULL;
+}
+
+#else
+
+static int register_core_dump_sysctl(void)
+{
+	return 0;
+}
+
+static void unregister_core_dump_sysctl(void)
+{
+}
+
 #endif		/* USE_ELF_CORE_DUMP */
 
 static int __init init_elf_binfmt(void)
 {
-	return register_binfmt(&elf_format);
+	int error = register_core_dump_sysctl();
+	if (!error) {
+		error = register_binfmt(&elf_format);
+		if (error)
+			unregister_core_dump_sysctl();
+	}
+	return error;
 }
 
 static void __exit exit_elf_binfmt(void)
 {
 	/* Remove the COFF and ELF loaders. */
 	unregister_binfmt(&elf_format);
+	unregister_core_dump_sysctl();
 }
 
 core_initcall(init_elf_binfmt);
-- 
1.5.2.1



Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel-2.6.spec,v
retrieving revision 1.3297
retrieving revision 1.3298
diff -u -r1.3297 -r1.3298
--- kernel-2.6.spec	11 Jul 2007 18:12:44 -0000	1.3297
+++ kernel-2.6.spec	12 Jul 2007 01:33:31 -0000	1.3298
@@ -486,7 +486,7 @@
 #Patch05: patch-2.6.%{base_sublevel}.5-6.bz2
 
 # non-released_kernel case
-# These are automagically defined by the rcrev and gitrev values set up 
+# These are automagically defined by the rcrev and gitrev values set up
 # near the top of this spec file.
 %else
 %if 0%{?rcrev}
@@ -587,6 +587,7 @@
 Patch820: linux-2.6-compile-fixes.patch
 Patch1000: linux-2.6-dmi-based-module-autoloading.patch
 Patch1010: linux-2.6-ondemand-timer.patch
+Patch1100: linux-2.6-elf-core-sysctl.patch
 
 %endif
 
@@ -1233,6 +1234,9 @@
 # DMI based module autoloading.
 ApplyPatch linux-2.6-dmi-based-module-autoloading.patch
 
+# core dump enhancement
+ApplyPatch linux-2.6-elf-core-sysctl.patch
+
 # END OF PATCH APPLICATIONS
 
 # Any further pre-build tree manipulations happen here.
@@ -2147,6 +2151,9 @@
 %endif
 
 %changelog
+* Wed Jul 11 2007 Roland McGrath <roland at redhat.com>
+- core dump enhancement: include first page of ELF files, with sysctl control
+
 * Wed Jul 11 2007 John W. Linville <linville at redhat.com>
 - Reinstate git-wireless-dev.patch
 - Add updated iwlwifi driver from intellinuxwireless.org




More information about the fedora-extras-commits mailing list