diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 149 |
1 files changed, 137 insertions, 12 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0225fddf49b7..28a64e769527 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, |
@@ -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,8 +1810,8 @@ 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); |
@@ -1713,14 +1833,14 @@ static int elf_note_info_init(struct elf_note_info *info) | |||
1713 | 1833 | ||
1714 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1834 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1715 | struct elf_note_info *info, | 1835 | struct elf_note_info *info, |
1716 | long signr, struct pt_regs *regs) | 1836 | siginfo_t *siginfo, struct pt_regs *regs) |
1717 | { | 1837 | { |
1718 | struct list_head *t; | 1838 | struct list_head *t; |
1719 | 1839 | ||
1720 | if (!elf_note_info_init(info)) | 1840 | if (!elf_note_info_init(info)) |
1721 | return 0; | 1841 | return 0; |
1722 | 1842 | ||
1723 | if (signr) { | 1843 | if (siginfo->si_signo) { |
1724 | struct core_thread *ct; | 1844 | struct core_thread *ct; |
1725 | struct elf_thread_status *ets; | 1845 | struct elf_thread_status *ets; |
1726 | 1846 | ||
@@ -1738,13 +1858,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1738 | int sz; | 1858 | int sz; |
1739 | 1859 | ||
1740 | ets = list_entry(t, struct elf_thread_status, list); | 1860 | ets = list_entry(t, struct elf_thread_status, list); |
1741 | sz = elf_dump_thread_status(signr, ets); | 1861 | sz = elf_dump_thread_status(siginfo->si_signo, ets); |
1742 | info->thread_status_size += sz; | 1862 | info->thread_status_size += sz; |
1743 | } | 1863 | } |
1744 | } | 1864 | } |
1745 | /* now collect the dump for the current */ | 1865 | /* now collect the dump for the current */ |
1746 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | 1866 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
1747 | fill_prstatus(info->prstatus, current, signr); | 1867 | fill_prstatus(info->prstatus, current, siginfo->si_signo); |
1748 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); | 1868 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
1749 | 1869 | ||
1750 | /* Set up header */ | 1870 | /* Set up header */ |
@@ -1761,9 +1881,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1761 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, | 1881 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, |
1762 | sizeof(*info->psinfo), info->psinfo); | 1882 | sizeof(*info->psinfo), info->psinfo); |
1763 | 1883 | ||
1764 | 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); | ||
1765 | 1887 | ||
1766 | fill_auxv_note(&info->notes[info->numnote++], current->mm); | 1888 | info->numnote = 5; |
1767 | 1889 | ||
1768 | /* Try to dump the FPU. */ | 1890 | /* Try to dump the FPU. */ |
1769 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, | 1891 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, |
@@ -1825,6 +1947,9 @@ static void free_note_info(struct elf_note_info *info) | |||
1825 | kfree(list_entry(tmp, struct elf_thread_status, list)); | 1947 | kfree(list_entry(tmp, struct elf_thread_status, list)); |
1826 | } | 1948 | } |
1827 | 1949 | ||
1950 | /* Free data allocated by fill_files_note(): */ | ||
1951 | vfree(info->notes[4].data); | ||
1952 | |||
1828 | kfree(info->prstatus); | 1953 | kfree(info->prstatus); |
1829 | kfree(info->psinfo); | 1954 | kfree(info->psinfo); |
1830 | kfree(info->notes); | 1955 | kfree(info->notes); |
@@ -1951,7 +2076,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1951 | * Collect all the non-memory information about the process for the | 2076 | * Collect all the non-memory information about the process for the |
1952 | * notes. This also sets up the file header. | 2077 | * notes. This also sets up the file header. |
1953 | */ | 2078 | */ |
1954 | 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)) |
1955 | goto cleanup; | 2080 | goto cleanup; |
1956 | 2081 | ||
1957 | has_dumped = 1; | 2082 | has_dumped = 1; |