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 a27e42bf3400..ba24cb2ff6ce 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 | } |
@@ -826,10 +836,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
826 | } | 836 | } |
827 | 837 | ||
828 | /* OK, This is the point of no return */ | 838 | /* OK, This is the point of no return */ |
829 | current->mm->start_data = 0; | ||
830 | current->mm->end_data = 0; | ||
831 | current->mm->end_code = 0; | ||
832 | current->mm->mmap = NULL; | ||
833 | current->flags &= ~PF_FORKNOEXEC; | 839 | current->flags &= ~PF_FORKNOEXEC; |
834 | current->mm->def_flags = def_flags; | 840 | current->mm->def_flags = def_flags; |
835 | 841 | ||
@@ -1051,9 +1057,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
1051 | 1057 | ||
1052 | compute_creds(bprm); | 1058 | compute_creds(bprm); |
1053 | current->flags &= ~PF_FORKNOEXEC; | 1059 | current->flags &= ~PF_FORKNOEXEC; |
1054 | create_elf_tables(bprm, &loc->elf_ex, | 1060 | retval = create_elf_tables(bprm, &loc->elf_ex, |
1055 | (interpreter_type == INTERPRETER_AOUT), | 1061 | (interpreter_type == INTERPRETER_AOUT), |
1056 | load_addr, interp_load_addr); | 1062 | load_addr, interp_load_addr); |
1063 | if (retval < 0) { | ||
1064 | send_sig(SIGKILL, current, 0); | ||
1065 | goto out; | ||
1066 | } | ||
1057 | /* N.B. passed_fileno might not be initialized? */ | 1067 | /* N.B. passed_fileno might not be initialized? */ |
1058 | if (interpreter_type == INTERPRETER_AOUT) | 1068 | if (interpreter_type == INTERPRETER_AOUT) |
1059 | current->mm->arg_start += strlen(passed_fileno) + 1; | 1069 | current->mm->arg_start += strlen(passed_fileno) + 1; |
@@ -1252,7 +1262,7 @@ static int dump_seek(struct file *file, loff_t off) | |||
1252 | * | 1262 | * |
1253 | * I think we should skip something. But I am not sure how. H.J. | 1263 | * I think we should skip something. But I am not sure how. H.J. |
1254 | */ | 1264 | */ |
1255 | static int maydump(struct vm_area_struct *vma) | 1265 | static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) |
1256 | { | 1266 | { |
1257 | /* The vma can be set up to tell us the answer directly. */ | 1267 | /* The vma can be set up to tell us the answer directly. */ |
1258 | if (vma->vm_flags & VM_ALWAYSDUMP) | 1268 | if (vma->vm_flags & VM_ALWAYSDUMP) |
@@ -1262,15 +1272,19 @@ static int maydump(struct vm_area_struct *vma) | |||
1262 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1272 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) |
1263 | return 0; | 1273 | return 0; |
1264 | 1274 | ||
1265 | /* Dump shared memory only if mapped from an anonymous file. */ | 1275 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1266 | if (vma->vm_flags & VM_SHARED) | 1276 | if (vma->vm_flags & VM_SHARED) { |
1267 | return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0; | 1277 | if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) |
1278 | return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); | ||
1279 | else | ||
1280 | return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); | ||
1281 | } | ||
1268 | 1282 | ||
1269 | /* If it hasn't been written to, don't write it out */ | 1283 | /* By default, if it hasn't been written to, don't write it out. */ |
1270 | if (!vma->anon_vma) | 1284 | if (!vma->anon_vma) |
1271 | return 0; | 1285 | return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); |
1272 | 1286 | ||
1273 | return 1; | 1287 | return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); |
1274 | } | 1288 | } |
1275 | 1289 | ||
1276 | /* An ELF note in memory */ | 1290 | /* An ELF note in memory */ |
@@ -1562,6 +1576,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1562 | #endif | 1576 | #endif |
1563 | int thread_status_size = 0; | 1577 | int thread_status_size = 0; |
1564 | elf_addr_t *auxv; | 1578 | elf_addr_t *auxv; |
1579 | unsigned long mm_flags; | ||
1565 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES | 1580 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES |
1566 | int extra_notes_size; | 1581 | int extra_notes_size; |
1567 | #endif | 1582 | #endif |
@@ -1705,6 +1720,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1705 | 1720 | ||
1706 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1721 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1707 | 1722 | ||
1723 | /* | ||
1724 | * We must use the same mm->flags while dumping core to avoid | ||
1725 | * inconsistency between the program headers and bodies, otherwise an | ||
1726 | * unusable core file can be generated. | ||
1727 | */ | ||
1728 | mm_flags = current->mm->flags; | ||
1729 | |||
1708 | /* Write program headers for segments dump */ | 1730 | /* Write program headers for segments dump */ |
1709 | for (vma = first_vma(current, gate_vma); vma != NULL; | 1731 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1710 | vma = next_vma(vma, gate_vma)) { | 1732 | vma = next_vma(vma, gate_vma)) { |
@@ -1717,7 +1739,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1717 | phdr.p_offset = offset; | 1739 | phdr.p_offset = offset; |
1718 | phdr.p_vaddr = vma->vm_start; | 1740 | phdr.p_vaddr = vma->vm_start; |
1719 | phdr.p_paddr = 0; | 1741 | phdr.p_paddr = 0; |
1720 | phdr.p_filesz = maydump(vma) ? sz : 0; | 1742 | phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; |
1721 | phdr.p_memsz = sz; | 1743 | phdr.p_memsz = sz; |
1722 | offset += phdr.p_filesz; | 1744 | offset += phdr.p_filesz; |
1723 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1745 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
@@ -1761,7 +1783,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1761 | vma = next_vma(vma, gate_vma)) { | 1783 | vma = next_vma(vma, gate_vma)) { |
1762 | unsigned long addr; | 1784 | unsigned long addr; |
1763 | 1785 | ||
1764 | if (!maydump(vma)) | 1786 | if (!maydump(vma, mm_flags)) |
1765 | continue; | 1787 | continue; |
1766 | 1788 | ||
1767 | for (addr = vma->vm_start; | 1789 | for (addr = vma->vm_start; |