diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 7cb28720f90e..669dbe5b0317 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -682,6 +682,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
682 | retval = PTR_ERR(interpreter); | 682 | retval = PTR_ERR(interpreter); |
683 | if (IS_ERR(interpreter)) | 683 | if (IS_ERR(interpreter)) |
684 | goto out_free_interp; | 684 | goto out_free_interp; |
685 | |||
686 | /* | ||
687 | * If the binary is not readable then enforce | ||
688 | * mm->dumpable = 0 regardless of the interpreter's | ||
689 | * permissions. | ||
690 | */ | ||
691 | if (file_permission(interpreter, MAY_READ) < 0) | ||
692 | bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; | ||
693 | |||
685 | retval = kernel_read(interpreter, 0, bprm->buf, | 694 | retval = kernel_read(interpreter, 0, bprm->buf, |
686 | BINPRM_BUF_SIZE); | 695 | BINPRM_BUF_SIZE); |
687 | if (retval != BINPRM_BUF_SIZE) { | 696 | if (retval != BINPRM_BUF_SIZE) { |
@@ -1178,6 +1187,10 @@ static int dump_seek(struct file *file, loff_t off) | |||
1178 | */ | 1187 | */ |
1179 | static int maydump(struct vm_area_struct *vma) | 1188 | static int maydump(struct vm_area_struct *vma) |
1180 | { | 1189 | { |
1190 | /* The vma can be set up to tell us the answer directly. */ | ||
1191 | if (vma->vm_flags & VM_ALWAYSDUMP) | ||
1192 | return 1; | ||
1193 | |||
1181 | /* Do not dump I/O mapped devices or special mappings */ | 1194 | /* Do not dump I/O mapped devices or special mappings */ |
1182 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1195 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) |
1183 | return 0; | 1196 | return 0; |
@@ -1424,6 +1437,32 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | |||
1424 | return sz; | 1437 | return sz; |
1425 | } | 1438 | } |
1426 | 1439 | ||
1440 | static struct vm_area_struct *first_vma(struct task_struct *tsk, | ||
1441 | struct vm_area_struct *gate_vma) | ||
1442 | { | ||
1443 | struct vm_area_struct *ret = tsk->mm->mmap; | ||
1444 | |||
1445 | if (ret) | ||
1446 | return ret; | ||
1447 | return gate_vma; | ||
1448 | } | ||
1449 | /* | ||
1450 | * Helper function for iterating across a vma list. It ensures that the caller | ||
1451 | * will visit `gate_vma' prior to terminating the search. | ||
1452 | */ | ||
1453 | static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | ||
1454 | struct vm_area_struct *gate_vma) | ||
1455 | { | ||
1456 | struct vm_area_struct *ret; | ||
1457 | |||
1458 | ret = this_vma->vm_next; | ||
1459 | if (ret) | ||
1460 | return ret; | ||
1461 | if (this_vma == gate_vma) | ||
1462 | return NULL; | ||
1463 | return gate_vma; | ||
1464 | } | ||
1465 | |||
1427 | /* | 1466 | /* |
1428 | * Actual dumper | 1467 | * Actual dumper |
1429 | * | 1468 | * |
@@ -1439,7 +1478,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1439 | int segs; | 1478 | int segs; |
1440 | size_t size = 0; | 1479 | size_t size = 0; |
1441 | int i; | 1480 | int i; |
1442 | struct vm_area_struct *vma; | 1481 | struct vm_area_struct *vma, *gate_vma; |
1443 | struct elfhdr *elf = NULL; | 1482 | struct elfhdr *elf = NULL; |
1444 | loff_t offset = 0, dataoff, foffset; | 1483 | loff_t offset = 0, dataoff, foffset; |
1445 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1484 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
@@ -1525,6 +1564,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1525 | segs += ELF_CORE_EXTRA_PHDRS; | 1564 | segs += ELF_CORE_EXTRA_PHDRS; |
1526 | #endif | 1565 | #endif |
1527 | 1566 | ||
1567 | gate_vma = get_gate_vma(current); | ||
1568 | if (gate_vma != NULL) | ||
1569 | segs++; | ||
1570 | |||
1528 | /* Set up header */ | 1571 | /* Set up header */ |
1529 | fill_elf_header(elf, segs + 1); /* including notes section */ | 1572 | fill_elf_header(elf, segs + 1); /* including notes section */ |
1530 | 1573 | ||
@@ -1592,7 +1635,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1592 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1635 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1593 | 1636 | ||
1594 | /* Write program headers for segments dump */ | 1637 | /* Write program headers for segments dump */ |
1595 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1638 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1639 | vma = next_vma(vma, gate_vma)) { | ||
1596 | struct elf_phdr phdr; | 1640 | struct elf_phdr phdr; |
1597 | size_t sz; | 1641 | size_t sz; |
1598 | 1642 | ||
@@ -1641,7 +1685,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1641 | /* Align to page */ | 1685 | /* Align to page */ |
1642 | DUMP_SEEK(dataoff - foffset); | 1686 | DUMP_SEEK(dataoff - foffset); |
1643 | 1687 | ||
1644 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1688 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1689 | vma = next_vma(vma, gate_vma)) { | ||
1645 | unsigned long addr; | 1690 | unsigned long addr; |
1646 | 1691 | ||
1647 | if (!maydump(vma)) | 1692 | if (!maydump(vma)) |