diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 08e4414b8374..4482a0673b15 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
148 | elf_addr_t *elf_info; | 148 | elf_addr_t *elf_info; |
149 | int ei_index = 0; | 149 | int ei_index = 0; |
150 | struct task_struct *tsk = current; | 150 | struct task_struct *tsk = current; |
151 | struct vm_area_struct *vma; | ||
151 | 152 | ||
152 | /* | 153 | /* |
153 | * If this architecture has a platform capability string, copy it | 154 | * If this architecture has a platform capability string, copy it |
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
234 | sp = (elf_addr_t __user *)bprm->p; | 235 | sp = (elf_addr_t __user *)bprm->p; |
235 | #endif | 236 | #endif |
236 | 237 | ||
238 | |||
239 | /* | ||
240 | * Grow the stack manually; some architectures have a limit on how | ||
241 | * far ahead a user-space access may be in order to grow the stack. | ||
242 | */ | ||
243 | vma = find_extend_vma(current->mm, bprm->p); | ||
244 | if (!vma) | ||
245 | return -EFAULT; | ||
246 | |||
237 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ | 247 | /* Now, let's put argc (and argv, envp if appropriate) on the stack */ |
238 | if (__put_user(argc, sp++)) | 248 | if (__put_user(argc, sp++)) |
239 | return -EFAULT; | 249 | return -EFAULT; |
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
254 | size_t len; | 264 | size_t len; |
255 | if (__put_user((elf_addr_t)p, argv++)) | 265 | if (__put_user((elf_addr_t)p, argv++)) |
256 | return -EFAULT; | 266 | return -EFAULT; |
257 | len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); | 267 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
258 | if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) | 268 | if (!len || len > MAX_ARG_STRLEN) |
259 | return 0; | 269 | return 0; |
260 | p += len; | 270 | p += len; |
261 | } | 271 | } |
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
266 | size_t len; | 276 | size_t len; |
267 | if (__put_user((elf_addr_t)p, envp++)) | 277 | if (__put_user((elf_addr_t)p, envp++)) |
268 | return -EFAULT; | 278 | return -EFAULT; |
269 | len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); | 279 | len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); |
270 | if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) | 280 | if (!len || len > MAX_ARG_STRLEN) |
271 | return 0; | 281 | return 0; |
272 | p += len; | 282 | p += len; |
273 | } | 283 | } |
@@ -777,10 +787,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
777 | } | 787 | } |
778 | 788 | ||
779 | /* OK, This is the point of no return */ | 789 | /* OK, This is the point of no return */ |
780 | current->mm->start_data = 0; | ||
781 | current->mm->end_data = 0; | ||
782 | current->mm->end_code = 0; | ||
783 | current->mm->mmap = NULL; | ||
784 | current->flags &= ~PF_FORKNOEXEC; | 790 | current->flags &= ~PF_FORKNOEXEC; |
785 | current->mm->def_flags = def_flags; | 791 | current->mm->def_flags = def_flags; |
786 | 792 | ||
@@ -988,9 +994,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
988 | 994 | ||
989 | compute_creds(bprm); | 995 | compute_creds(bprm); |
990 | current->flags &= ~PF_FORKNOEXEC; | 996 | current->flags &= ~PF_FORKNOEXEC; |
991 | create_elf_tables(bprm, &loc->elf_ex, | 997 | retval = create_elf_tables(bprm, &loc->elf_ex, |
992 | (interpreter_type == INTERPRETER_AOUT), | 998 | (interpreter_type == INTERPRETER_AOUT), |
993 | load_addr, interp_load_addr); | 999 | load_addr, interp_load_addr); |
1000 | if (retval < 0) { | ||
1001 | send_sig(SIGKILL, current, 0); | ||
1002 | goto out; | ||
1003 | } | ||
994 | /* N.B. passed_fileno might not be initialized? */ | 1004 | /* N.B. passed_fileno might not be initialized? */ |
995 | if (interpreter_type == INTERPRETER_AOUT) | 1005 | if (interpreter_type == INTERPRETER_AOUT) |
996 | current->mm->arg_start += strlen(passed_fileno) + 1; | 1006 | current->mm->arg_start += strlen(passed_fileno) + 1; |
@@ -1189,7 +1199,7 @@ static int dump_seek(struct file *file, loff_t off) | |||
1189 | * | 1199 | * |
1190 | * I think we should skip something. But I am not sure how. H.J. | 1200 | * I think we should skip something. But I am not sure how. H.J. |
1191 | */ | 1201 | */ |
1192 | static int maydump(struct vm_area_struct *vma) | 1202 | static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) |
1193 | { | 1203 | { |
1194 | /* The vma can be set up to tell us the answer directly. */ | 1204 | /* The vma can be set up to tell us the answer directly. */ |
1195 | if (vma->vm_flags & VM_ALWAYSDUMP) | 1205 | if (vma->vm_flags & VM_ALWAYSDUMP) |
@@ -1199,15 +1209,19 @@ static int maydump(struct vm_area_struct *vma) | |||
1199 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1209 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) |
1200 | return 0; | 1210 | return 0; |
1201 | 1211 | ||
1202 | /* Dump shared memory only if mapped from an anonymous file. */ | 1212 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1203 | if (vma->vm_flags & VM_SHARED) | 1213 | if (vma->vm_flags & VM_SHARED) { |
1204 | return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0; | 1214 | if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) |
1215 | return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); | ||
1216 | else | ||
1217 | return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); | ||
1218 | } | ||
1205 | 1219 | ||
1206 | /* If it hasn't been written to, don't write it out */ | 1220 | /* By default, if it hasn't been written to, don't write it out. */ |
1207 | if (!vma->anon_vma) | 1221 | if (!vma->anon_vma) |
1208 | return 0; | 1222 | return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); |
1209 | 1223 | ||
1210 | return 1; | 1224 | return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); |
1211 | } | 1225 | } |
1212 | 1226 | ||
1213 | /* An ELF note in memory */ | 1227 | /* An ELF note in memory */ |
@@ -1499,6 +1513,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1499 | #endif | 1513 | #endif |
1500 | int thread_status_size = 0; | 1514 | int thread_status_size = 0; |
1501 | elf_addr_t *auxv; | 1515 | elf_addr_t *auxv; |
1516 | unsigned long mm_flags; | ||
1502 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES | 1517 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES |
1503 | int extra_notes_size; | 1518 | int extra_notes_size; |
1504 | #endif | 1519 | #endif |
@@ -1642,6 +1657,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1642 | 1657 | ||
1643 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1658 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1644 | 1659 | ||
1660 | /* | ||
1661 | * We must use the same mm->flags while dumping core to avoid | ||
1662 | * inconsistency between the program headers and bodies, otherwise an | ||
1663 | * unusable core file can be generated. | ||
1664 | */ | ||
1665 | mm_flags = current->mm->flags; | ||
1666 | |||
1645 | /* Write program headers for segments dump */ | 1667 | /* Write program headers for segments dump */ |
1646 | for (vma = first_vma(current, gate_vma); vma != NULL; | 1668 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1647 | vma = next_vma(vma, gate_vma)) { | 1669 | vma = next_vma(vma, gate_vma)) { |
@@ -1654,7 +1676,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1654 | phdr.p_offset = offset; | 1676 | phdr.p_offset = offset; |
1655 | phdr.p_vaddr = vma->vm_start; | 1677 | phdr.p_vaddr = vma->vm_start; |
1656 | phdr.p_paddr = 0; | 1678 | phdr.p_paddr = 0; |
1657 | phdr.p_filesz = maydump(vma) ? sz : 0; | 1679 | phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; |
1658 | phdr.p_memsz = sz; | 1680 | phdr.p_memsz = sz; |
1659 | offset += phdr.p_filesz; | 1681 | offset += phdr.p_filesz; |
1660 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1682 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
@@ -1698,7 +1720,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1698 | vma = next_vma(vma, gate_vma)) { | 1720 | vma = next_vma(vma, gate_vma)) { |
1699 | unsigned long addr; | 1721 | unsigned long addr; |
1700 | 1722 | ||
1701 | if (!maydump(vma)) | 1723 | if (!maydump(vma, mm_flags)) |
1702 | continue; | 1724 | continue; |
1703 | 1725 | ||
1704 | for (addr = vma->vm_start; | 1726 | for (addr = vma->vm_start; |