diff options
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 63 |
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 | ||
1508 | static 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 | ||
1588 | static 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 |