diff options
-rw-r--r-- | arch/ia64/kernel/elfcore.c | 16 | ||||
-rw-r--r-- | arch/um/sys-i386/elfcore.c | 16 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 66 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 63 | ||||
-rw-r--r-- | include/linux/elf.h | 26 | ||||
-rw-r--r-- | include/linux/elfcore.h | 1 | ||||
-rw-r--r-- | kernel/elfcore.c | 5 |
7 files changed, 187 insertions, 6 deletions
diff --git a/arch/ia64/kernel/elfcore.c b/arch/ia64/kernel/elfcore.c index 57a2298a8581..bac1639bc320 100644 --- a/arch/ia64/kernel/elfcore.c +++ b/arch/ia64/kernel/elfcore.c | |||
@@ -62,3 +62,19 @@ int elf_core_write_extra_data(struct file *file, size_t *size, | |||
62 | } | 62 | } |
63 | return 1; | 63 | return 1; |
64 | } | 64 | } |
65 | |||
66 | size_t elf_core_extra_data_size(void) | ||
67 | { | ||
68 | const struct elf_phdr *const gate_phdrs = | ||
69 | (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff); | ||
70 | int i; | ||
71 | size_t size = 0; | ||
72 | |||
73 | for (i = 0; i < GATE_EHDR->e_phnum; ++i) { | ||
74 | if (gate_phdrs[i].p_type == PT_LOAD) { | ||
75 | size += PAGE_ALIGN(gate_phdrs[i].p_memsz); | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | return size; | ||
80 | } | ||
diff --git a/arch/um/sys-i386/elfcore.c b/arch/um/sys-i386/elfcore.c index 30cac52a04b4..6bb49b687c97 100644 --- a/arch/um/sys-i386/elfcore.c +++ b/arch/um/sys-i386/elfcore.c | |||
@@ -65,3 +65,19 @@ int elf_core_write_extra_data(struct file *file, size_t *size, | |||
65 | } | 65 | } |
66 | return 1; | 66 | return 1; |
67 | } | 67 | } |
68 | |||
69 | size_t elf_core_extra_data_size(void) | ||
70 | { | ||
71 | if ( vsyscall_ehdr ) { | ||
72 | const struct elfhdr *const ehdrp = | ||
73 | (struct elfhdr *)vsyscall_ehdr; | ||
74 | const struct elf_phdr *const phdrp = | ||
75 | (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); | ||
76 | int i; | ||
77 | |||
78 | for (i = 0; i < ehdrp->e_phnum; ++i) | ||
79 | if (phdrp[i].p_type == PT_LOAD) | ||
80 | return (size_t) phdrp[i].p_filesz; | ||
81 | } | ||
82 | return 0; | ||
83 | } | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6fc49b6ed936..78de530cfb02 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1838,6 +1838,34 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | |||
1838 | return gate_vma; | 1838 | return gate_vma; |
1839 | } | 1839 | } |
1840 | 1840 | ||
1841 | static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, | ||
1842 | elf_addr_t e_shoff, int segs) | ||
1843 | { | ||
1844 | elf->e_shoff = e_shoff; | ||
1845 | elf->e_shentsize = sizeof(*shdr4extnum); | ||
1846 | elf->e_shnum = 1; | ||
1847 | elf->e_shstrndx = SHN_UNDEF; | ||
1848 | |||
1849 | memset(shdr4extnum, 0, sizeof(*shdr4extnum)); | ||
1850 | |||
1851 | shdr4extnum->sh_type = SHT_NULL; | ||
1852 | shdr4extnum->sh_size = elf->e_shnum; | ||
1853 | shdr4extnum->sh_link = elf->e_shstrndx; | ||
1854 | shdr4extnum->sh_info = segs; | ||
1855 | } | ||
1856 | |||
1857 | static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma, | ||
1858 | unsigned long mm_flags) | ||
1859 | { | ||
1860 | struct vm_area_struct *vma; | ||
1861 | size_t size = 0; | ||
1862 | |||
1863 | for (vma = first_vma(current, gate_vma); vma != NULL; | ||
1864 | vma = next_vma(vma, gate_vma)) | ||
1865 | size += vma_dump_size(vma, mm_flags); | ||
1866 | return size; | ||
1867 | } | ||
1868 | |||
1841 | /* | 1869 | /* |
1842 | * Actual dumper | 1870 | * Actual dumper |
1843 | * | 1871 | * |
@@ -1857,6 +1885,9 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1857 | unsigned long mm_flags; | 1885 | unsigned long mm_flags; |
1858 | struct elf_note_info info; | 1886 | struct elf_note_info info; |
1859 | struct elf_phdr *phdr4note = NULL; | 1887 | struct elf_phdr *phdr4note = NULL; |
1888 | struct elf_shdr *shdr4extnum = NULL; | ||
1889 | Elf_Half e_phnum; | ||
1890 | elf_addr_t e_shoff; | ||
1860 | 1891 | ||
1861 | /* | 1892 | /* |
1862 | * We no longer stop all VM operations. | 1893 | * We no longer stop all VM operations. |
@@ -1885,12 +1916,19 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1885 | if (gate_vma != NULL) | 1916 | if (gate_vma != NULL) |
1886 | segs++; | 1917 | segs++; |
1887 | 1918 | ||
1919 | /* for notes section */ | ||
1920 | segs++; | ||
1921 | |||
1922 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid | ||
1923 | * this, kernel supports extended numbering. Have a look at | ||
1924 | * include/linux/elf.h for further information. */ | ||
1925 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; | ||
1926 | |||
1888 | /* | 1927 | /* |
1889 | * Collect all the non-memory information about the process for the | 1928 | * Collect all the non-memory information about the process for the |
1890 | * notes. This also sets up the file header. | 1929 | * notes. This also sets up the file header. |
1891 | */ | 1930 | */ |
1892 | if (!fill_note_info(elf, segs + 1, /* including notes section */ | 1931 | if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs)) |
1893 | &info, cprm->signr, cprm->regs)) | ||
1894 | goto cleanup; | 1932 | goto cleanup; |
1895 | 1933 | ||
1896 | has_dumped = 1; | 1934 | has_dumped = 1; |
@@ -1900,7 +1938,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1900 | set_fs(KERNEL_DS); | 1938 | set_fs(KERNEL_DS); |
1901 | 1939 | ||
1902 | offset += sizeof(*elf); /* Elf header */ | 1940 | offset += sizeof(*elf); /* Elf header */ |
1903 | offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ | 1941 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
1904 | foffset = offset; | 1942 | foffset = offset; |
1905 | 1943 | ||
1906 | /* Write notes phdr entry */ | 1944 | /* Write notes phdr entry */ |
@@ -1926,6 +1964,19 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1926 | */ | 1964 | */ |
1927 | mm_flags = current->mm->flags; | 1965 | mm_flags = current->mm->flags; |
1928 | 1966 | ||
1967 | offset += elf_core_vma_data_size(gate_vma, mm_flags); | ||
1968 | offset += elf_core_extra_data_size(); | ||
1969 | e_shoff = offset; | ||
1970 | |||
1971 | if (e_phnum == PN_XNUM) { | ||
1972 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); | ||
1973 | if (!shdr4extnum) | ||
1974 | goto end_coredump; | ||
1975 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); | ||
1976 | } | ||
1977 | |||
1978 | offset = dataoff; | ||
1979 | |||
1929 | size += sizeof(*elf); | 1980 | size += sizeof(*elf); |
1930 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | 1981 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) |
1931 | goto end_coredump; | 1982 | goto end_coredump; |
@@ -2003,11 +2054,20 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2003 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 2054 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) |
2004 | goto end_coredump; | 2055 | goto end_coredump; |
2005 | 2056 | ||
2057 | if (e_phnum == PN_XNUM) { | ||
2058 | size += sizeof(*shdr4extnum); | ||
2059 | if (size > cprm->limit | ||
2060 | || !dump_write(cprm->file, shdr4extnum, | ||
2061 | sizeof(*shdr4extnum))) | ||
2062 | goto end_coredump; | ||
2063 | } | ||
2064 | |||
2006 | end_coredump: | 2065 | end_coredump: |
2007 | set_fs(fs); | 2066 | set_fs(fs); |
2008 | 2067 | ||
2009 | cleanup: | 2068 | cleanup: |
2010 | free_note_info(&info); | 2069 | free_note_info(&info); |
2070 | kfree(shdr4extnum); | ||
2011 | kfree(phdr4note); | 2071 | kfree(phdr4note); |
2012 | kfree(elf); | 2072 | kfree(elf); |
2013 | out: | 2073 | out: |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 112da491d75d..e49d9c06a4b6 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1505,6 +1505,22 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | |||
1505 | return sz; | 1505 | return sz; |
1506 | } | 1506 | } |
1507 | 1507 | ||
1508 | static 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 | |||
1508 | /* | 1524 | /* |
1509 | * dump the segments for an MMU process | 1525 | * dump the segments for an MMU process |
1510 | */ | 1526 | */ |
@@ -1569,6 +1585,17 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, | |||
1569 | } | 1585 | } |
1570 | #endif | 1586 | #endif |
1571 | 1587 | ||
1588 | static 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->vm_next) | ||
1594 | if (maydump(vma, mm_flags)) | ||
1595 | size += vma->vm_end - vma->vm_start; | ||
1596 | return size; | ||
1597 | } | ||
1598 | |||
1572 | /* | 1599 | /* |
1573 | * Actual dumper | 1600 | * Actual dumper |
1574 | * | 1601 | * |
@@ -1601,6 +1628,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1601 | elf_addr_t *auxv; | 1628 | elf_addr_t *auxv; |
1602 | unsigned long mm_flags; | 1629 | unsigned long mm_flags; |
1603 | struct elf_phdr *phdr4note = NULL; | 1630 | struct elf_phdr *phdr4note = NULL; |
1631 | struct elf_shdr *shdr4extnum = NULL; | ||
1632 | Elf_Half e_phnum; | ||
1633 | elf_addr_t e_shoff; | ||
1604 | 1634 | ||
1605 | /* | 1635 | /* |
1606 | * We no longer stop all VM operations. | 1636 | * We no longer stop all VM operations. |
@@ -1667,8 +1697,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1667 | segs = current->mm->map_count; | 1697 | segs = current->mm->map_count; |
1668 | segs += elf_core_extra_phdrs(); | 1698 | segs += elf_core_extra_phdrs(); |
1669 | 1699 | ||
1700 | /* for notes section */ | ||
1701 | segs++; | ||
1702 | |||
1703 | /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid | ||
1704 | * this, kernel supports extended numbering. Have a look at | ||
1705 | * include/linux/elf.h for further information. */ | ||
1706 | e_phnum = segs > PN_XNUM ? PN_XNUM : segs; | ||
1707 | |||
1670 | /* Set up header */ | 1708 | /* Set up header */ |
1671 | fill_elf_fdpic_header(elf, segs + 1); /* including notes section */ | 1709 | fill_elf_fdpic_header(elf, e_phnum); |
1672 | 1710 | ||
1673 | has_dumped = 1; | 1711 | has_dumped = 1; |
1674 | current->flags |= PF_DUMPCORE; | 1712 | current->flags |= PF_DUMPCORE; |
@@ -1708,7 +1746,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1708 | set_fs(KERNEL_DS); | 1746 | set_fs(KERNEL_DS); |
1709 | 1747 | ||
1710 | offset += sizeof(*elf); /* Elf header */ | 1748 | offset += sizeof(*elf); /* Elf header */ |
1711 | offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ | 1749 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
1712 | foffset = offset; | 1750 | foffset = offset; |
1713 | 1751 | ||
1714 | /* Write notes phdr entry */ | 1752 | /* Write notes phdr entry */ |
@@ -1738,6 +1776,19 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1738 | */ | 1776 | */ |
1739 | mm_flags = current->mm->flags; | 1777 | mm_flags = current->mm->flags; |
1740 | 1778 | ||
1779 | offset += elf_core_vma_data_size(mm_flags); | ||
1780 | offset += elf_core_extra_data_size(); | ||
1781 | e_shoff = offset; | ||
1782 | |||
1783 | if (e_phnum == PN_XNUM) { | ||
1784 | shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL); | ||
1785 | if (!shdr4extnum) | ||
1786 | goto end_coredump; | ||
1787 | fill_extnum_info(elf, shdr4extnum, e_shoff, segs); | ||
1788 | } | ||
1789 | |||
1790 | offset = dataoff; | ||
1791 | |||
1741 | size += sizeof(*elf); | 1792 | size += sizeof(*elf); |
1742 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | 1793 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) |
1743 | goto end_coredump; | 1794 | goto end_coredump; |
@@ -1802,6 +1853,14 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1802 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 1853 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) |
1803 | goto end_coredump; | 1854 | goto end_coredump; |
1804 | 1855 | ||
1856 | if (e_phnum == PN_XNUM) { | ||
1857 | size += sizeof(*shdr4extnum); | ||
1858 | if (size > cprm->limit | ||
1859 | || !dump_write(cprm->file, shdr4extnum, | ||
1860 | sizeof(*shdr4extnum))) | ||
1861 | goto end_coredump; | ||
1862 | } | ||
1863 | |||
1805 | if (cprm->file->f_pos != offset) { | 1864 | if (cprm->file->f_pos != offset) { |
1806 | /* Sanity check */ | 1865 | /* Sanity check */ |
1807 | printk(KERN_WARNING | 1866 | printk(KERN_WARNING |
diff --git a/include/linux/elf.h b/include/linux/elf.h index ccde3fd45f36..597858418051 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
@@ -50,6 +50,28 @@ typedef __s64 Elf64_Sxword; | |||
50 | 50 | ||
51 | #define PT_GNU_STACK (PT_LOOS + 0x474e551) | 51 | #define PT_GNU_STACK (PT_LOOS + 0x474e551) |
52 | 52 | ||
53 | /* | ||
54 | * Extended Numbering | ||
55 | * | ||
56 | * If the real number of program header table entries is larger than | ||
57 | * or equal to PN_XNUM(0xffff), it is set to sh_info field of the | ||
58 | * section header at index 0, and PN_XNUM is set to e_phnum | ||
59 | * field. Otherwise, the section header at index 0 is zero | ||
60 | * initialized, if it exists. | ||
61 | * | ||
62 | * Specifications are available in: | ||
63 | * | ||
64 | * - Sun microsystems: Linker and Libraries. | ||
65 | * Part No: 817-1984-17, September 2008. | ||
66 | * URL: http://docs.sun.com/app/docs/doc/817-1984 | ||
67 | * | ||
68 | * - System V ABI AMD64 Architecture Processor Supplement | ||
69 | * Draft Version 0.99., | ||
70 | * May 11, 2009. | ||
71 | * URL: http://www.x86-64.org/ | ||
72 | */ | ||
73 | #define PN_XNUM 0xffff | ||
74 | |||
53 | /* These constants define the different elf file types */ | 75 | /* These constants define the different elf file types */ |
54 | #define ET_NONE 0 | 76 | #define ET_NONE 0 |
55 | #define ET_REL 1 | 77 | #define ET_REL 1 |
@@ -286,7 +308,7 @@ typedef struct elf64_phdr { | |||
286 | #define SHN_COMMON 0xfff2 | 308 | #define SHN_COMMON 0xfff2 |
287 | #define SHN_HIRESERVE 0xffff | 309 | #define SHN_HIRESERVE 0xffff |
288 | 310 | ||
289 | typedef struct { | 311 | typedef struct elf32_shdr { |
290 | Elf32_Word sh_name; | 312 | Elf32_Word sh_name; |
291 | Elf32_Word sh_type; | 313 | Elf32_Word sh_type; |
292 | Elf32_Word sh_flags; | 314 | Elf32_Word sh_flags; |
@@ -394,6 +416,7 @@ typedef struct elf64_note { | |||
394 | extern Elf32_Dyn _DYNAMIC []; | 416 | extern Elf32_Dyn _DYNAMIC []; |
395 | #define elfhdr elf32_hdr | 417 | #define elfhdr elf32_hdr |
396 | #define elf_phdr elf32_phdr | 418 | #define elf_phdr elf32_phdr |
419 | #define elf_shdr elf32_shdr | ||
397 | #define elf_note elf32_note | 420 | #define elf_note elf32_note |
398 | #define elf_addr_t Elf32_Off | 421 | #define elf_addr_t Elf32_Off |
399 | #define Elf_Half Elf32_Half | 422 | #define Elf_Half Elf32_Half |
@@ -403,6 +426,7 @@ extern Elf32_Dyn _DYNAMIC []; | |||
403 | extern Elf64_Dyn _DYNAMIC []; | 426 | extern Elf64_Dyn _DYNAMIC []; |
404 | #define elfhdr elf64_hdr | 427 | #define elfhdr elf64_hdr |
405 | #define elf_phdr elf64_phdr | 428 | #define elf_phdr elf64_phdr |
429 | #define elf_shdr elf64_shdr | ||
406 | #define elf_note elf64_note | 430 | #define elf_note elf64_note |
407 | #define elf_addr_t Elf64_Off | 431 | #define elf_addr_t Elf64_Off |
408 | #define Elf_Half Elf64_Half | 432 | #define Elf_Half Elf64_Half |
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h index cfda74f521b5..e687bc3ba4da 100644 --- a/include/linux/elfcore.h +++ b/include/linux/elfcore.h | |||
@@ -166,5 +166,6 @@ elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size, | |||
166 | unsigned long limit); | 166 | unsigned long limit); |
167 | extern int | 167 | extern int |
168 | elf_core_write_extra_data(struct file *file, size_t *size, unsigned long limit); | 168 | elf_core_write_extra_data(struct file *file, size_t *size, unsigned long limit); |
169 | extern size_t elf_core_extra_data_size(void); | ||
169 | 170 | ||
170 | #endif /* _LINUX_ELFCORE_H */ | 171 | #endif /* _LINUX_ELFCORE_H */ |
diff --git a/kernel/elfcore.c b/kernel/elfcore.c index 5445741f4b4c..ff915efef66d 100644 --- a/kernel/elfcore.c +++ b/kernel/elfcore.c | |||
@@ -21,3 +21,8 @@ int __weak elf_core_write_extra_data(struct file *file, size_t *size, | |||
21 | { | 21 | { |
22 | return 1; | 22 | return 1; |
23 | } | 23 | } |
24 | |||
25 | size_t __weak elf_core_extra_data_size(void) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||