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