diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 172 |
1 files changed, 143 insertions, 29 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 1b52956afe33..e800dec958c3 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/compiler.h> | 27 | #include <linux/compiler.h> |
28 | #include <linux/highmem.h> | 28 | #include <linux/highmem.h> |
29 | #include <linux/pagemap.h> | 29 | #include <linux/pagemap.h> |
30 | #include <linux/vmalloc.h> | ||
30 | #include <linux/security.h> | 31 | #include <linux/security.h> |
31 | #include <linux/random.h> | 32 | #include <linux/random.h> |
32 | #include <linux/elf.h> | 33 | #include <linux/elf.h> |
@@ -37,6 +38,13 @@ | |||
37 | #include <asm/page.h> | 38 | #include <asm/page.h> |
38 | #include <asm/exec.h> | 39 | #include <asm/exec.h> |
39 | 40 | ||
41 | #ifndef user_long_t | ||
42 | #define user_long_t long | ||
43 | #endif | ||
44 | #ifndef user_siginfo_t | ||
45 | #define user_siginfo_t siginfo_t | ||
46 | #endif | ||
47 | |||
40 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 48 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
41 | static int load_elf_library(struct file *); | 49 | static int load_elf_library(struct file *); |
42 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, | 50 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
@@ -881,7 +889,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
881 | } | 889 | } |
882 | 890 | ||
883 | if (elf_interpreter) { | 891 | if (elf_interpreter) { |
884 | unsigned long uninitialized_var(interp_map_addr); | 892 | unsigned long interp_map_addr = 0; |
885 | 893 | ||
886 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 894 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
887 | interpreter, | 895 | interpreter, |
@@ -1115,7 +1123,7 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, | |||
1115 | if (always_dump_vma(vma)) | 1123 | if (always_dump_vma(vma)) |
1116 | goto whole; | 1124 | goto whole; |
1117 | 1125 | ||
1118 | if (vma->vm_flags & VM_NODUMP) | 1126 | if (vma->vm_flags & VM_DONTDUMP) |
1119 | return 0; | 1127 | return 0; |
1120 | 1128 | ||
1121 | /* Hugetlb memory check */ | 1129 | /* Hugetlb memory check */ |
@@ -1127,7 +1135,7 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, | |||
1127 | } | 1135 | } |
1128 | 1136 | ||
1129 | /* Do not dump I/O mapped devices or special mappings */ | 1137 | /* Do not dump I/O mapped devices or special mappings */ |
1130 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1138 | if (vma->vm_flags & VM_IO) |
1131 | return 0; | 1139 | return 0; |
1132 | 1140 | ||
1133 | /* By default, dump shared memory if mapped from an anonymous file. */ | 1141 | /* By default, dump shared memory if mapped from an anonymous file. */ |
@@ -1372,6 +1380,103 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) | |||
1372 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); | 1380 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); |
1373 | } | 1381 | } |
1374 | 1382 | ||
1383 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, | ||
1384 | siginfo_t *siginfo) | ||
1385 | { | ||
1386 | mm_segment_t old_fs = get_fs(); | ||
1387 | set_fs(KERNEL_DS); | ||
1388 | copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); | ||
1389 | set_fs(old_fs); | ||
1390 | fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); | ||
1391 | } | ||
1392 | |||
1393 | #define MAX_FILE_NOTE_SIZE (4*1024*1024) | ||
1394 | /* | ||
1395 | * Format of NT_FILE note: | ||
1396 | * | ||
1397 | * long count -- how many files are mapped | ||
1398 | * long page_size -- units for file_ofs | ||
1399 | * array of [COUNT] elements of | ||
1400 | * long start | ||
1401 | * long end | ||
1402 | * long file_ofs | ||
1403 | * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... | ||
1404 | */ | ||
1405 | static void fill_files_note(struct memelfnote *note) | ||
1406 | { | ||
1407 | struct vm_area_struct *vma; | ||
1408 | unsigned count, size, names_ofs, remaining, n; | ||
1409 | user_long_t *data; | ||
1410 | user_long_t *start_end_ofs; | ||
1411 | char *name_base, *name_curpos; | ||
1412 | |||
1413 | /* *Estimated* file count and total data size needed */ | ||
1414 | count = current->mm->map_count; | ||
1415 | size = count * 64; | ||
1416 | |||
1417 | names_ofs = (2 + 3 * count) * sizeof(data[0]); | ||
1418 | alloc: | ||
1419 | if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ | ||
1420 | goto err; | ||
1421 | size = round_up(size, PAGE_SIZE); | ||
1422 | data = vmalloc(size); | ||
1423 | if (!data) | ||
1424 | goto err; | ||
1425 | |||
1426 | start_end_ofs = data + 2; | ||
1427 | name_base = name_curpos = ((char *)data) + names_ofs; | ||
1428 | remaining = size - names_ofs; | ||
1429 | count = 0; | ||
1430 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
1431 | struct file *file; | ||
1432 | const char *filename; | ||
1433 | |||
1434 | file = vma->vm_file; | ||
1435 | if (!file) | ||
1436 | continue; | ||
1437 | filename = d_path(&file->f_path, name_curpos, remaining); | ||
1438 | if (IS_ERR(filename)) { | ||
1439 | if (PTR_ERR(filename) == -ENAMETOOLONG) { | ||
1440 | vfree(data); | ||
1441 | size = size * 5 / 4; | ||
1442 | goto alloc; | ||
1443 | } | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | /* d_path() fills at the end, move name down */ | ||
1448 | /* n = strlen(filename) + 1: */ | ||
1449 | n = (name_curpos + remaining) - filename; | ||
1450 | remaining = filename - name_curpos; | ||
1451 | memmove(name_curpos, filename, n); | ||
1452 | name_curpos += n; | ||
1453 | |||
1454 | *start_end_ofs++ = vma->vm_start; | ||
1455 | *start_end_ofs++ = vma->vm_end; | ||
1456 | *start_end_ofs++ = vma->vm_pgoff; | ||
1457 | count++; | ||
1458 | } | ||
1459 | |||
1460 | /* Now we know exact count of files, can store it */ | ||
1461 | data[0] = count; | ||
1462 | data[1] = PAGE_SIZE; | ||
1463 | /* | ||
1464 | * Count usually is less than current->mm->map_count, | ||
1465 | * we need to move filenames down. | ||
1466 | */ | ||
1467 | n = current->mm->map_count - count; | ||
1468 | if (n != 0) { | ||
1469 | unsigned shift_bytes = n * 3 * sizeof(data[0]); | ||
1470 | memmove(name_base - shift_bytes, name_base, | ||
1471 | name_curpos - name_base); | ||
1472 | name_curpos -= shift_bytes; | ||
1473 | } | ||
1474 | |||
1475 | size = name_curpos - (char *)data; | ||
1476 | fill_note(note, "CORE", NT_FILE, size, data); | ||
1477 | err: ; | ||
1478 | } | ||
1479 | |||
1375 | #ifdef CORE_DUMP_USE_REGSET | 1480 | #ifdef CORE_DUMP_USE_REGSET |
1376 | #include <linux/regset.h> | 1481 | #include <linux/regset.h> |
1377 | 1482 | ||
@@ -1385,7 +1490,10 @@ struct elf_thread_core_info { | |||
1385 | struct elf_note_info { | 1490 | struct elf_note_info { |
1386 | struct elf_thread_core_info *thread; | 1491 | struct elf_thread_core_info *thread; |
1387 | struct memelfnote psinfo; | 1492 | struct memelfnote psinfo; |
1493 | struct memelfnote signote; | ||
1388 | struct memelfnote auxv; | 1494 | struct memelfnote auxv; |
1495 | struct memelfnote files; | ||
1496 | user_siginfo_t csigdata; | ||
1389 | size_t size; | 1497 | size_t size; |
1390 | int thread_notes; | 1498 | int thread_notes; |
1391 | }; | 1499 | }; |
@@ -1480,7 +1588,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1480 | 1588 | ||
1481 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1589 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1482 | struct elf_note_info *info, | 1590 | struct elf_note_info *info, |
1483 | long signr, struct pt_regs *regs) | 1591 | siginfo_t *siginfo, struct pt_regs *regs) |
1484 | { | 1592 | { |
1485 | struct task_struct *dump_task = current; | 1593 | struct task_struct *dump_task = current; |
1486 | const struct user_regset_view *view = task_user_regset_view(dump_task); | 1594 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
@@ -1550,7 +1658,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1550 | * Now fill in each thread's information. | 1658 | * Now fill in each thread's information. |
1551 | */ | 1659 | */ |
1552 | for (t = info->thread; t != NULL; t = t->next) | 1660 | for (t = info->thread; t != NULL; t = t->next) |
1553 | if (!fill_thread_core_info(t, view, signr, &info->size)) | 1661 | if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) |
1554 | return 0; | 1662 | return 0; |
1555 | 1663 | ||
1556 | /* | 1664 | /* |
@@ -1559,9 +1667,15 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1559 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); | 1667 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); |
1560 | info->size += notesize(&info->psinfo); | 1668 | info->size += notesize(&info->psinfo); |
1561 | 1669 | ||
1670 | fill_siginfo_note(&info->signote, &info->csigdata, siginfo); | ||
1671 | info->size += notesize(&info->signote); | ||
1672 | |||
1562 | fill_auxv_note(&info->auxv, current->mm); | 1673 | fill_auxv_note(&info->auxv, current->mm); |
1563 | info->size += notesize(&info->auxv); | 1674 | info->size += notesize(&info->auxv); |
1564 | 1675 | ||
1676 | fill_files_note(&info->files); | ||
1677 | info->size += notesize(&info->files); | ||
1678 | |||
1565 | return 1; | 1679 | return 1; |
1566 | } | 1680 | } |
1567 | 1681 | ||
@@ -1588,8 +1702,12 @@ static int write_note_info(struct elf_note_info *info, | |||
1588 | 1702 | ||
1589 | if (first && !writenote(&info->psinfo, file, foffset)) | 1703 | if (first && !writenote(&info->psinfo, file, foffset)) |
1590 | return 0; | 1704 | return 0; |
1705 | if (first && !writenote(&info->signote, file, foffset)) | ||
1706 | return 0; | ||
1591 | if (first && !writenote(&info->auxv, file, foffset)) | 1707 | if (first && !writenote(&info->auxv, file, foffset)) |
1592 | return 0; | 1708 | return 0; |
1709 | if (first && !writenote(&info->files, file, foffset)) | ||
1710 | return 0; | ||
1593 | 1711 | ||
1594 | for (i = 1; i < info->thread_notes; ++i) | 1712 | for (i = 1; i < info->thread_notes; ++i) |
1595 | if (t->notes[i].data && | 1713 | if (t->notes[i].data && |
@@ -1616,6 +1734,7 @@ static void free_note_info(struct elf_note_info *info) | |||
1616 | kfree(t); | 1734 | kfree(t); |
1617 | } | 1735 | } |
1618 | kfree(info->psinfo.data); | 1736 | kfree(info->psinfo.data); |
1737 | vfree(info->files.data); | ||
1619 | } | 1738 | } |
1620 | 1739 | ||
1621 | #else | 1740 | #else |
@@ -1681,6 +1800,7 @@ struct elf_note_info { | |||
1681 | #ifdef ELF_CORE_COPY_XFPREGS | 1800 | #ifdef ELF_CORE_COPY_XFPREGS |
1682 | elf_fpxregset_t *xfpu; | 1801 | elf_fpxregset_t *xfpu; |
1683 | #endif | 1802 | #endif |
1803 | user_siginfo_t csigdata; | ||
1684 | int thread_status_size; | 1804 | int thread_status_size; |
1685 | int numnote; | 1805 | int numnote; |
1686 | }; | 1806 | }; |
@@ -1690,48 +1810,37 @@ static int elf_note_info_init(struct elf_note_info *info) | |||
1690 | memset(info, 0, sizeof(*info)); | 1810 | memset(info, 0, sizeof(*info)); |
1691 | INIT_LIST_HEAD(&info->thread_list); | 1811 | INIT_LIST_HEAD(&info->thread_list); |
1692 | 1812 | ||
1693 | /* Allocate space for six ELF notes */ | 1813 | /* Allocate space for ELF notes */ |
1694 | info->notes = kmalloc(6 * sizeof(struct memelfnote), GFP_KERNEL); | 1814 | info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL); |
1695 | if (!info->notes) | 1815 | if (!info->notes) |
1696 | return 0; | 1816 | return 0; |
1697 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); | 1817 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); |
1698 | if (!info->psinfo) | 1818 | if (!info->psinfo) |
1699 | goto notes_free; | 1819 | return 0; |
1700 | info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); | 1820 | info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); |
1701 | if (!info->prstatus) | 1821 | if (!info->prstatus) |
1702 | goto psinfo_free; | 1822 | return 0; |
1703 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); | 1823 | info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); |
1704 | if (!info->fpu) | 1824 | if (!info->fpu) |
1705 | goto prstatus_free; | 1825 | return 0; |
1706 | #ifdef ELF_CORE_COPY_XFPREGS | 1826 | #ifdef ELF_CORE_COPY_XFPREGS |
1707 | info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); | 1827 | info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); |
1708 | if (!info->xfpu) | 1828 | if (!info->xfpu) |
1709 | goto fpu_free; | 1829 | return 0; |
1710 | #endif | 1830 | #endif |
1711 | return 1; | 1831 | return 1; |
1712 | #ifdef ELF_CORE_COPY_XFPREGS | ||
1713 | fpu_free: | ||
1714 | kfree(info->fpu); | ||
1715 | #endif | ||
1716 | prstatus_free: | ||
1717 | kfree(info->prstatus); | ||
1718 | psinfo_free: | ||
1719 | kfree(info->psinfo); | ||
1720 | notes_free: | ||
1721 | kfree(info->notes); | ||
1722 | return 0; | ||
1723 | } | 1832 | } |
1724 | 1833 | ||
1725 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1834 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1726 | struct elf_note_info *info, | 1835 | struct elf_note_info *info, |
1727 | long signr, struct pt_regs *regs) | 1836 | siginfo_t *siginfo, struct pt_regs *regs) |
1728 | { | 1837 | { |
1729 | struct list_head *t; | 1838 | struct list_head *t; |
1730 | 1839 | ||
1731 | if (!elf_note_info_init(info)) | 1840 | if (!elf_note_info_init(info)) |
1732 | return 0; | 1841 | return 0; |
1733 | 1842 | ||
1734 | if (signr) { | 1843 | if (siginfo->si_signo) { |
1735 | struct core_thread *ct; | 1844 | struct core_thread *ct; |
1736 | struct elf_thread_status *ets; | 1845 | struct elf_thread_status *ets; |
1737 | 1846 | ||
@@ -1749,13 +1858,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1749 | int sz; | 1858 | int sz; |
1750 | 1859 | ||
1751 | ets = list_entry(t, struct elf_thread_status, list); | 1860 | ets = list_entry(t, struct elf_thread_status, list); |
1752 | sz = elf_dump_thread_status(signr, ets); | 1861 | sz = elf_dump_thread_status(siginfo->si_signo, ets); |
1753 | info->thread_status_size += sz; | 1862 | info->thread_status_size += sz; |
1754 | } | 1863 | } |
1755 | } | 1864 | } |
1756 | /* now collect the dump for the current */ | 1865 | /* now collect the dump for the current */ |
1757 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | 1866 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
1758 | fill_prstatus(info->prstatus, current, signr); | 1867 | fill_prstatus(info->prstatus, current, siginfo->si_signo); |
1759 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); | 1868 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
1760 | 1869 | ||
1761 | /* Set up header */ | 1870 | /* Set up header */ |
@@ -1772,9 +1881,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1772 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, | 1881 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, |
1773 | sizeof(*info->psinfo), info->psinfo); | 1882 | sizeof(*info->psinfo), info->psinfo); |
1774 | 1883 | ||
1775 | info->numnote = 2; | 1884 | fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); |
1885 | fill_auxv_note(info->notes + 3, current->mm); | ||
1886 | fill_files_note(info->notes + 4); | ||
1776 | 1887 | ||
1777 | fill_auxv_note(&info->notes[info->numnote++], current->mm); | 1888 | info->numnote = 5; |
1778 | 1889 | ||
1779 | /* Try to dump the FPU. */ | 1890 | /* Try to dump the FPU. */ |
1780 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, | 1891 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, |
@@ -1836,6 +1947,9 @@ static void free_note_info(struct elf_note_info *info) | |||
1836 | kfree(list_entry(tmp, struct elf_thread_status, list)); | 1947 | kfree(list_entry(tmp, struct elf_thread_status, list)); |
1837 | } | 1948 | } |
1838 | 1949 | ||
1950 | /* Free data allocated by fill_files_note(): */ | ||
1951 | vfree(info->notes[4].data); | ||
1952 | |||
1839 | kfree(info->prstatus); | 1953 | kfree(info->prstatus); |
1840 | kfree(info->psinfo); | 1954 | kfree(info->psinfo); |
1841 | kfree(info->notes); | 1955 | kfree(info->notes); |
@@ -1962,7 +2076,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1962 | * Collect all the non-memory information about the process for the | 2076 | * Collect all the non-memory information about the process for the |
1963 | * notes. This also sets up the file header. | 2077 | * notes. This also sets up the file header. |
1964 | */ | 2078 | */ |
1965 | if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs)) | 2079 | if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) |
1966 | goto cleanup; | 2080 | goto cleanup; |
1967 | 2081 | ||
1968 | has_dumped = 1; | 2082 | has_dumped = 1; |