aboutsummaryrefslogtreecommitdiffstats
path: root/fs/binfmt_elf_fdpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r--fs/binfmt_elf_fdpic.c183
1 files changed, 113 insertions, 70 deletions
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 18d77297ccc8..7ab23e006e4c 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -34,6 +34,7 @@
34#include <linux/elf.h> 34#include <linux/elf.h>
35#include <linux/elf-fdpic.h> 35#include <linux/elf-fdpic.h>
36#include <linux/elfcore.h> 36#include <linux/elfcore.h>
37#include <linux/coredump.h>
37 38
38#include <asm/uaccess.h> 39#include <asm/uaccess.h>
39#include <asm/param.h> 40#include <asm/param.h>
@@ -1216,26 +1217,6 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
1216#ifdef CONFIG_ELF_CORE 1217#ifdef CONFIG_ELF_CORE
1217 1218
1218/* 1219/*
1219 * These are the only things you should do on a core-file: use only these
1220 * functions to write out all the necessary info.
1221 */
1222static int dump_write(struct file *file, const void *addr, int nr)
1223{
1224 return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
1225}
1226
1227static int dump_seek(struct file *file, loff_t off)
1228{
1229 if (file->f_op->llseek) {
1230 if (file->f_op->llseek(file, off, SEEK_SET) != off)
1231 return 0;
1232 } else {
1233 file->f_pos = off;
1234 }
1235 return 1;
1236}
1237
1238/*
1239 * Decide whether a segment is worth dumping; default is yes to be 1220 * Decide whether a segment is worth dumping; default is yes to be
1240 * sure (missing info is worse than too much; etc). 1221 * sure (missing info is worse than too much; etc).
1241 * Personally I'd include everything, and use the coredump limit... 1222 * Personally I'd include everything, and use the coredump limit...
@@ -1313,35 +1294,35 @@ static int notesize(struct memelfnote *en)
1313 1294
1314/* #define DEBUG */ 1295/* #define DEBUG */
1315 1296
1316#define DUMP_WRITE(addr, nr) \ 1297#define DUMP_WRITE(addr, nr, foffset) \
1317 do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) 1298 do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
1318#define DUMP_SEEK(off) \
1319 do { if (!dump_seek(file, (off))) return 0; } while(0)
1320 1299
1321static int writenote(struct memelfnote *men, struct file *file) 1300static int alignfile(struct file *file, loff_t *foffset)
1322{ 1301{
1323 struct elf_note en; 1302 static const char buf[4] = { 0, };
1303 DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
1304 return 1;
1305}
1324 1306
1307static int writenote(struct memelfnote *men, struct file *file,
1308 loff_t *foffset)
1309{
1310 struct elf_note en;
1325 en.n_namesz = strlen(men->name) + 1; 1311 en.n_namesz = strlen(men->name) + 1;
1326 en.n_descsz = men->datasz; 1312 en.n_descsz = men->datasz;
1327 en.n_type = men->type; 1313 en.n_type = men->type;
1328 1314
1329 DUMP_WRITE(&en, sizeof(en)); 1315 DUMP_WRITE(&en, sizeof(en), foffset);
1330 DUMP_WRITE(men->name, en.n_namesz); 1316 DUMP_WRITE(men->name, en.n_namesz, foffset);
1331 /* XXX - cast from long long to long to avoid need for libgcc.a */ 1317 if (!alignfile(file, foffset))
1332 DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ 1318 return 0;
1333 DUMP_WRITE(men->data, men->datasz); 1319 DUMP_WRITE(men->data, men->datasz, foffset);
1334 DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ 1320 if (!alignfile(file, foffset))
1321 return 0;
1335 1322
1336 return 1; 1323 return 1;
1337} 1324}
1338#undef DUMP_WRITE 1325#undef DUMP_WRITE
1339#undef DUMP_SEEK
1340
1341#define DUMP_WRITE(addr, nr) \
1342 if ((size += (nr)) > cprm->limit || \
1343 !dump_write(cprm->file, (addr), (nr))) \
1344 goto end_coredump;
1345 1326
1346static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) 1327static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs)
1347{ 1328{
@@ -1393,7 +1374,7 @@ static inline void fill_note(struct memelfnote *note, const char *name, int type
1393 1374
1394/* 1375/*
1395 * fill up all the fields in prstatus from the given task struct, except 1376 * fill up all the fields in prstatus from the given task struct, except
1396 * registers which need to be filled up seperately. 1377 * registers which need to be filled up separately.
1397 */ 1378 */
1398static void fill_prstatus(struct elf_prstatus *prstatus, 1379static void fill_prstatus(struct elf_prstatus *prstatus,
1399 struct task_struct *p, long signr) 1380 struct task_struct *p, long signr)
@@ -1524,6 +1505,22 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
1524 return sz; 1505 return sz;
1525} 1506}
1526 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
1527/* 1524/*
1528 * dump the segments for an MMU process 1525 * dump the segments for an MMU process
1529 */ 1526 */
@@ -1552,7 +1549,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
1552 err = -EIO; 1549 err = -EIO;
1553 kunmap(page); 1550 kunmap(page);
1554 page_cache_release(page); 1551 page_cache_release(page);
1555 } else if (!dump_seek(file, file->f_pos + PAGE_SIZE)) 1552 } else if (!dump_seek(file, PAGE_SIZE))
1556 err = -EFBIG; 1553 err = -EFBIG;
1557 if (err) 1554 if (err)
1558 goto out; 1555 goto out;
@@ -1588,6 +1585,17 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
1588} 1585}
1589#endif 1586#endif
1590 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 = vma->vm_next)
1594 if (maydump(vma, mm_flags))
1595 size += vma->vm_end - vma->vm_start;
1596 return size;
1597}
1598
1591/* 1599/*
1592 * Actual dumper 1600 * Actual dumper
1593 * 1601 *
@@ -1605,7 +1613,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1605 int i; 1613 int i;
1606 struct vm_area_struct *vma; 1614 struct vm_area_struct *vma;
1607 struct elfhdr *elf = NULL; 1615 struct elfhdr *elf = NULL;
1608 loff_t offset = 0, dataoff; 1616 loff_t offset = 0, dataoff, foffset;
1609 int numnote; 1617 int numnote;
1610 struct memelfnote *notes = NULL; 1618 struct memelfnote *notes = NULL;
1611 struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ 1619 struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
@@ -1618,7 +1626,10 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1618#endif 1626#endif
1619 int thread_status_size = 0; 1627 int thread_status_size = 0;
1620 elf_addr_t *auxv; 1628 elf_addr_t *auxv;
1621 unsigned long mm_flags; 1629 struct elf_phdr *phdr4note = NULL;
1630 struct elf_shdr *shdr4extnum = NULL;
1631 Elf_Half e_phnum;
1632 elf_addr_t e_shoff;
1622 1633
1623 /* 1634 /*
1624 * We no longer stop all VM operations. 1635 * We no longer stop all VM operations.
@@ -1683,12 +1694,18 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1683 elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); 1694 elf_core_copy_regs(&prstatus->pr_reg, cprm->regs);
1684 1695
1685 segs = current->mm->map_count; 1696 segs = current->mm->map_count;
1686#ifdef ELF_CORE_EXTRA_PHDRS 1697 segs += elf_core_extra_phdrs();
1687 segs += ELF_CORE_EXTRA_PHDRS; 1698
1688#endif 1699 /* for notes section */
1700 segs++;
1701
1702 /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
1703 * this, kernel supports extended numbering. Have a look at
1704 * include/linux/elf.h for further information. */
1705 e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
1689 1706
1690 /* Set up header */ 1707 /* Set up header */
1691 fill_elf_fdpic_header(elf, segs + 1); /* including notes section */ 1708 fill_elf_fdpic_header(elf, e_phnum);
1692 1709
1693 has_dumped = 1; 1710 has_dumped = 1;
1694 current->flags |= PF_DUMPCORE; 1711 current->flags |= PF_DUMPCORE;
@@ -1727,13 +1744,12 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1727 fs = get_fs(); 1744 fs = get_fs();
1728 set_fs(KERNEL_DS); 1745 set_fs(KERNEL_DS);
1729 1746
1730 DUMP_WRITE(elf, sizeof(*elf));
1731 offset += sizeof(*elf); /* Elf header */ 1747 offset += sizeof(*elf); /* Elf header */
1732 offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ 1748 offset += segs * sizeof(struct elf_phdr); /* Program headers */
1749 foffset = offset;
1733 1750
1734 /* Write notes phdr entry */ 1751 /* Write notes phdr entry */
1735 { 1752 {
1736 struct elf_phdr phdr;
1737 int sz = 0; 1753 int sz = 0;
1738 1754
1739 for (i = 0; i < numnote; i++) 1755 for (i = 0; i < numnote; i++)
@@ -1741,20 +1757,38 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1741 1757
1742 sz += thread_status_size; 1758 sz += thread_status_size;
1743 1759
1744 fill_elf_note_phdr(&phdr, sz, offset); 1760 phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
1761 if (!phdr4note)
1762 goto end_coredump;
1763
1764 fill_elf_note_phdr(phdr4note, sz, offset);
1745 offset += sz; 1765 offset += sz;
1746 DUMP_WRITE(&phdr, sizeof(phdr));
1747 } 1766 }
1748 1767
1749 /* Page-align dumped data */ 1768 /* Page-align dumped data */
1750 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); 1769 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
1751 1770
1752 /* 1771 offset += elf_core_vma_data_size(cprm->mm_flags);
1753 * We must use the same mm->flags while dumping core to avoid 1772 offset += elf_core_extra_data_size();
1754 * inconsistency between the program headers and bodies, otherwise an 1773 e_shoff = offset;
1755 * unusable core file can be generated. 1774
1756 */ 1775 if (e_phnum == PN_XNUM) {
1757 mm_flags = current->mm->flags; 1776 shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
1777 if (!shdr4extnum)
1778 goto end_coredump;
1779 fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
1780 }
1781
1782 offset = dataoff;
1783
1784 size += sizeof(*elf);
1785 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
1786 goto end_coredump;
1787
1788 size += sizeof(*phdr4note);
1789 if (size > cprm->limit
1790 || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
1791 goto end_coredump;
1758 1792
1759 /* write program headers for segments dump */ 1793 /* write program headers for segments dump */
1760 for (vma = current->mm->mmap; vma; vma = vma->vm_next) { 1794 for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
@@ -1767,7 +1801,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1767 phdr.p_offset = offset; 1801 phdr.p_offset = offset;
1768 phdr.p_vaddr = vma->vm_start; 1802 phdr.p_vaddr = vma->vm_start;
1769 phdr.p_paddr = 0; 1803 phdr.p_paddr = 0;
1770 phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; 1804 phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0;
1771 phdr.p_memsz = sz; 1805 phdr.p_memsz = sz;
1772 offset += phdr.p_filesz; 1806 offset += phdr.p_filesz;
1773 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; 1807 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1777,16 +1811,18 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1777 phdr.p_flags |= PF_X; 1811 phdr.p_flags |= PF_X;
1778 phdr.p_align = ELF_EXEC_PAGESIZE; 1812 phdr.p_align = ELF_EXEC_PAGESIZE;
1779 1813
1780 DUMP_WRITE(&phdr, sizeof(phdr)); 1814 size += sizeof(phdr);
1815 if (size > cprm->limit
1816 || !dump_write(cprm->file, &phdr, sizeof(phdr)))
1817 goto end_coredump;
1781 } 1818 }
1782 1819
1783#ifdef ELF_CORE_WRITE_EXTRA_PHDRS 1820 if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit))
1784 ELF_CORE_WRITE_EXTRA_PHDRS; 1821 goto end_coredump;
1785#endif
1786 1822
1787 /* write out the notes section */ 1823 /* write out the notes section */
1788 for (i = 0; i < numnote; i++) 1824 for (i = 0; i < numnote; i++)
1789 if (!writenote(notes + i, cprm->file)) 1825 if (!writenote(notes + i, cprm->file, &foffset))
1790 goto end_coredump; 1826 goto end_coredump;
1791 1827
1792 /* write out the thread status notes section */ 1828 /* write out the thread status notes section */
@@ -1795,20 +1831,27 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1795 list_entry(t, struct elf_thread_status, list); 1831 list_entry(t, struct elf_thread_status, list);
1796 1832
1797 for (i = 0; i < tmp->num_notes; i++) 1833 for (i = 0; i < tmp->num_notes; i++)
1798 if (!writenote(&tmp->notes[i], cprm->file)) 1834 if (!writenote(&tmp->notes[i], cprm->file, &foffset))
1799 goto end_coredump; 1835 goto end_coredump;
1800 } 1836 }
1801 1837
1802 if (!dump_seek(cprm->file, dataoff)) 1838 if (!dump_seek(cprm->file, dataoff - foffset))
1803 goto end_coredump; 1839 goto end_coredump;
1804 1840
1805 if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit, 1841 if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit,
1806 mm_flags) < 0) 1842 cprm->mm_flags) < 0)
1807 goto end_coredump; 1843 goto end_coredump;
1808 1844
1809#ifdef ELF_CORE_WRITE_EXTRA_DATA 1845 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
1810 ELF_CORE_WRITE_EXTRA_DATA; 1846 goto end_coredump;
1811#endif 1847
1848 if (e_phnum == PN_XNUM) {
1849 size += sizeof(*shdr4extnum);
1850 if (size > cprm->limit
1851 || !dump_write(cprm->file, shdr4extnum,
1852 sizeof(*shdr4extnum)))
1853 goto end_coredump;
1854 }
1812 1855
1813 if (cprm->file->f_pos != offset) { 1856 if (cprm->file->f_pos != offset) {
1814 /* Sanity check */ 1857 /* Sanity check */
@@ -1826,7 +1869,7 @@ cleanup:
1826 list_del(tmp); 1869 list_del(tmp);
1827 kfree(list_entry(tmp, struct elf_thread_status, list)); 1870 kfree(list_entry(tmp, struct elf_thread_status, list));
1828 } 1871 }
1829 1872 kfree(phdr4note);
1830 kfree(elf); 1873 kfree(elf);
1831 kfree(prstatus); 1874 kfree(prstatus);
1832 kfree(psinfo); 1875 kfree(psinfo);