diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 91 |
1 files changed, 50 insertions, 41 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index dfd8cfb7fb5d..06435f3665f4 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -46,7 +46,6 @@ | |||
46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 46 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
47 | static int load_elf_library(struct file *); | 47 | static int load_elf_library(struct file *); |
48 | static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); | 48 | static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); |
49 | extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); | ||
50 | 49 | ||
51 | #ifndef elf_addr_t | 50 | #ifndef elf_addr_t |
52 | #define elf_addr_t unsigned long | 51 | #define elf_addr_t unsigned long |
@@ -1038,10 +1037,8 @@ out_free_interp: | |||
1038 | out_free_file: | 1037 | out_free_file: |
1039 | sys_close(elf_exec_fileno); | 1038 | sys_close(elf_exec_fileno); |
1040 | out_free_fh: | 1039 | out_free_fh: |
1041 | if (files) { | 1040 | if (files) |
1042 | put_files_struct(current->files); | 1041 | reset_files_struct(current, files); |
1043 | current->files = files; | ||
1044 | } | ||
1045 | out_free_ph: | 1042 | out_free_ph: |
1046 | kfree(elf_phdata); | 1043 | kfree(elf_phdata); |
1047 | goto out; | 1044 | goto out; |
@@ -1154,11 +1151,23 @@ static int dump_write(struct file *file, const void *addr, int nr) | |||
1154 | 1151 | ||
1155 | static int dump_seek(struct file *file, loff_t off) | 1152 | static int dump_seek(struct file *file, loff_t off) |
1156 | { | 1153 | { |
1157 | if (file->f_op->llseek) { | 1154 | if (file->f_op->llseek && file->f_op->llseek != no_llseek) { |
1158 | if (file->f_op->llseek(file, off, 0) != off) | 1155 | if (file->f_op->llseek(file, off, 1) != off) |
1159 | return 0; | 1156 | return 0; |
1160 | } else | 1157 | } else { |
1161 | 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 | } | ||
1162 | return 1; | 1171 | return 1; |
1163 | } | 1172 | } |
1164 | 1173 | ||
@@ -1206,30 +1215,35 @@ static int notesize(struct memelfnote *en) | |||
1206 | return sz; | 1215 | return sz; |
1207 | } | 1216 | } |
1208 | 1217 | ||
1209 | #define DUMP_WRITE(addr, nr) \ | 1218 | #define DUMP_WRITE(addr, nr, foffset) \ |
1210 | 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) |
1211 | #define DUMP_SEEK(off) \ | ||
1212 | do { if (!dump_seek(file, (off))) return 0; } while(0) | ||
1213 | 1220 | ||
1214 | static int writenote(struct memelfnote *men, struct file *file) | 1221 | static int alignfile(struct file *file, loff_t *foffset) |
1215 | { | 1222 | { |
1216 | struct elf_note en; | 1223 | char buf[4] = { 0, }; |
1224 | DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset); | ||
1225 | return 1; | ||
1226 | } | ||
1217 | 1227 | ||
1228 | static int writenote(struct memelfnote *men, struct file *file, | ||
1229 | loff_t *foffset) | ||
1230 | { | ||
1231 | struct elf_note en; | ||
1218 | en.n_namesz = strlen(men->name) + 1; | 1232 | en.n_namesz = strlen(men->name) + 1; |
1219 | en.n_descsz = men->datasz; | 1233 | en.n_descsz = men->datasz; |
1220 | en.n_type = men->type; | 1234 | en.n_type = men->type; |
1221 | 1235 | ||
1222 | DUMP_WRITE(&en, sizeof(en)); | 1236 | DUMP_WRITE(&en, sizeof(en), foffset); |
1223 | DUMP_WRITE(men->name, en.n_namesz); | 1237 | DUMP_WRITE(men->name, en.n_namesz, foffset); |
1224 | /* XXX - cast from long long to long to avoid need for libgcc.a */ | 1238 | if (!alignfile(file, foffset)) |
1225 | DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ | 1239 | return 0; |
1226 | DUMP_WRITE(men->data, men->datasz); | 1240 | DUMP_WRITE(men->data, men->datasz, foffset); |
1227 | DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ | 1241 | if (!alignfile(file, foffset)) |
1242 | return 0; | ||
1228 | 1243 | ||
1229 | return 1; | 1244 | return 1; |
1230 | } | 1245 | } |
1231 | #undef DUMP_WRITE | 1246 | #undef DUMP_WRITE |
1232 | #undef DUMP_SEEK | ||
1233 | 1247 | ||
1234 | #define DUMP_WRITE(addr, nr) \ | 1248 | #define DUMP_WRITE(addr, nr) \ |
1235 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ | 1249 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ |
@@ -1429,7 +1443,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1429 | int i; | 1443 | int i; |
1430 | struct vm_area_struct *vma; | 1444 | struct vm_area_struct *vma; |
1431 | struct elfhdr *elf = NULL; | 1445 | struct elfhdr *elf = NULL; |
1432 | loff_t offset = 0, dataoff; | 1446 | loff_t offset = 0, dataoff, foffset; |
1433 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1447 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
1434 | int numnote; | 1448 | int numnote; |
1435 | struct memelfnote *notes = NULL; | 1449 | struct memelfnote *notes = NULL; |
@@ -1481,20 +1495,19 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1481 | 1495 | ||
1482 | if (signr) { | 1496 | if (signr) { |
1483 | struct elf_thread_status *tmp; | 1497 | struct elf_thread_status *tmp; |
1484 | read_lock(&tasklist_lock); | 1498 | rcu_read_lock(); |
1485 | do_each_thread(g,p) | 1499 | do_each_thread(g,p) |
1486 | if (current->mm == p->mm && current != p) { | 1500 | if (current->mm == p->mm && current != p) { |
1487 | tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); | 1501 | tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); |
1488 | if (!tmp) { | 1502 | if (!tmp) { |
1489 | read_unlock(&tasklist_lock); | 1503 | rcu_read_unlock(); |
1490 | goto cleanup; | 1504 | goto cleanup; |
1491 | } | 1505 | } |
1492 | INIT_LIST_HEAD(&tmp->list); | ||
1493 | tmp->thread = p; | 1506 | tmp->thread = p; |
1494 | list_add(&tmp->list, &thread_list); | 1507 | list_add(&tmp->list, &thread_list); |
1495 | } | 1508 | } |
1496 | while_each_thread(g,p); | 1509 | while_each_thread(g,p); |
1497 | read_unlock(&tasklist_lock); | 1510 | rcu_read_unlock(); |
1498 | list_for_each(t, &thread_list) { | 1511 | list_for_each(t, &thread_list) { |
1499 | struct elf_thread_status *tmp; | 1512 | struct elf_thread_status *tmp; |
1500 | int sz; | 1513 | int sz; |
@@ -1573,7 +1586,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1573 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1586 | DUMP_WRITE(&phdr, sizeof(phdr)); |
1574 | } | 1587 | } |
1575 | 1588 | ||
1576 | /* Page-align dumped data */ | 1589 | foffset = offset; |
1590 | |||
1577 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1591 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1578 | 1592 | ||
1579 | /* Write program headers for segments dump */ | 1593 | /* Write program headers for segments dump */ |
@@ -1598,6 +1612,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1598 | phdr.p_align = ELF_EXEC_PAGESIZE; | 1612 | phdr.p_align = ELF_EXEC_PAGESIZE; |
1599 | 1613 | ||
1600 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1614 | DUMP_WRITE(&phdr, sizeof(phdr)); |
1615 | foffset += sizeof(phdr); | ||
1601 | } | 1616 | } |
1602 | 1617 | ||
1603 | #ifdef ELF_CORE_WRITE_EXTRA_PHDRS | 1618 | #ifdef ELF_CORE_WRITE_EXTRA_PHDRS |
@@ -1606,7 +1621,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1606 | 1621 | ||
1607 | /* write out the notes section */ | 1622 | /* write out the notes section */ |
1608 | for (i = 0; i < numnote; i++) | 1623 | for (i = 0; i < numnote; i++) |
1609 | if (!writenote(notes + i, file)) | 1624 | if (!writenote(notes + i, file, &foffset)) |
1610 | goto end_coredump; | 1625 | goto end_coredump; |
1611 | 1626 | ||
1612 | /* write out the thread status notes section */ | 1627 | /* write out the thread status notes section */ |
@@ -1615,11 +1630,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1615 | list_entry(t, struct elf_thread_status, list); | 1630 | list_entry(t, struct elf_thread_status, list); |
1616 | 1631 | ||
1617 | for (i = 0; i < tmp->num_notes; i++) | 1632 | for (i = 0; i < tmp->num_notes; i++) |
1618 | if (!writenote(&tmp->notes[i], file)) | 1633 | if (!writenote(&tmp->notes[i], file, &foffset)) |
1619 | goto end_coredump; | 1634 | goto end_coredump; |
1620 | } | 1635 | } |
1621 | 1636 | ||
1622 | DUMP_SEEK(dataoff); | 1637 | /* Align to page */ |
1638 | DUMP_SEEK(dataoff - foffset); | ||
1623 | 1639 | ||
1624 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1640 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
1625 | unsigned long addr; | 1641 | unsigned long addr; |
@@ -1635,10 +1651,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1635 | 1651 | ||
1636 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, | 1652 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, |
1637 | &page, &vma) <= 0) { | 1653 | &page, &vma) <= 0) { |
1638 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | 1654 | DUMP_SEEK(PAGE_SIZE); |
1639 | } else { | 1655 | } else { |
1640 | if (page == ZERO_PAGE(addr)) { | 1656 | if (page == ZERO_PAGE(addr)) { |
1641 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | 1657 | DUMP_SEEK(PAGE_SIZE); |
1642 | } else { | 1658 | } else { |
1643 | void *kaddr; | 1659 | void *kaddr; |
1644 | flush_cache_page(vma, addr, | 1660 | flush_cache_page(vma, addr, |
@@ -1662,13 +1678,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1662 | ELF_CORE_WRITE_EXTRA_DATA; | 1678 | ELF_CORE_WRITE_EXTRA_DATA; |
1663 | #endif | 1679 | #endif |
1664 | 1680 | ||
1665 | if (file->f_pos != offset) { | ||
1666 | /* Sanity check */ | ||
1667 | printk(KERN_WARNING | ||
1668 | "elf_core_dump: file->f_pos (%Ld) != offset (%Ld)\n", | ||
1669 | file->f_pos, offset); | ||
1670 | } | ||
1671 | |||
1672 | end_coredump: | 1681 | end_coredump: |
1673 | set_fs(fs); | 1682 | set_fs(fs); |
1674 | 1683 | ||