diff options
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 152 |
1 files changed, 47 insertions, 105 deletions
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index c166f325a183..fe2a643ee005 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -111,7 +111,7 @@ static int is_elf_fdpic(struct elfhdr *hdr, struct file *file) | |||
111 | return 0; | 111 | return 0; |
112 | if (!elf_check_arch(hdr) || !elf_check_fdpic(hdr)) | 112 | if (!elf_check_arch(hdr) || !elf_check_fdpic(hdr)) |
113 | return 0; | 113 | return 0; |
114 | if (!file->f_op || !file->f_op->mmap) | 114 | if (!file->f_op->mmap) |
115 | return 0; | 115 | return 0; |
116 | return 1; | 116 | return 1; |
117 | } | 117 | } |
@@ -1267,35 +1267,17 @@ static int notesize(struct memelfnote *en) | |||
1267 | 1267 | ||
1268 | /* #define DEBUG */ | 1268 | /* #define DEBUG */ |
1269 | 1269 | ||
1270 | #define DUMP_WRITE(addr, nr, foffset) \ | 1270 | static int writenote(struct memelfnote *men, struct coredump_params *cprm) |
1271 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) | ||
1272 | |||
1273 | static int alignfile(struct file *file, loff_t *foffset) | ||
1274 | { | ||
1275 | static const char buf[4] = { 0, }; | ||
1276 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | ||
1277 | return 1; | ||
1278 | } | ||
1279 | |||
1280 | static int writenote(struct memelfnote *men, struct file *file, | ||
1281 | loff_t *foffset) | ||
1282 | { | 1271 | { |
1283 | struct elf_note en; | 1272 | struct elf_note en; |
1284 | en.n_namesz = strlen(men->name) + 1; | 1273 | en.n_namesz = strlen(men->name) + 1; |
1285 | en.n_descsz = men->datasz; | 1274 | en.n_descsz = men->datasz; |
1286 | en.n_type = men->type; | 1275 | en.n_type = men->type; |
1287 | 1276 | ||
1288 | DUMP_WRITE(&en, sizeof(en), foffset); | 1277 | return dump_emit(cprm, &en, sizeof(en)) && |
1289 | DUMP_WRITE(men->name, en.n_namesz, foffset); | 1278 | dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) && |
1290 | if (!alignfile(file, foffset)) | 1279 | dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4); |
1291 | return 0; | ||
1292 | DUMP_WRITE(men->data, men->datasz, foffset); | ||
1293 | if (!alignfile(file, foffset)) | ||
1294 | return 0; | ||
1295 | |||
1296 | return 1; | ||
1297 | } | 1280 | } |
1298 | #undef DUMP_WRITE | ||
1299 | 1281 | ||
1300 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) | 1282 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) |
1301 | { | 1283 | { |
@@ -1500,66 +1482,40 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, | |||
1500 | /* | 1482 | /* |
1501 | * dump the segments for an MMU process | 1483 | * dump the segments for an MMU process |
1502 | */ | 1484 | */ |
1503 | #ifdef CONFIG_MMU | 1485 | static bool elf_fdpic_dump_segments(struct coredump_params *cprm) |
1504 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, | ||
1505 | unsigned long *limit, unsigned long mm_flags) | ||
1506 | { | 1486 | { |
1507 | struct vm_area_struct *vma; | 1487 | struct vm_area_struct *vma; |
1508 | int err = 0; | ||
1509 | 1488 | ||
1510 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | 1489 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
1511 | unsigned long addr; | 1490 | unsigned long addr; |
1512 | 1491 | ||
1513 | if (!maydump(vma, mm_flags)) | 1492 | if (!maydump(vma, cprm->mm_flags)) |
1514 | continue; | 1493 | continue; |
1515 | 1494 | ||
1495 | #ifdef CONFIG_MMU | ||
1516 | for (addr = vma->vm_start; addr < vma->vm_end; | 1496 | for (addr = vma->vm_start; addr < vma->vm_end; |
1517 | addr += PAGE_SIZE) { | 1497 | addr += PAGE_SIZE) { |
1498 | bool res; | ||
1518 | struct page *page = get_dump_page(addr); | 1499 | struct page *page = get_dump_page(addr); |
1519 | if (page) { | 1500 | if (page) { |
1520 | void *kaddr = kmap(page); | 1501 | void *kaddr = kmap(page); |
1521 | *size += PAGE_SIZE; | 1502 | res = dump_emit(cprm, kaddr, PAGE_SIZE); |
1522 | if (*size > *limit) | ||
1523 | err = -EFBIG; | ||
1524 | else if (!dump_write(file, kaddr, PAGE_SIZE)) | ||
1525 | err = -EIO; | ||
1526 | kunmap(page); | 1503 | kunmap(page); |
1527 | page_cache_release(page); | 1504 | page_cache_release(page); |
1528 | } else if (!dump_seek(file, PAGE_SIZE)) | 1505 | } else { |
1529 | err = -EFBIG; | 1506 | res = dump_skip(cprm, PAGE_SIZE); |
1530 | if (err) | 1507 | } |
1531 | goto out; | 1508 | if (!res) |
1509 | return false; | ||
1532 | } | 1510 | } |
1533 | } | 1511 | #else |
1534 | out: | 1512 | if (!dump_emit(cprm, (void *) vma->vm_start, |
1535 | return err; | ||
1536 | } | ||
1537 | #endif | ||
1538 | |||
1539 | /* | ||
1540 | * dump the segments for a NOMMU process | ||
1541 | */ | ||
1542 | #ifndef CONFIG_MMU | ||
1543 | static int elf_fdpic_dump_segments(struct file *file, size_t *size, | ||
1544 | unsigned long *limit, unsigned long mm_flags) | ||
1545 | { | ||
1546 | struct vm_area_struct *vma; | ||
1547 | |||
1548 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | ||
1549 | if (!maydump(vma, mm_flags)) | ||
1550 | continue; | ||
1551 | |||
1552 | if ((*size += PAGE_SIZE) > *limit) | ||
1553 | return -EFBIG; | ||
1554 | |||
1555 | if (!dump_write(file, (void *) vma->vm_start, | ||
1556 | vma->vm_end - vma->vm_start)) | 1513 | vma->vm_end - vma->vm_start)) |
1557 | return -EIO; | 1514 | return false; |
1515 | #endif | ||
1558 | } | 1516 | } |
1559 | 1517 | return true; | |
1560 | return 0; | ||
1561 | } | 1518 | } |
1562 | #endif | ||
1563 | 1519 | ||
1564 | static size_t elf_core_vma_data_size(unsigned long mm_flags) | 1520 | static size_t elf_core_vma_data_size(unsigned long mm_flags) |
1565 | { | 1521 | { |
@@ -1585,11 +1541,10 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1585 | int has_dumped = 0; | 1541 | int has_dumped = 0; |
1586 | mm_segment_t fs; | 1542 | mm_segment_t fs; |
1587 | int segs; | 1543 | int segs; |
1588 | size_t size = 0; | ||
1589 | int i; | 1544 | int i; |
1590 | struct vm_area_struct *vma; | 1545 | struct vm_area_struct *vma; |
1591 | struct elfhdr *elf = NULL; | 1546 | struct elfhdr *elf = NULL; |
1592 | loff_t offset = 0, dataoff, foffset; | 1547 | loff_t offset = 0, dataoff; |
1593 | int numnote; | 1548 | int numnote; |
1594 | struct memelfnote *notes = NULL; | 1549 | struct memelfnote *notes = NULL; |
1595 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ | 1550 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ |
@@ -1606,6 +1561,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1606 | struct elf_shdr *shdr4extnum = NULL; | 1561 | struct elf_shdr *shdr4extnum = NULL; |
1607 | Elf_Half e_phnum; | 1562 | Elf_Half e_phnum; |
1608 | elf_addr_t e_shoff; | 1563 | elf_addr_t e_shoff; |
1564 | struct core_thread *ct; | ||
1565 | struct elf_thread_status *tmp; | ||
1609 | 1566 | ||
1610 | /* | 1567 | /* |
1611 | * We no longer stop all VM operations. | 1568 | * We no longer stop all VM operations. |
@@ -1641,28 +1598,23 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1641 | goto cleanup; | 1598 | goto cleanup; |
1642 | #endif | 1599 | #endif |
1643 | 1600 | ||
1644 | if (cprm->siginfo->si_signo) { | 1601 | for (ct = current->mm->core_state->dumper.next; |
1645 | struct core_thread *ct; | 1602 | ct; ct = ct->next) { |
1646 | struct elf_thread_status *tmp; | 1603 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
1647 | 1604 | if (!tmp) | |
1648 | for (ct = current->mm->core_state->dumper.next; | 1605 | goto cleanup; |
1649 | ct; ct = ct->next) { | ||
1650 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | ||
1651 | if (!tmp) | ||
1652 | goto cleanup; | ||
1653 | 1606 | ||
1654 | tmp->thread = ct->task; | 1607 | tmp->thread = ct->task; |
1655 | list_add(&tmp->list, &thread_list); | 1608 | list_add(&tmp->list, &thread_list); |
1656 | } | 1609 | } |
1657 | 1610 | ||
1658 | list_for_each(t, &thread_list) { | 1611 | list_for_each(t, &thread_list) { |
1659 | struct elf_thread_status *tmp; | 1612 | struct elf_thread_status *tmp; |
1660 | int sz; | 1613 | int sz; |
1661 | 1614 | ||
1662 | tmp = list_entry(t, struct elf_thread_status, list); | 1615 | tmp = list_entry(t, struct elf_thread_status, list); |
1663 | sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); | 1616 | sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); |
1664 | thread_status_size += sz; | 1617 | thread_status_size += sz; |
1665 | } | ||
1666 | } | 1618 | } |
1667 | 1619 | ||
1668 | /* now collect the dump for the current */ | 1620 | /* now collect the dump for the current */ |
@@ -1720,7 +1672,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1720 | 1672 | ||
1721 | offset += sizeof(*elf); /* Elf header */ | 1673 | offset += sizeof(*elf); /* Elf header */ |
1722 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ | 1674 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
1723 | foffset = offset; | ||
1724 | 1675 | ||
1725 | /* Write notes phdr entry */ | 1676 | /* Write notes phdr entry */ |
1726 | { | 1677 | { |
@@ -1755,13 +1706,10 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1755 | 1706 | ||
1756 | offset = dataoff; | 1707 | offset = dataoff; |
1757 | 1708 | ||
1758 | size += sizeof(*elf); | 1709 | if (!dump_emit(cprm, elf, sizeof(*elf))) |
1759 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | ||
1760 | goto end_coredump; | 1710 | goto end_coredump; |
1761 | 1711 | ||
1762 | size += sizeof(*phdr4note); | 1712 | if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) |
1763 | if (size > cprm->limit | ||
1764 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) | ||
1765 | goto end_coredump; | 1713 | goto end_coredump; |
1766 | 1714 | ||
1767 | /* write program headers for segments dump */ | 1715 | /* write program headers for segments dump */ |
@@ -1785,18 +1733,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1785 | phdr.p_flags |= PF_X; | 1733 | phdr.p_flags |= PF_X; |
1786 | phdr.p_align = ELF_EXEC_PAGESIZE; | 1734 | phdr.p_align = ELF_EXEC_PAGESIZE; |
1787 | 1735 | ||
1788 | size += sizeof(phdr); | 1736 | if (!dump_emit(cprm, &phdr, sizeof(phdr))) |
1789 | if (size > cprm->limit | ||
1790 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) | ||
1791 | goto end_coredump; | 1737 | goto end_coredump; |
1792 | } | 1738 | } |
1793 | 1739 | ||
1794 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) | 1740 | if (!elf_core_write_extra_phdrs(cprm, offset)) |
1795 | goto end_coredump; | 1741 | goto end_coredump; |
1796 | 1742 | ||
1797 | /* write out the notes section */ | 1743 | /* write out the notes section */ |
1798 | for (i = 0; i < numnote; i++) | 1744 | for (i = 0; i < numnote; i++) |
1799 | if (!writenote(notes + i, cprm->file, &foffset)) | 1745 | if (!writenote(notes + i, cprm)) |
1800 | goto end_coredump; | 1746 | goto end_coredump; |
1801 | 1747 | ||
1802 | /* write out the thread status notes section */ | 1748 | /* write out the thread status notes section */ |
@@ -1805,25 +1751,21 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1805 | list_entry(t, struct elf_thread_status, list); | 1751 | list_entry(t, struct elf_thread_status, list); |
1806 | 1752 | ||
1807 | for (i = 0; i < tmp->num_notes; i++) | 1753 | for (i = 0; i < tmp->num_notes; i++) |
1808 | if (!writenote(&tmp->notes[i], cprm->file, &foffset)) | 1754 | if (!writenote(&tmp->notes[i], cprm)) |
1809 | goto end_coredump; | 1755 | goto end_coredump; |
1810 | } | 1756 | } |
1811 | 1757 | ||
1812 | if (!dump_seek(cprm->file, dataoff - foffset)) | 1758 | if (!dump_skip(cprm, dataoff - cprm->written)) |
1813 | goto end_coredump; | 1759 | goto end_coredump; |
1814 | 1760 | ||
1815 | if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit, | 1761 | if (!elf_fdpic_dump_segments(cprm)) |
1816 | cprm->mm_flags) < 0) | ||
1817 | goto end_coredump; | 1762 | goto end_coredump; |
1818 | 1763 | ||
1819 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 1764 | if (!elf_core_write_extra_data(cprm)) |
1820 | goto end_coredump; | 1765 | goto end_coredump; |
1821 | 1766 | ||
1822 | if (e_phnum == PN_XNUM) { | 1767 | if (e_phnum == PN_XNUM) { |
1823 | size += sizeof(*shdr4extnum); | 1768 | if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum))) |
1824 | if (size > cprm->limit | ||
1825 | || !dump_write(cprm->file, shdr4extnum, | ||
1826 | sizeof(*shdr4extnum))) | ||
1827 | goto end_coredump; | 1769 | goto end_coredump; |
1828 | } | 1770 | } |
1829 | 1771 | ||