diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 127 |
1 files changed, 47 insertions, 80 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 4c94a79991bb..571a42326908 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -406,7 +406,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
406 | goto out; | 406 | goto out; |
407 | if (!elf_check_arch(interp_elf_ex)) | 407 | if (!elf_check_arch(interp_elf_ex)) |
408 | goto out; | 408 | goto out; |
409 | if (!interpreter->f_op || !interpreter->f_op->mmap) | 409 | if (!interpreter->f_op->mmap) |
410 | goto out; | 410 | goto out; |
411 | 411 | ||
412 | /* | 412 | /* |
@@ -607,7 +607,7 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
607 | goto out; | 607 | goto out; |
608 | if (!elf_check_arch(&loc->elf_ex)) | 608 | if (!elf_check_arch(&loc->elf_ex)) |
609 | goto out; | 609 | goto out; |
610 | if (!bprm->file->f_op || !bprm->file->f_op->mmap) | 610 | if (!bprm->file->f_op->mmap) |
611 | goto out; | 611 | goto out; |
612 | 612 | ||
613 | /* Now read in all of the header information */ | 613 | /* Now read in all of the header information */ |
@@ -1028,7 +1028,7 @@ static int load_elf_library(struct file *file) | |||
1028 | 1028 | ||
1029 | /* First of all, some simple consistency checks */ | 1029 | /* First of all, some simple consistency checks */ |
1030 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || | 1030 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || |
1031 | !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap) | 1031 | !elf_check_arch(&elf_ex) || !file->f_op->mmap) |
1032 | goto out; | 1032 | goto out; |
1033 | 1033 | ||
1034 | /* Now read in all of the header information */ | 1034 | /* Now read in all of the header information */ |
@@ -1225,35 +1225,17 @@ static int notesize(struct memelfnote *en) | |||
1225 | return sz; | 1225 | return sz; |
1226 | } | 1226 | } |
1227 | 1227 | ||
1228 | #define DUMP_WRITE(addr, nr, foffset) \ | 1228 | static int writenote(struct memelfnote *men, struct coredump_params *cprm) |
1229 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) | ||
1230 | |||
1231 | static int alignfile(struct file *file, loff_t *foffset) | ||
1232 | { | ||
1233 | static const char buf[4] = { 0, }; | ||
1234 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | ||
1235 | return 1; | ||
1236 | } | ||
1237 | |||
1238 | static int writenote(struct memelfnote *men, struct file *file, | ||
1239 | loff_t *foffset) | ||
1240 | { | 1229 | { |
1241 | struct elf_note en; | 1230 | struct elf_note en; |
1242 | en.n_namesz = strlen(men->name) + 1; | 1231 | en.n_namesz = strlen(men->name) + 1; |
1243 | en.n_descsz = men->datasz; | 1232 | en.n_descsz = men->datasz; |
1244 | en.n_type = men->type; | 1233 | en.n_type = men->type; |
1245 | 1234 | ||
1246 | DUMP_WRITE(&en, sizeof(en), foffset); | 1235 | return dump_emit(cprm, &en, sizeof(en)) && |
1247 | DUMP_WRITE(men->name, en.n_namesz, foffset); | 1236 | dump_emit(cprm, men->name, en.n_namesz) && dump_align(cprm, 4) && |
1248 | if (!alignfile(file, foffset)) | 1237 | dump_emit(cprm, men->data, men->datasz) && dump_align(cprm, 4); |
1249 | return 0; | ||
1250 | DUMP_WRITE(men->data, men->datasz, foffset); | ||
1251 | if (!alignfile(file, foffset)) | ||
1252 | return 0; | ||
1253 | |||
1254 | return 1; | ||
1255 | } | 1238 | } |
1256 | #undef DUMP_WRITE | ||
1257 | 1239 | ||
1258 | static void fill_elf_header(struct elfhdr *elf, int segs, | 1240 | static void fill_elf_header(struct elfhdr *elf, int segs, |
1259 | u16 machine, u32 flags) | 1241 | u16 machine, u32 flags) |
@@ -1392,7 +1374,7 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) | |||
1392 | } | 1374 | } |
1393 | 1375 | ||
1394 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, | 1376 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, |
1395 | siginfo_t *siginfo) | 1377 | const siginfo_t *siginfo) |
1396 | { | 1378 | { |
1397 | mm_segment_t old_fs = get_fs(); | 1379 | mm_segment_t old_fs = get_fs(); |
1398 | set_fs(KERNEL_DS); | 1380 | set_fs(KERNEL_DS); |
@@ -1599,7 +1581,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1599 | 1581 | ||
1600 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1582 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1601 | struct elf_note_info *info, | 1583 | struct elf_note_info *info, |
1602 | siginfo_t *siginfo, struct pt_regs *regs) | 1584 | const siginfo_t *siginfo, struct pt_regs *regs) |
1603 | { | 1585 | { |
1604 | struct task_struct *dump_task = current; | 1586 | struct task_struct *dump_task = current; |
1605 | const struct user_regset_view *view = task_user_regset_view(dump_task); | 1587 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
@@ -1702,7 +1684,7 @@ static size_t get_note_info_size(struct elf_note_info *info) | |||
1702 | * process-wide notes are interleaved after the first thread-specific note. | 1684 | * process-wide notes are interleaved after the first thread-specific note. |
1703 | */ | 1685 | */ |
1704 | static int write_note_info(struct elf_note_info *info, | 1686 | static int write_note_info(struct elf_note_info *info, |
1705 | struct file *file, loff_t *foffset) | 1687 | struct coredump_params *cprm) |
1706 | { | 1688 | { |
1707 | bool first = 1; | 1689 | bool first = 1; |
1708 | struct elf_thread_core_info *t = info->thread; | 1690 | struct elf_thread_core_info *t = info->thread; |
@@ -1710,22 +1692,22 @@ static int write_note_info(struct elf_note_info *info, | |||
1710 | do { | 1692 | do { |
1711 | int i; | 1693 | int i; |
1712 | 1694 | ||
1713 | if (!writenote(&t->notes[0], file, foffset)) | 1695 | if (!writenote(&t->notes[0], cprm)) |
1714 | return 0; | 1696 | return 0; |
1715 | 1697 | ||
1716 | if (first && !writenote(&info->psinfo, file, foffset)) | 1698 | if (first && !writenote(&info->psinfo, cprm)) |
1717 | return 0; | 1699 | return 0; |
1718 | if (first && !writenote(&info->signote, file, foffset)) | 1700 | if (first && !writenote(&info->signote, cprm)) |
1719 | return 0; | 1701 | return 0; |
1720 | if (first && !writenote(&info->auxv, file, foffset)) | 1702 | if (first && !writenote(&info->auxv, cprm)) |
1721 | return 0; | 1703 | return 0; |
1722 | if (first && info->files.data && | 1704 | if (first && info->files.data && |
1723 | !writenote(&info->files, file, foffset)) | 1705 | !writenote(&info->files, cprm)) |
1724 | return 0; | 1706 | return 0; |
1725 | 1707 | ||
1726 | for (i = 1; i < info->thread_notes; ++i) | 1708 | for (i = 1; i < info->thread_notes; ++i) |
1727 | if (t->notes[i].data && | 1709 | if (t->notes[i].data && |
1728 | !writenote(&t->notes[i], file, foffset)) | 1710 | !writenote(&t->notes[i], cprm)) |
1729 | return 0; | 1711 | return 0; |
1730 | 1712 | ||
1731 | first = 0; | 1713 | first = 0; |
@@ -1848,34 +1830,31 @@ static int elf_note_info_init(struct elf_note_info *info) | |||
1848 | 1830 | ||
1849 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1831 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1850 | struct elf_note_info *info, | 1832 | struct elf_note_info *info, |
1851 | siginfo_t *siginfo, struct pt_regs *regs) | 1833 | const siginfo_t *siginfo, struct pt_regs *regs) |
1852 | { | 1834 | { |
1853 | struct list_head *t; | 1835 | struct list_head *t; |
1836 | struct core_thread *ct; | ||
1837 | struct elf_thread_status *ets; | ||
1854 | 1838 | ||
1855 | if (!elf_note_info_init(info)) | 1839 | if (!elf_note_info_init(info)) |
1856 | return 0; | 1840 | return 0; |
1857 | 1841 | ||
1858 | if (siginfo->si_signo) { | 1842 | for (ct = current->mm->core_state->dumper.next; |
1859 | struct core_thread *ct; | 1843 | ct; ct = ct->next) { |
1860 | struct elf_thread_status *ets; | 1844 | ets = kzalloc(sizeof(*ets), GFP_KERNEL); |
1861 | 1845 | if (!ets) | |
1862 | for (ct = current->mm->core_state->dumper.next; | 1846 | return 0; |
1863 | ct; ct = ct->next) { | ||
1864 | ets = kzalloc(sizeof(*ets), GFP_KERNEL); | ||
1865 | if (!ets) | ||
1866 | return 0; | ||
1867 | 1847 | ||
1868 | ets->thread = ct->task; | 1848 | ets->thread = ct->task; |
1869 | list_add(&ets->list, &info->thread_list); | 1849 | list_add(&ets->list, &info->thread_list); |
1870 | } | 1850 | } |
1871 | 1851 | ||
1872 | list_for_each(t, &info->thread_list) { | 1852 | list_for_each(t, &info->thread_list) { |
1873 | int sz; | 1853 | int sz; |
1874 | 1854 | ||
1875 | ets = list_entry(t, struct elf_thread_status, list); | 1855 | ets = list_entry(t, struct elf_thread_status, list); |
1876 | sz = elf_dump_thread_status(siginfo->si_signo, ets); | 1856 | sz = elf_dump_thread_status(siginfo->si_signo, ets); |
1877 | info->thread_status_size += sz; | 1857 | info->thread_status_size += sz; |
1878 | } | ||
1879 | } | 1858 | } |
1880 | /* now collect the dump for the current */ | 1859 | /* now collect the dump for the current */ |
1881 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | 1860 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
@@ -1935,13 +1914,13 @@ static size_t get_note_info_size(struct elf_note_info *info) | |||
1935 | } | 1914 | } |
1936 | 1915 | ||
1937 | static int write_note_info(struct elf_note_info *info, | 1916 | static int write_note_info(struct elf_note_info *info, |
1938 | struct file *file, loff_t *foffset) | 1917 | struct coredump_params *cprm) |
1939 | { | 1918 | { |
1940 | int i; | 1919 | int i; |
1941 | struct list_head *t; | 1920 | struct list_head *t; |
1942 | 1921 | ||
1943 | for (i = 0; i < info->numnote; i++) | 1922 | for (i = 0; i < info->numnote; i++) |
1944 | if (!writenote(info->notes + i, file, foffset)) | 1923 | if (!writenote(info->notes + i, cprm)) |
1945 | return 0; | 1924 | return 0; |
1946 | 1925 | ||
1947 | /* write out the thread status notes section */ | 1926 | /* write out the thread status notes section */ |
@@ -1950,7 +1929,7 @@ static int write_note_info(struct elf_note_info *info, | |||
1950 | list_entry(t, struct elf_thread_status, list); | 1929 | list_entry(t, struct elf_thread_status, list); |
1951 | 1930 | ||
1952 | for (i = 0; i < tmp->num_notes; i++) | 1931 | for (i = 0; i < tmp->num_notes; i++) |
1953 | if (!writenote(&tmp->notes[i], file, foffset)) | 1932 | if (!writenote(&tmp->notes[i], cprm)) |
1954 | return 0; | 1933 | return 0; |
1955 | } | 1934 | } |
1956 | 1935 | ||
@@ -2046,10 +2025,9 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2046 | int has_dumped = 0; | 2025 | int has_dumped = 0; |
2047 | mm_segment_t fs; | 2026 | mm_segment_t fs; |
2048 | int segs; | 2027 | int segs; |
2049 | size_t size = 0; | ||
2050 | struct vm_area_struct *vma, *gate_vma; | 2028 | struct vm_area_struct *vma, *gate_vma; |
2051 | struct elfhdr *elf = NULL; | 2029 | struct elfhdr *elf = NULL; |
2052 | loff_t offset = 0, dataoff, foffset; | 2030 | loff_t offset = 0, dataoff; |
2053 | struct elf_note_info info = { }; | 2031 | struct elf_note_info info = { }; |
2054 | struct elf_phdr *phdr4note = NULL; | 2032 | struct elf_phdr *phdr4note = NULL; |
2055 | struct elf_shdr *shdr4extnum = NULL; | 2033 | struct elf_shdr *shdr4extnum = NULL; |
@@ -2105,7 +2083,6 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2105 | 2083 | ||
2106 | offset += sizeof(*elf); /* Elf header */ | 2084 | offset += sizeof(*elf); /* Elf header */ |
2107 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ | 2085 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
2108 | foffset = offset; | ||
2109 | 2086 | ||
2110 | /* Write notes phdr entry */ | 2087 | /* Write notes phdr entry */ |
2111 | { | 2088 | { |
@@ -2136,13 +2113,10 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2136 | 2113 | ||
2137 | offset = dataoff; | 2114 | offset = dataoff; |
2138 | 2115 | ||
2139 | size += sizeof(*elf); | 2116 | if (!dump_emit(cprm, elf, sizeof(*elf))) |
2140 | if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) | ||
2141 | goto end_coredump; | 2117 | goto end_coredump; |
2142 | 2118 | ||
2143 | size += sizeof(*phdr4note); | 2119 | if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note))) |
2144 | if (size > cprm->limit | ||
2145 | || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note))) | ||
2146 | goto end_coredump; | 2120 | goto end_coredump; |
2147 | 2121 | ||
2148 | /* Write program headers for segments dump */ | 2122 | /* Write program headers for segments dump */ |
@@ -2164,24 +2138,22 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2164 | phdr.p_flags |= PF_X; | 2138 | phdr.p_flags |= PF_X; |
2165 | phdr.p_align = ELF_EXEC_PAGESIZE; | 2139 | phdr.p_align = ELF_EXEC_PAGESIZE; |
2166 | 2140 | ||
2167 | size += sizeof(phdr); | 2141 | if (!dump_emit(cprm, &phdr, sizeof(phdr))) |
2168 | if (size > cprm->limit | ||
2169 | || !dump_write(cprm->file, &phdr, sizeof(phdr))) | ||
2170 | goto end_coredump; | 2142 | goto end_coredump; |
2171 | } | 2143 | } |
2172 | 2144 | ||
2173 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) | 2145 | if (!elf_core_write_extra_phdrs(cprm, offset)) |
2174 | goto end_coredump; | 2146 | goto end_coredump; |
2175 | 2147 | ||
2176 | /* write out the notes section */ | 2148 | /* write out the notes section */ |
2177 | if (!write_note_info(&info, cprm->file, &foffset)) | 2149 | if (!write_note_info(&info, cprm)) |
2178 | goto end_coredump; | 2150 | goto end_coredump; |
2179 | 2151 | ||
2180 | if (elf_coredump_extra_notes_write(cprm->file, &foffset)) | 2152 | if (elf_coredump_extra_notes_write(cprm)) |
2181 | goto end_coredump; | 2153 | goto end_coredump; |
2182 | 2154 | ||
2183 | /* Align to page */ | 2155 | /* Align to page */ |
2184 | if (!dump_seek(cprm->file, dataoff - foffset)) | 2156 | if (!dump_skip(cprm, dataoff - cprm->written)) |
2185 | goto end_coredump; | 2157 | goto end_coredump; |
2186 | 2158 | ||
2187 | for (vma = first_vma(current, gate_vma); vma != NULL; | 2159 | for (vma = first_vma(current, gate_vma); vma != NULL; |
@@ -2198,26 +2170,21 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2198 | page = get_dump_page(addr); | 2170 | page = get_dump_page(addr); |
2199 | if (page) { | 2171 | if (page) { |
2200 | void *kaddr = kmap(page); | 2172 | void *kaddr = kmap(page); |
2201 | stop = ((size += PAGE_SIZE) > cprm->limit) || | 2173 | stop = !dump_emit(cprm, kaddr, PAGE_SIZE); |
2202 | !dump_write(cprm->file, kaddr, | ||
2203 | PAGE_SIZE); | ||
2204 | kunmap(page); | 2174 | kunmap(page); |
2205 | page_cache_release(page); | 2175 | page_cache_release(page); |
2206 | } else | 2176 | } else |
2207 | stop = !dump_seek(cprm->file, PAGE_SIZE); | 2177 | stop = !dump_skip(cprm, PAGE_SIZE); |
2208 | if (stop) | 2178 | if (stop) |
2209 | goto end_coredump; | 2179 | goto end_coredump; |
2210 | } | 2180 | } |
2211 | } | 2181 | } |
2212 | 2182 | ||
2213 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) | 2183 | if (!elf_core_write_extra_data(cprm)) |
2214 | goto end_coredump; | 2184 | goto end_coredump; |
2215 | 2185 | ||
2216 | if (e_phnum == PN_XNUM) { | 2186 | if (e_phnum == PN_XNUM) { |
2217 | size += sizeof(*shdr4extnum); | 2187 | if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum))) |
2218 | if (size > cprm->limit | ||
2219 | || !dump_write(cprm->file, shdr4extnum, | ||
2220 | sizeof(*shdr4extnum))) | ||
2221 | goto end_coredump; | 2188 | goto end_coredump; |
2222 | } | 2189 | } |
2223 | 2190 | ||