diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/binfmt_elf.c | 77 | ||||
| -rw-r--r-- | fs/exec.c | 23 |
2 files changed, 63 insertions, 37 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 | ||
| @@ -58,7 +58,7 @@ | |||
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | int core_uses_pid; | 60 | int core_uses_pid; |
| 61 | char core_pattern[65] = "core"; | 61 | char core_pattern[128] = "core"; |
| 62 | int suid_dumpable = 0; | 62 | int suid_dumpable = 0; |
| 63 | 63 | ||
| 64 | EXPORT_SYMBOL(suid_dumpable); | 64 | EXPORT_SYMBOL(suid_dumpable); |
| @@ -1463,6 +1463,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1463 | int retval = 0; | 1463 | int retval = 0; |
| 1464 | int fsuid = current->fsuid; | 1464 | int fsuid = current->fsuid; |
| 1465 | int flag = 0; | 1465 | int flag = 0; |
| 1466 | int ispipe = 0; | ||
| 1466 | 1467 | ||
| 1467 | binfmt = current->binfmt; | 1468 | binfmt = current->binfmt; |
| 1468 | if (!binfmt || !binfmt->core_dump) | 1469 | if (!binfmt || !binfmt->core_dump) |
| @@ -1504,22 +1505,34 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1504 | lock_kernel(); | 1505 | lock_kernel(); |
| 1505 | format_corename(corename, core_pattern, signr); | 1506 | format_corename(corename, core_pattern, signr); |
| 1506 | unlock_kernel(); | 1507 | unlock_kernel(); |
| 1507 | file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); | 1508 | if (corename[0] == '|') { |
| 1509 | /* SIGPIPE can happen, but it's just never processed */ | ||
| 1510 | if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) { | ||
| 1511 | printk(KERN_INFO "Core dump to %s pipe failed\n", | ||
| 1512 | corename); | ||
| 1513 | goto fail_unlock; | ||
| 1514 | } | ||
| 1515 | ispipe = 1; | ||
| 1516 | } else | ||
| 1517 | file = filp_open(corename, | ||
| 1518 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600); | ||
| 1508 | if (IS_ERR(file)) | 1519 | if (IS_ERR(file)) |
| 1509 | goto fail_unlock; | 1520 | goto fail_unlock; |
| 1510 | inode = file->f_dentry->d_inode; | 1521 | inode = file->f_dentry->d_inode; |
| 1511 | if (inode->i_nlink > 1) | 1522 | if (inode->i_nlink > 1) |
| 1512 | goto close_fail; /* multiple links - don't dump */ | 1523 | goto close_fail; /* multiple links - don't dump */ |
| 1513 | if (d_unhashed(file->f_dentry)) | 1524 | if (!ispipe && d_unhashed(file->f_dentry)) |
| 1514 | goto close_fail; | 1525 | goto close_fail; |
| 1515 | 1526 | ||
| 1516 | if (!S_ISREG(inode->i_mode)) | 1527 | /* AK: actually i see no reason to not allow this for named pipes etc., |
| 1528 | but keep the previous behaviour for now. */ | ||
| 1529 | if (!ispipe && !S_ISREG(inode->i_mode)) | ||
| 1517 | goto close_fail; | 1530 | goto close_fail; |
| 1518 | if (!file->f_op) | 1531 | if (!file->f_op) |
| 1519 | goto close_fail; | 1532 | goto close_fail; |
| 1520 | if (!file->f_op->write) | 1533 | if (!file->f_op->write) |
| 1521 | goto close_fail; | 1534 | goto close_fail; |
| 1522 | if (do_truncate(file->f_dentry, 0, 0, file) != 0) | 1535 | if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0) |
| 1523 | goto close_fail; | 1536 | goto close_fail; |
| 1524 | 1537 | ||
| 1525 | retval = binfmt->core_dump(signr, regs, file); | 1538 | retval = binfmt->core_dump(signr, regs, file); |
