aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_elf.c324
1 files changed, 194 insertions, 130 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index b8bca1ebc1a0..4510429b973e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1395,7 +1395,8 @@ static int writenote(struct memelfnote *men, struct file *file,
1395 if (!dump_seek(file, (off))) \ 1395 if (!dump_seek(file, (off))) \
1396 goto end_coredump; 1396 goto end_coredump;
1397 1397
1398static void fill_elf_header(struct elfhdr *elf, int segs) 1398static void fill_elf_header(struct elfhdr *elf, int segs,
1399 u16 machine, u32 flags, u8 osabi)
1399{ 1400{
1400 memcpy(elf->e_ident, ELFMAG, SELFMAG); 1401 memcpy(elf->e_ident, ELFMAG, SELFMAG);
1401 elf->e_ident[EI_CLASS] = ELF_CLASS; 1402 elf->e_ident[EI_CLASS] = ELF_CLASS;
@@ -1405,12 +1406,12 @@ static void fill_elf_header(struct elfhdr *elf, int segs)
1405 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); 1406 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
1406 1407
1407 elf->e_type = ET_CORE; 1408 elf->e_type = ET_CORE;
1408 elf->e_machine = ELF_ARCH; 1409 elf->e_machine = machine;
1409 elf->e_version = EV_CURRENT; 1410 elf->e_version = EV_CURRENT;
1410 elf->e_entry = 0; 1411 elf->e_entry = 0;
1411 elf->e_phoff = sizeof(struct elfhdr); 1412 elf->e_phoff = sizeof(struct elfhdr);
1412 elf->e_shoff = 0; 1413 elf->e_shoff = 0;
1413 elf->e_flags = ELF_CORE_EFLAGS; 1414 elf->e_flags = flags;
1414 elf->e_ehsize = sizeof(struct elfhdr); 1415 elf->e_ehsize = sizeof(struct elfhdr);
1415 elf->e_phentsize = sizeof(struct elf_phdr); 1416 elf->e_phentsize = sizeof(struct elf_phdr);
1416 elf->e_phnum = segs; 1417 elf->e_phnum = segs;
@@ -1517,6 +1518,16 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
1517 return 0; 1518 return 0;
1518} 1519}
1519 1520
1521static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
1522{
1523 elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv;
1524 int i = 0;
1525 do
1526 i += 2;
1527 while (auxv[i - 2] != AT_NULL);
1528 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
1529}
1530
1520/* Here is the structure in which status of each thread is captured. */ 1531/* Here is the structure in which status of each thread is captured. */
1521struct elf_thread_status 1532struct elf_thread_status
1522{ 1533{
@@ -1569,6 +1580,174 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
1569 return sz; 1580 return sz;
1570} 1581}
1571 1582
1583struct elf_note_info {
1584 struct memelfnote *notes;
1585 struct elf_prstatus *prstatus; /* NT_PRSTATUS */
1586 struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
1587 struct list_head thread_list;
1588 elf_fpregset_t *fpu;
1589#ifdef ELF_CORE_COPY_XFPREGS
1590 elf_fpxregset_t *xfpu;
1591#endif
1592 int thread_status_size;
1593 int numnote;
1594};
1595
1596static int fill_note_info(struct elfhdr *elf, int phdrs,
1597 struct elf_note_info *info,
1598 long signr, struct pt_regs *regs)
1599{
1600#define NUM_NOTES 6
1601 struct list_head *t;
1602 struct task_struct *g, *p;
1603
1604 info->notes = NULL;
1605 info->prstatus = NULL;
1606 info->psinfo = NULL;
1607 info->fpu = NULL;
1608#ifdef ELF_CORE_COPY_XFPREGS
1609 info->xfpu = NULL;
1610#endif
1611 INIT_LIST_HEAD(&info->thread_list);
1612
1613 info->notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote),
1614 GFP_KERNEL);
1615 if (!info->notes)
1616 return 0;
1617 info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
1618 if (!info->psinfo)
1619 return 0;
1620 info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
1621 if (!info->prstatus)
1622 return 0;
1623 info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
1624 if (!info->fpu)
1625 return 0;
1626#ifdef ELF_CORE_COPY_XFPREGS
1627 info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
1628 if (!info->xfpu)
1629 return 0;
1630#endif
1631
1632 info->thread_status_size = 0;
1633 if (signr) {
1634 struct elf_thread_status *tmp;
1635 rcu_read_lock();
1636 do_each_thread(g, p)
1637 if (current->mm == p->mm && current != p) {
1638 tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
1639 if (!tmp) {
1640 rcu_read_unlock();
1641 return 0;
1642 }
1643 tmp->thread = p;
1644 list_add(&tmp->list, &info->thread_list);
1645 }
1646 while_each_thread(g, p);
1647 rcu_read_unlock();
1648 list_for_each(t, &info->thread_list) {
1649 struct elf_thread_status *tmp;
1650 int sz;
1651
1652 tmp = list_entry(t, struct elf_thread_status, list);
1653 sz = elf_dump_thread_status(signr, tmp);
1654 info->thread_status_size += sz;
1655 }
1656 }
1657 /* now collect the dump for the current */
1658 memset(info->prstatus, 0, sizeof(*info->prstatus));
1659 fill_prstatus(info->prstatus, current, signr);
1660 elf_core_copy_regs(&info->prstatus->pr_reg, regs);
1661
1662 /* Set up header */
1663 fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI);
1664
1665 /*
1666 * Set up the notes in similar form to SVR4 core dumps made
1667 * with info from their /proc.
1668 */
1669
1670 fill_note(info->notes + 0, "CORE", NT_PRSTATUS,
1671 sizeof(*info->prstatus), info->prstatus);
1672 fill_psinfo(info->psinfo, current->group_leader, current->mm);
1673 fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
1674 sizeof(*info->psinfo), info->psinfo);
1675
1676 info->numnote = 2;
1677
1678 fill_auxv_note(&info->notes[info->numnote++], current->mm);
1679
1680 /* Try to dump the FPU. */
1681 info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
1682 info->fpu);
1683 if (info->prstatus->pr_fpvalid)
1684 fill_note(info->notes + info->numnote++,
1685 "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
1686#ifdef ELF_CORE_COPY_XFPREGS
1687 if (elf_core_copy_task_xfpregs(current, info->xfpu))
1688 fill_note(info->notes + info->numnote++,
1689 "LINUX", ELF_CORE_XFPREG_TYPE,
1690 sizeof(*info->xfpu), info->xfpu);
1691#endif
1692
1693 return 1;
1694
1695#undef NUM_NOTES
1696}
1697
1698static size_t get_note_info_size(struct elf_note_info *info)
1699{
1700 int sz = 0;
1701 int i;
1702
1703 for (i = 0; i < info->numnote; i++)
1704 sz += notesize(info->notes + i);
1705
1706 sz += info->thread_status_size;
1707
1708 return sz;
1709}
1710
1711static int write_note_info(struct elf_note_info *info,
1712 struct file *file, loff_t *foffset)
1713{
1714 int i;
1715 struct list_head *t;
1716
1717 for (i = 0; i < info->numnote; i++)
1718 if (!writenote(info->notes + i, file, foffset))
1719 return 0;
1720
1721 /* write out the thread status notes section */
1722 list_for_each(t, &info->thread_list) {
1723 struct elf_thread_status *tmp =
1724 list_entry(t, struct elf_thread_status, list);
1725
1726 for (i = 0; i < tmp->num_notes; i++)
1727 if (!writenote(&tmp->notes[i], file, foffset))
1728 return 0;
1729 }
1730
1731 return 1;
1732}
1733
1734static void free_note_info(struct elf_note_info *info)
1735{
1736 while (!list_empty(&info->thread_list)) {
1737 struct list_head *tmp = info->thread_list.next;
1738 list_del(tmp);
1739 kfree(list_entry(tmp, struct elf_thread_status, list));
1740 }
1741
1742 kfree(info->prstatus);
1743 kfree(info->psinfo);
1744 kfree(info->notes);
1745 kfree(info->fpu);
1746#ifdef ELF_CORE_COPY_XFPREGS
1747 kfree(info->xfpu);
1748#endif
1749}
1750
1572static struct vm_area_struct *first_vma(struct task_struct *tsk, 1751static struct vm_area_struct *first_vma(struct task_struct *tsk,
1573 struct vm_area_struct *gate_vma) 1752 struct vm_area_struct *gate_vma)
1574{ 1753{
@@ -1604,29 +1783,15 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
1604 */ 1783 */
1605static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) 1784static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
1606{ 1785{
1607#define NUM_NOTES 6
1608 int has_dumped = 0; 1786 int has_dumped = 0;
1609 mm_segment_t fs; 1787 mm_segment_t fs;
1610 int segs; 1788 int segs;
1611 size_t size = 0; 1789 size_t size = 0;
1612 int i;
1613 struct vm_area_struct *vma, *gate_vma; 1790 struct vm_area_struct *vma, *gate_vma;
1614 struct elfhdr *elf = NULL; 1791 struct elfhdr *elf = NULL;
1615 loff_t offset = 0, dataoff, foffset; 1792 loff_t offset = 0, dataoff, foffset;
1616 int numnote;
1617 struct memelfnote *notes = NULL;
1618 struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
1619 struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */
1620 struct task_struct *g, *p;
1621 LIST_HEAD(thread_list);
1622 struct list_head *t;
1623 elf_fpregset_t *fpu = NULL;
1624#ifdef ELF_CORE_COPY_XFPREGS
1625 elf_fpxregset_t *xfpu = NULL;
1626#endif
1627 int thread_status_size = 0;
1628 elf_addr_t *auxv;
1629 unsigned long mm_flags; 1793 unsigned long mm_flags;
1794 struct elf_note_info info;
1630 1795
1631 /* 1796 /*
1632 * We no longer stop all VM operations. 1797 * We no longer stop all VM operations.
@@ -1644,52 +1809,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1644 elf = kmalloc(sizeof(*elf), GFP_KERNEL); 1809 elf = kmalloc(sizeof(*elf), GFP_KERNEL);
1645 if (!elf) 1810 if (!elf)
1646 goto cleanup; 1811 goto cleanup;
1647 prstatus = kmalloc(sizeof(*prstatus), GFP_KERNEL);
1648 if (!prstatus)
1649 goto cleanup;
1650 psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
1651 if (!psinfo)
1652 goto cleanup;
1653 notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL);
1654 if (!notes)
1655 goto cleanup;
1656 fpu = kmalloc(sizeof(*fpu), GFP_KERNEL);
1657 if (!fpu)
1658 goto cleanup;
1659#ifdef ELF_CORE_COPY_XFPREGS
1660 xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL);
1661 if (!xfpu)
1662 goto cleanup;
1663#endif
1664
1665 if (signr) {
1666 struct elf_thread_status *tmp;
1667 rcu_read_lock();
1668 do_each_thread(g,p)
1669 if (current->mm == p->mm && current != p) {
1670 tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
1671 if (!tmp) {
1672 rcu_read_unlock();
1673 goto cleanup;
1674 }
1675 tmp->thread = p;
1676 list_add(&tmp->list, &thread_list);
1677 }
1678 while_each_thread(g,p);
1679 rcu_read_unlock();
1680 list_for_each(t, &thread_list) {
1681 struct elf_thread_status *tmp;
1682 int sz;
1683
1684 tmp = list_entry(t, struct elf_thread_status, list);
1685 sz = elf_dump_thread_status(signr, tmp);
1686 thread_status_size += sz;
1687 }
1688 }
1689 /* now collect the dump for the current */
1690 memset(prstatus, 0, sizeof(*prstatus));
1691 fill_prstatus(prstatus, current, signr);
1692 elf_core_copy_regs(&prstatus->pr_reg, regs);
1693 1812
1694 segs = current->mm->map_count; 1813 segs = current->mm->map_count;
1695#ifdef ELF_CORE_EXTRA_PHDRS 1814#ifdef ELF_CORE_EXTRA_PHDRS
@@ -1700,42 +1819,16 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1700 if (gate_vma != NULL) 1819 if (gate_vma != NULL)
1701 segs++; 1820 segs++;
1702 1821
1703 /* Set up header */
1704 fill_elf_header(elf, segs + 1); /* including notes section */
1705
1706 has_dumped = 1;
1707 current->flags |= PF_DUMPCORE;
1708
1709 /* 1822 /*
1710 * Set up the notes in similar form to SVR4 core dumps made 1823 * Collect all the non-memory information about the process for the
1711 * with info from their /proc. 1824 * notes. This also sets up the file header.
1712 */ 1825 */
1826 if (!fill_note_info(elf, segs + 1, /* including notes section */
1827 &info, signr, regs))
1828 goto cleanup;
1713 1829
1714 fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); 1830 has_dumped = 1;
1715 fill_psinfo(psinfo, current->group_leader, current->mm); 1831 current->flags |= PF_DUMPCORE;
1716 fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
1717
1718 numnote = 2;
1719
1720 auxv = (elf_addr_t *)current->mm->saved_auxv;
1721
1722 i = 0;
1723 do
1724 i += 2;
1725 while (auxv[i - 2] != AT_NULL);
1726 fill_note(&notes[numnote++], "CORE", NT_AUXV,
1727 i * sizeof(elf_addr_t), auxv);
1728
1729 /* Try to dump the FPU. */
1730 if ((prstatus->pr_fpvalid =
1731 elf_core_copy_task_fpregs(current, regs, fpu)))
1732 fill_note(notes + numnote++,
1733 "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
1734#ifdef ELF_CORE_COPY_XFPREGS
1735 if (elf_core_copy_task_xfpregs(current, xfpu))
1736 fill_note(notes + numnote++,
1737 "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
1738#endif
1739 1832
1740 fs = get_fs(); 1833 fs = get_fs();
1741 set_fs(KERNEL_DS); 1834 set_fs(KERNEL_DS);
@@ -1748,12 +1841,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1748 /* Write notes phdr entry */ 1841 /* Write notes phdr entry */
1749 { 1842 {
1750 struct elf_phdr phdr; 1843 struct elf_phdr phdr;
1751 int sz = 0; 1844 size_t sz = get_note_info_size(&info);
1752
1753 for (i = 0; i < numnote; i++)
1754 sz += notesize(notes + i);
1755
1756 sz += thread_status_size;
1757 1845
1758 sz += elf_coredump_extra_notes_size(); 1846 sz += elf_coredump_extra_notes_size();
1759 1847
@@ -1798,23 +1886,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1798#endif 1886#endif
1799 1887
1800 /* write out the notes section */ 1888 /* write out the notes section */
1801 for (i = 0; i < numnote; i++) 1889 if (!write_note_info(&info, file, &foffset))
1802 if (!writenote(notes + i, file, &foffset)) 1890 goto end_coredump;
1803 goto end_coredump;
1804 1891
1805 if (elf_coredump_extra_notes_write(file, &foffset)) 1892 if (elf_coredump_extra_notes_write(file, &foffset))
1806 goto end_coredump; 1893 goto end_coredump;
1807 1894
1808 /* write out the thread status notes section */
1809 list_for_each(t, &thread_list) {
1810 struct elf_thread_status *tmp =
1811 list_entry(t, struct elf_thread_status, list);
1812
1813 for (i = 0; i < tmp->num_notes; i++)
1814 if (!writenote(&tmp->notes[i], file, &foffset))
1815 goto end_coredump;
1816 }
1817
1818 /* Align to page */ 1895 /* Align to page */
1819 DUMP_SEEK(dataoff - foffset); 1896 DUMP_SEEK(dataoff - foffset);
1820 1897
@@ -1865,22 +1942,9 @@ end_coredump:
1865 set_fs(fs); 1942 set_fs(fs);
1866 1943
1867cleanup: 1944cleanup:
1868 while (!list_empty(&thread_list)) {
1869 struct list_head *tmp = thread_list.next;
1870 list_del(tmp);
1871 kfree(list_entry(tmp, struct elf_thread_status, list));
1872 }
1873
1874 kfree(elf); 1945 kfree(elf);
1875 kfree(prstatus); 1946 free_note_info(&info);
1876 kfree(psinfo);
1877 kfree(notes);
1878 kfree(fpu);
1879#ifdef ELF_CORE_COPY_XFPREGS
1880 kfree(xfpu);
1881#endif
1882 return has_dumped; 1947 return has_dumped;
1883#undef NUM_NOTES
1884} 1948}
1885 1949
1886#endif /* USE_ELF_CORE_DUMP */ 1950#endif /* USE_ELF_CORE_DUMP */