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 | ||
