diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 77 |
1 files changed, 45 insertions, 32 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index bad52433de69..06435f3665f4 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1151,11 +1151,23 @@ static int dump_write(struct file *file, const void *addr, int nr) | |||
1151 | 1151 | ||
1152 | static int dump_seek(struct file *file, loff_t off) | 1152 | static int dump_seek(struct file *file, loff_t off) |
1153 | { | 1153 | { |
1154 | if (file->f_op->llseek) { | 1154 | if (file->f_op->llseek && file->f_op->llseek != no_llseek) { |
1155 | if (file->f_op->llseek(file, off, 0) != off) | 1155 | if (file->f_op->llseek(file, off, 1) != off) |
1156 | return 0; | 1156 | return 0; |
1157 | } else | 1157 | } else { |
1158 | file->f_pos = off; | 1158 | char *buf = (char *)get_zeroed_page(GFP_KERNEL); |
1159 | if (!buf) | ||
1160 | return 0; | ||
1161 | while (off > 0) { | ||
1162 | unsigned long n = off; | ||
1163 | if (n > PAGE_SIZE) | ||
1164 | n = PAGE_SIZE; | ||
1165 | if (!dump_write(file, buf, n)) | ||
1166 | return 0; | ||
1167 | off -= n; | ||
1168 | } | ||
1169 | free_page((unsigned long)buf); | ||
1170 | } | ||
1159 | return 1; | 1171 | return 1; |
1160 | } | 1172 | } |
1161 | 1173 | ||
@@ -1203,30 +1215,35 @@ static int notesize(struct memelfnote *en) | |||
1203 | return sz; | 1215 | return sz; |
1204 | } | 1216 | } |
1205 | 1217 | ||
1206 | #define DUMP_WRITE(addr, nr) \ | 1218 | #define DUMP_WRITE(addr, nr, foffset) \ |
1207 | do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) | 1219 | do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0) |
1208 | #define DUMP_SEEK(off) \ | ||
1209 | do { if (!dump_seek(file, (off))) return 0; } while(0) | ||
1210 | 1220 | ||
1211 | static int writenote(struct memelfnote *men, struct file *file) | 1221 | static int alignfile(struct file *file, loff_t *foffset) |
1212 | { | 1222 | { |
1213 | struct elf_note en; | 1223 | char buf[4] = { 0, }; |
1224 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | ||
1225 | return 1; | ||
1226 | } | ||
1214 | 1227 | ||
1228 | static int writenote(struct memelfnote *men, struct file *file, | ||
1229 | loff_t *foffset) | ||
1230 | { | ||
1231 | struct elf_note en; | ||
1215 | en.n_namesz = strlen(men->name) + 1; | 1232 | en.n_namesz = strlen(men->name) + 1; |
1216 | en.n_descsz = men->datasz; | 1233 | en.n_descsz = men->datasz; |
1217 | en.n_type = men->type; | 1234 | en.n_type = men->type; |
1218 | 1235 | ||
1219 | DUMP_WRITE(&en, sizeof(en)); | 1236 | DUMP_WRITE(&en, sizeof(en), foffset); |
1220 | DUMP_WRITE(men->name, en.n_namesz); | 1237 | DUMP_WRITE(men->name, en.n_namesz, foffset); |
1221 | /* XXX - cast from long long to long to avoid need for libgcc.a */ | 1238 | if (!alignfile(file, foffset)) |
1222 | DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ | 1239 | return 0; |
1223 | DUMP_WRITE(men->data, men->datasz); | 1240 | DUMP_WRITE(men->data, men->datasz, foffset); |
1224 | DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ | 1241 | if (!alignfile(file, foffset)) |
1242 | return 0; | ||
1225 | 1243 | ||
1226 | return 1; | 1244 | return 1; |
1227 | } | 1245 | } |
1228 | #undef DUMP_WRITE | 1246 | #undef DUMP_WRITE |
1229 | #undef DUMP_SEEK | ||
1230 | 1247 | ||
1231 | #define DUMP_WRITE(addr, nr) \ | 1248 | #define DUMP_WRITE(addr, nr) \ |
1232 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ | 1249 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ |
@@ -1426,7 +1443,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1426 | int i; | 1443 | int i; |
1427 | struct vm_area_struct *vma; | 1444 | struct vm_area_struct *vma; |
1428 | struct elfhdr *elf = NULL; | 1445 | struct elfhdr *elf = NULL; |
1429 | loff_t offset = 0, dataoff; | 1446 | loff_t offset = 0, dataoff, foffset; |
1430 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1447 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
1431 | int numnote; | 1448 | int numnote; |
1432 | struct memelfnote *notes = NULL; | 1449 | struct memelfnote *notes = NULL; |
@@ -1569,7 +1586,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1569 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1586 | DUMP_WRITE(&phdr, sizeof(phdr)); |
1570 | } | 1587 | } |
1571 | 1588 | ||
1572 | /* Page-align dumped data */ | 1589 | foffset = offset; |
1590 | |||
1573 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1591 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1574 | 1592 | ||
1575 | /* Write program headers for segments dump */ | 1593 | /* Write program headers for segments dump */ |
@@ -1594,6 +1612,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1594 | phdr.p_align = ELF_EXEC_PAGESIZE; | 1612 | phdr.p_align = ELF_EXEC_PAGESIZE; |
1595 | 1613 | ||
1596 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1614 | DUMP_WRITE(&phdr, sizeof(phdr)); |
1615 | foffset += sizeof(phdr); | ||
1597 | } | 1616 | } |
1598 | 1617 | ||
1599 | #ifdef ELF_CORE_WRITE_EXTRA_PHDRS | 1618 | #ifdef ELF_CORE_WRITE_EXTRA_PHDRS |
@@ -1602,7 +1621,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1602 | 1621 | ||
1603 | /* write out the notes section */ | 1622 | /* write out the notes section */ |
1604 | for (i = 0; i < numnote; i++) | 1623 | for (i = 0; i < numnote; i++) |
1605 | if (!writenote(notes + i, file)) | 1624 | if (!writenote(notes + i, file, &foffset)) |
1606 | goto end_coredump; | 1625 | goto end_coredump; |
1607 | 1626 | ||
1608 | /* write out the thread status notes section */ | 1627 | /* write out the thread status notes section */ |
@@ -1611,11 +1630,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1611 | list_entry(t, struct elf_thread_status, list); | 1630 | list_entry(t, struct elf_thread_status, list); |
1612 | 1631 | ||
1613 | for (i = 0; i < tmp->num_notes; i++) | 1632 | for (i = 0; i < tmp->num_notes; i++) |
1614 | if (!writenote(&tmp->notes[i], file)) | 1633 | if (!writenote(&tmp->notes[i], file, &foffset)) |
1615 | goto end_coredump; | 1634 | goto end_coredump; |
1616 | } | 1635 | } |
1617 | 1636 | ||
1618 | DUMP_SEEK(dataoff); | 1637 | /* Align to page */ |
1638 | DUMP_SEEK(dataoff - foffset); | ||
1619 | 1639 | ||
1620 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1640 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
1621 | unsigned long addr; | 1641 | unsigned long addr; |
@@ -1631,10 +1651,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1631 | 1651 | ||
1632 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, | 1652 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, |
1633 | &page, &vma) <= 0) { | 1653 | &page, &vma) <= 0) { |
1634 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | 1654 | DUMP_SEEK(PAGE_SIZE); |
1635 | } else { | 1655 | } else { |
1636 | if (page == ZERO_PAGE(addr)) { | 1656 | if (page == ZERO_PAGE(addr)) { |
1637 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | 1657 | DUMP_SEEK(PAGE_SIZE); |
1638 | } else { | 1658 | } else { |
1639 | void *kaddr; | 1659 | void *kaddr; |
1640 | flush_cache_page(vma, addr, | 1660 | flush_cache_page(vma, addr, |
@@ -1658,13 +1678,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1658 | ELF_CORE_WRITE_EXTRA_DATA; | 1678 | ELF_CORE_WRITE_EXTRA_DATA; |
1659 | #endif | 1679 | #endif |
1660 | 1680 | ||
1661 | if (file->f_pos != offset) { | ||
1662 | /* Sanity check */ | ||
1663 | printk(KERN_WARNING | ||
1664 | "elf_core_dump: file->f_pos (%Ld) != offset (%Ld)\n", | ||
1665 | file->f_pos, offset); | ||
1666 | } | ||
1667 | |||
1668 | end_coredump: | 1681 | end_coredump: |
1669 | set_fs(fs); | 1682 | set_fs(fs); |
1670 | 1683 | ||