X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fbinfmt_elf_fdpic.c;h=5810aa1339fdeb5d6d98dd857328998bcde733e5;hb=557ed1fa2620dc119adb86b34c614e152a629a80;hp=f86d5c9ce5ebda5eaf4c94fbd441dd770a24b9c4;hpb=59458f40e25915a355d8b1d701425fe9f4f9ea23;p=linux-2.6 diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index f86d5c9ce5..c5ca2f0aca 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -40,9 +39,6 @@ #include typedef char *elf_caddr_t; -#ifndef elf_addr_t -#define elf_addr_t unsigned long -#endif #if 0 #define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) @@ -182,6 +178,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, int executable_stack; int retval, i; + kdebug("____ LOAD %d ____", current->pid); + memset(&exec_params, 0, sizeof(exec_params)); memset(&interp_params, 0, sizeof(interp_params)); @@ -237,6 +235,14 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, goto error; } + /* + * If the binary is not readable then enforce + * mm->dumpable = 0 regardless of the interpreter's + * permissions. + */ + if (file_permission(interpreter, MAY_READ) < 0) + bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; + retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); if (retval < 0) @@ -367,7 +373,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, down_write(¤t->mm->mmap_sem); current->mm->start_brk = do_mmap(NULL, 0, stack_size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, 0); if (IS_ERR_VALUE(current->mm->start_brk)) { @@ -615,8 +621,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, p = (char __user *) current->mm->arg_start; for (loop = bprm->argc; loop > 0; loop--) { __put_user((elf_caddr_t) p, argv++); - len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES); - if (!len || len > PAGE_SIZE * MAX_ARG_PAGES) + len = strnlen_user(p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } @@ -627,8 +633,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, current->mm->env_start = (unsigned long) p; for (loop = bprm->envc; loop > 0; loop--) { __put_user((elf_caddr_t)(unsigned long) p, envp++); - len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES); - if (!len || len > PAGE_SIZE * MAX_ARG_PAGES) + len = strnlen_user(p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) return -EINVAL; p += len; } @@ -709,12 +715,11 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, return -ELIBBAD; size = sizeof(*loadmap) + nloads * sizeof(*seg); - loadmap = kmalloc(size, GFP_KERNEL); + loadmap = kzalloc(size, GFP_KERNEL); if (!loadmap) return -ENOMEM; params->loadmap = loadmap; - memset(loadmap, 0, size); loadmap->version = ELF32_FDPIC_LOADMAP_VERSION; loadmap->nsegs = nloads; @@ -858,7 +863,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, dynamic_error: printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n", - what, file->f_dentry->d_inode->i_ino); + what, file->f_path.dentry->d_inode->i_ino); return -ELIBBAD; } @@ -937,8 +942,11 @@ static int elf_fdpic_map_file_constdisp_on_uclinux( if (mm) { if (phdr->p_flags & PF_X) { - mm->start_code = seg->addr; - mm->end_code = seg->addr + phdr->p_memsz; + if (!mm->start_code) { + mm->start_code = seg->addr; + mm->end_code = seg->addr + + phdr->p_memsz; + } } else if (!mm->start_data) { mm->start_data = seg->addr; #ifndef CONFIG_MMU @@ -1119,8 +1127,10 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, if (mm) { if (phdr->p_flags & PF_X) { - mm->start_code = maddr; - mm->end_code = maddr + phdr->p_memsz; + if (!mm->start_code) { + mm->start_code = maddr; + mm->end_code = maddr + phdr->p_memsz; + } } else if (!mm->start_data) { mm->start_data = maddr; mm->end_data = maddr + phdr->p_memsz; @@ -1171,8 +1181,10 @@ static int dump_seek(struct file *file, loff_t off) * * I think we should skip something. But I am not sure how. H.J. */ -static int maydump(struct vm_area_struct *vma) +static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) { + int dump_ok; + /* Do not dump I/O mapped devices or special mappings */ if (vma->vm_flags & (VM_IO | VM_RESERVED)) { kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags); @@ -1187,27 +1199,35 @@ static int maydump(struct vm_area_struct *vma) return 0; } - /* Dump shared memory only if mapped from an anonymous file. */ + /* By default, dump shared memory if mapped from an anonymous file. */ if (vma->vm_flags & VM_SHARED) { - if (vma->vm_file->f_dentry->d_inode->i_nlink == 0) { - kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags); - return 1; + if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) { + dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); + kdcore("%08lx: %08lx: %s (share)", vma->vm_start, + vma->vm_flags, dump_ok ? "yes" : "no"); + return dump_ok; } - kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags); - return 0; + dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); + kdcore("%08lx: %08lx: %s (share)", vma->vm_start, + vma->vm_flags, dump_ok ? "yes" : "no"); + return dump_ok; } #ifdef CONFIG_MMU - /* If it hasn't been written to, don't write it out */ + /* By default, if it hasn't been written to, don't write it out */ if (!vma->anon_vma) { - kdcore("%08lx: %08lx: no (!anon)", vma->vm_start, vma->vm_flags); - return 0; + dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); + kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start, + vma->vm_flags, dump_ok ? "yes" : "no"); + return dump_ok; } #endif - kdcore("%08lx: %08lx: yes", vma->vm_start, vma->vm_flags); - return 1; + dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); + kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags, + dump_ok ? "yes" : "no"); + return dump_ok; } /* An ELF note in memory */ @@ -1325,7 +1345,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, prstatus->pr_pid = p->pid; prstatus->pr_ppid = p->parent->pid; prstatus->pr_pgrp = process_group(p); - prstatus->pr_sid = p->signal->session; + prstatus->pr_sid = process_session(p); if (thread_group_leader(p)) { /* * This is the record for the group leader. Add in the @@ -1374,7 +1394,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, psinfo->pr_pid = p->pid; psinfo->pr_ppid = p->parent->pid; psinfo->pr_pgrp = process_group(p); - psinfo->pr_sid = p->signal->session; + psinfo->pr_sid = process_session(p); i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; @@ -1446,15 +1466,15 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) * dump the segments for an MMU process */ #ifdef CONFIG_MMU -static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm, - size_t *size, unsigned long *limit) +static int elf_fdpic_dump_segments(struct file *file, size_t *size, + unsigned long *limit, unsigned long mm_flags) { struct vm_area_struct *vma; for (vma = current->mm->mmap; vma; vma = vma->vm_next) { unsigned long addr; - if (!maydump(vma)) + if (!maydump(vma, mm_flags)) continue; for (addr = vma->vm_start; @@ -1468,9 +1488,9 @@ static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm, &page, &vma) <= 0) { DUMP_SEEK(file->f_pos + PAGE_SIZE); } - else if (page == ZERO_PAGE(addr)) { - DUMP_SEEK(file->f_pos + PAGE_SIZE); + else if (page == ZERO_PAGE(0)) { page_cache_release(page); + DUMP_SEEK(file->f_pos + PAGE_SIZE); } else { void *kaddr; @@ -1501,15 +1521,15 @@ end_coredump: * dump the segments for a NOMMU process */ #ifndef CONFIG_MMU -static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm, - size_t *size, unsigned long *limit) +static int elf_fdpic_dump_segments(struct file *file, size_t *size, + unsigned long *limit, unsigned long mm_flags) { struct vm_list_struct *vml; for (vml = current->mm->context.vmlist; vml; vml = vml->next) { struct vm_area_struct *vma = vml->vma; - if (!maydump(vma)) + if (!maydump(vma, mm_flags)) continue; if ((*size += PAGE_SIZE) > *limit) @@ -1560,6 +1580,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, struct vm_list_struct *vml; #endif elf_addr_t *auxv; + unsigned long mm_flags; /* * We no longer stop all VM operations. @@ -1697,6 +1718,13 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); + /* + * We must use the same mm->flags while dumping core to avoid + * inconsistency between the program headers and bodies, otherwise an + * unusable core file can be generated. + */ + mm_flags = current->mm->flags; + /* write program headers for segments dump */ for ( #ifdef CONFIG_MMU @@ -1718,7 +1746,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; - phdr.p_filesz = maydump(vma) ? sz : 0; + phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; @@ -1752,7 +1780,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, DUMP_SEEK(dataoff); - if (elf_fdpic_dump_segments(file, current->mm, &size, &limit) < 0) + if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0) goto end_coredump; #ifdef ELF_CORE_WRITE_EXTRA_DATA