aboutsummaryrefslogtreecommitdiffstats
path: root/fs/binfmt_elf_fdpic.c
diff options
context:
space:
mode:
authorDaisuke HATAYAMA <d.hatayama@jp.fujitsu.com>2010-03-05 16:44:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 14:26:46 -0500
commit8d9032bbe4671dc481261ccd4e161cd96e54b118 (patch)
treea31d22f488f7d6789259da68c53cb2727a925fa8 /fs/binfmt_elf_fdpic.c
parent93eb211e6c9ff6054fcf9c5b9e344d8d9ad29175 (diff)
elf coredump: add extended numbering support
The current ELF dumper implementation can produce broken corefiles if program headers exceed 65535. This number is determined by the number of vmas which the process have. In particular, some extreme programs may use more than 65535 vmas. (If you google max_map_count, you can find some users facing this problem.) This kind of program never be able to generate correct coredumps. This patch implements ``extended numbering'' that uses sh_info field of the first section header instead of e_phnum field in order to represent upto 4294967295 vmas. This is supported by AMD64-ABI(http://www.x86-64.org/documentation.html) and Solaris(http://docs.sun.com/app/docs/doc/817-1984/). Of course, we are preparing patches for gdb and binutils. Signed-off-by: Daisuke HATAYAMA <d.hatayama@jp.fujitsu.com> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Jeff Dike <jdike@addtoit.com> Cc: David Howells <dhowells@redhat.com> Cc: Greg Ungerer <gerg@snapgear.com> Cc: Roland McGrath <roland@redhat.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Andi Kleen <andi@firstfloor.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r--fs/binfmt_elf_fdpic.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 112da491d75d..e49d9c06a4b6 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1505,6 +1505,22 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
1505 return sz; 1505 return sz;
1506} 1506}
1507 1507
1508static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
1509 elf_addr_t e_shoff, int segs)
1510{
1511 elf->e_shoff = e_shoff;
1512 elf->e_shentsize = sizeof(*shdr4extnum);
1513 elf->e_shnum = 1;
1514 elf->e_shstrndx = SHN_UNDEF;
1515
1516 memset(shdr4extnum, 0, sizeof(*shdr4extnum));
1517
1518 shdr4extnum->sh_type = SHT_NULL;
1519 shdr4extnum->sh_size = elf->e_shnum;
1520 shdr4extnum->sh_link = elf->e_shstrndx;
1521 shdr4extnum->sh_info = segs;
1522}
1523
1508/* 1524/*
1509 * dump the segments for an MMU process 1525 * dump the segments for an MMU process
1510 */ 1526 */
@@ -1569,6 +1585,17 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
1569} 1585}
1570#endif 1586#endif
1571 1587
1588static size_t elf_core_vma_data_size(unsigned long mm_flags)
1589{
1590 struct vm_area_struct *vma;
1591 size_t size = 0;
1592
1593 for (vma = current->mm->mmap; vma; vma->vm_next)
1594 if (maydump(vma, mm_flags))
1595 size += vma->vm_end - vma->vm_start;
1596 return size;
1597}
1598
1572/* 1599/*
1573 * Actual dumper 1600 * Actual dumper
1574 * 1601 *
@@ -1601,6 +1628,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1601 elf_addr_t *auxv; 1628 elf_addr_t *auxv;
1602 unsigned long mm_flags; 1629 unsigned long mm_flags;
1603 struct elf_phdr *phdr4note = NULL; 1630 struct elf_phdr *phdr4note = NULL;
1631 struct elf_shdr *shdr4extnum = NULL;
1632 Elf_Half e_phnum;
1633 elf_addr_t e_shoff;
1604 1634
1605 /* 1635 /*
1606 * We no longer stop all VM operations. 1636 * We no longer stop all VM operations.
@@ -1667,8 +1697,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1667 segs = current->mm->map_count; 1697 segs = current->mm->map_count;
1668 segs += elf_core_extra_phdrs(); 1698 segs += elf_core_extra_phdrs();
1669 1699
1700 /* for notes section */
1701 segs++;
1702
1703 /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
1704 * this, kernel supports extended numbering. Have a look at
1705 * include/linux/elf.h for further information. */
1706 e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
1707
1670 /* Set up header */ 1708 /* Set up header */
1671 fill_elf_fdpic_header(elf, segs + 1); /* including notes section */ 1709 fill_elf_fdpic_header(elf, e_phnum);
1672 1710
1673 has_dumped = 1; 1711 has_dumped = 1;
1674 current->flags |= PF_DUMPCORE; 1712 current->flags |= PF_DUMPCORE;
@@ -1708,7 +1746,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1708 set_fs(KERNEL_DS); 1746 set_fs(KERNEL_DS);
1709 1747
1710 offset += sizeof(*elf); /* Elf header */ 1748 offset += sizeof(*elf); /* Elf header */
1711 offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ 1749 offset += segs * sizeof(struct elf_phdr); /* Program headers */
1712 foffset = offset; 1750 foffset = offset;
1713 1751
1714 /* Write notes phdr entry */ 1752 /* Write notes phdr entry */
@@ -1738,6 +1776,19 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1738 */ 1776 */
1739 mm_flags = current->mm->flags; 1777 mm_flags = current->mm->flags;
1740 1778
1779 offset += elf_core_vma_data_size(mm_flags);
1780 offset += elf_core_extra_data_size();
1781 e_shoff = offset;
1782
1783 if (e_phnum == PN_XNUM) {
1784 shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
1785 if (!shdr4extnum)
1786 goto end_coredump;
1787 fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
1788 }
1789
1790 offset = dataoff;
1791
1741 size += sizeof(*elf); 1792 size += sizeof(*elf);
1742 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) 1793 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
1743 goto end_coredump; 1794 goto end_coredump;
@@ -1802,6 +1853,14 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1802 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) 1853 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
1803 goto end_coredump; 1854 goto end_coredump;
1804 1855
1856 if (e_phnum == PN_XNUM) {
1857 size += sizeof(*shdr4extnum);
1858 if (size > cprm->limit
1859 || !dump_write(cprm->file, shdr4extnum,
1860 sizeof(*shdr4extnum)))
1861 goto end_coredump;
1862 }
1863
1805 if (cprm->file->f_pos != offset) { 1864 if (cprm->file->f_pos != offset) {
1806 /* Sanity check */ 1865 /* Sanity check */
1807 printk(KERN_WARNING 1866 printk(KERN_WARNING