static struct mm_struct * mm_init(struct mm_struct * mm) { atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); INIT_LIST_HEAD(&mm->mmlist); mm->flags = (current->mm) ? current->mm->flags : MMF_DUMP_FILTER_DEFAULT; mm->core_waiters = 0; mm->nr_ptes = 0; set_mm_counter(mm, file_rss, 0); set_mm_counter(mm, anon_rss, 0); spin_lock_init(&mm->page_table_lock); rwlock_init(&mm->ioctx_list_lock); mm->ioctx_list = NULL; mm->free_area_cache = TASK_UNMAPPED_BASE; mm->cached_hole_size = ~0UL; if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; return mm; } free_mm(mm); return NULL; }
static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p) { atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); INIT_LIST_HEAD(&mm->mmlist); mm->flags = (current->mm) ? (current->mm->flags & MMF_INIT_MASK) : default_dump_filter; mm->core_state = NULL; mm->nr_ptes = 0; set_mm_counter(mm, file_rss, 0); set_mm_counter(mm, anon_rss, 0); spin_lock_init(&mm->page_table_lock); mm->free_area_cache = TASK_UNMAPPED_BASE; mm->cached_hole_size = ~0UL; mm_init_aio(mm); mm_init_owner(mm, p); if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; mmu_notifier_mm_init(mm); return mm; } free_mm(mm); return NULL; }
/* * Helper function to process the load operation. */ static int xout_load_object(struct linux_binprm * bpp, struct pt_regs *rp, int executable) { struct xexec *xexec = (struct xexec *)bpp->buf; struct xext *xext = (struct xext *)(xexec + 1); struct xseg *seglist; struct file *fp = NULL; u_long addr, lPers; int nsegs, ntext, ndata; int pageable = 1, err = 0, i; #ifdef CONFIG_BINFMT_XOUT_X286 struct file *file; #endif lPers = abi_personality((char *)_BX(rp)); if (lPers == 0) lPers = PER_XENIX; if (xexec->x_magic != X_MAGIC) { return -ENOEXEC; } switch (xexec->x_cpu & XC_CPU) { case XC_386: break; #if defined(CONFIG_BINFMT_XOUT_X286) case XC_8086: case XC_286: case XC_286V: case XC_186: if (!Emulx286) return -ENOEXEC; file = open_exec(Emulx286); if (file) { fput(bpp->file); bpp->file = file; kernel_read(bpp->file, 0L, bpp->buf, sizeof(bpp->buf)); } return -ENOEXEC; #endif default: dprintk(KERN_DEBUG "xout: unsupported CPU type (%02x)\n", xexec->x_cpu); return -ENOEXEC; } /* * We can't handle byte or word swapped headers. Well, we * *could* but they should never happen surely? */ if ((xexec->x_cpu & (XC_BSWAP | XC_WSWAP)) != XC_WSWAP) { dprintk(KERN_DEBUG "xout: wrong byte or word sex (%02x)\n", xexec->x_cpu); return -ENOEXEC; } /* Check it's an executable. */ if (!(xexec->x_renv & XE_EXEC)) { dprintk(KERN_DEBUG "xout: not executable\n"); return -ENOEXEC; } /* * There should be an extended header and there should be * some segments. At this stage we don't handle non-segmented * binaries. I'm not sure you can get them under Xenix anyway. */ if (xexec->x_ext != sizeof(struct xext)) { dprintk(KERN_DEBUG "xout: bad extended header\n"); return -ENOEXEC; } if (!(xexec->x_renv & XE_SEG) || !xext->xe_segsize) { dprintk(KERN_DEBUG "xout: not segmented\n"); return -ENOEXEC; } if (!(seglist = kmalloc(xext->xe_segsize, GFP_KERNEL))) { printk(KERN_WARNING "xout: allocating segment list failed\n"); return -ENOMEM; } err = kernel_read(bpp->file, xext->xe_segpos, (char *)seglist, xext->xe_segsize); if (err < 0) { dprintk(KERN_DEBUG "xout: problem reading segment table\n"); goto out; } if (!bpp->file->f_op->mmap) pageable = 0; nsegs = xext->xe_segsize / sizeof(struct xseg); ntext = ndata = 0; for (i = 0; i < nsegs; i++) { switch (seglist[i].xs_type) { case XS_TTEXT: if (isnotaligned(seglist+i)) pageable = 0; ntext++; break; case XS_TDATA: if (isnotaligned(seglist+i)) pageable = 0; ndata++; break; } } if (!ndata) goto out; /* * Generate the proper values for the text fields * * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD. */ /* * Flush the executable from memory. At this point the executable is * committed to being defined or a segmentation violation will occur. */ if (executable) { dprintk(KERN_DEBUG "xout: flushing executable\n"); flush_old_exec(bpp); if ( (lPers & 0xFF) == (current->personality & 0xFF) ) set_personality(0); set_personality(lPers); #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_UNIMPL, "Personality %08X assigned\n", (unsigned int)current->personality); #endif #ifdef CONFIG_64BIT set_thread_flag(TIF_IA32); clear_thread_flag(TIF_ABI_PENDING); #endif current->mm->mmap = NULL; #ifdef set_mm_counter #if _KSL > 14 set_mm_counter(current->mm, file_rss, 0); #else set_mm_counter(current->mm, rss, 0); #endif #else current->mm->rss = 0; #endif #if _KSL > 10 if ((err = setup_arg_pages(bpp, STACK_TOP, EXSTACK_DEFAULT)) < 0) #else if ((err = setup_arg_pages(bpp, EXSTACK_DEFAULT)) < 0) #endif { send_sig(SIGSEGV, current, 1); return (err); } bpp->p = (u_long)xout_create_tables((char *)bpp->p, bpp, (xexec->x_cpu & XC_CPU) == XC_386 ? 1 : 0); current->mm->start_code = 0; current->mm->end_code = xexec->x_text; current->mm->end_data = xexec->x_text + xexec->x_data; current->mm->start_brk = current->mm->brk = xexec->x_text + xexec->x_data + xexec->x_bss; #if _KSL > 28 install_exec_creds(bpp); #else compute_creds(bpp); #endif current->flags &= ~PF_FORKNOEXEC; #if _KSL < 15 #ifdef CONFIG_64BIT __asm__ volatile ( "movl %0,%%fs; movl %0,%%es; movl %0,%%ds" : :"r" (0)); __asm__ volatile ( "pushf; cli; swapgs; movl %0,%%gs; mfence; swapgs; popf" : :"r" (0)); write_pda(oldrsp,bpp->p); _FLG(rp) = 0x200; #else __asm__ volatile ( "movl %0,%%fs ; movl %0,%%gs" : :"r" (0)); _DS(rp) = _ES(rp) = __USER_DS; #endif _SS(rp) = __USER_DS; _SP(rp) = bpp->p; _CS(rp) = __USER_CS; _IP(rp) = xexec->x_entry; set_fs(USER_DS); #else start_thread(rp, xexec->x_entry, bpp->p); #endif #ifdef CONFIG_64BIT __asm__ volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); _SS(rp) = __USER32_DS; _CS(rp) = __USER32_CS; #endif dprintk(KERN_DEBUG "xout: entry point = 0x%x:0x%08lx\n", xext->xe_eseg, xexec->x_entry); } /* * Scan the segments and map them into the process space. If this * executable is pageable (unlikely since Xenix aligns to 1k * boundaries and we want it aligned to 4k boundaries) this is * all we need to do. If it isn't pageable we go round again * afterwards and load the data. We have to do this in two steps * because if segments overlap within a 4K page we'll lose the * first instance when we remap the page. Hope that's clear... */ for (i = 0; err >= 0 && i < nsegs; i++) { struct xseg *sp = seglist+i; if (sp->xs_attr & XS_AMEM) { err = xout_amen(fp, sp, pageable, &addr, xexec, rp, (!ntext && ndata == 1)); } } /* * We better fix start_data because sys_brk looks there to * calculate data size. * Kernel 2.2 did look at end_code so this is reasonable. */ if (current->mm->start_data == current->mm->start_code) current->mm->start_data = current->mm->end_code; dprintk(KERN_DEBUG "xout: start code 0x%08lx, end code 0x%08lx," " start data 0x%08lx, end data 0x%08lx, brk 0x%08lx\n", current->mm->start_code, current->mm->end_code, current->mm->start_data, current->mm->end_data, current->mm->brk); if (pageable) goto trap; if (err < 0) goto trap; for (i = 0; (err >= 0) && (i < nsegs); i++) { struct xseg *sp = seglist + i; u_long psize; if (sp->xs_type == XS_TTEXT || sp->xs_type == XS_TDATA) { dprintk(KERN_DEBUG "xout: read to 0x%08lx from 0x%08lx," " length 0x%8lx\n", sp->xs_rbase, sp->xs_filpos, sp->xs_psize); if (sp->xs_psize < 0) continue; /* * Do we still get the size ? Yes! [joerg] */ psize = kernel_read(bpp->file, sp->xs_filpos, (char *)((long)sp->xs_rbase), sp->xs_psize); if (psize != sp->xs_psize) { dprintk(KERN_DEBUG "xout: short read 0x%8lx\n",psize); err = -1; break; } } } /* * Generate any needed trap for this process. If an error occured then * generate a segmentation violation. If the process is being debugged * then generate the load trap. (Note: If this is a library load then * do not generate the trap here. Pass the error to the caller who * will do it for the process in the outer lay of this procedure call.) */ trap: if (executable) { if (err < 0) { dprintk(KERN_DEBUG "xout: loader forces seg fault " "(err = %d)\n", err); send_sig(SIGSEGV, current, 0); } #ifdef CONFIG_PTRACE /* --- Red Hat specific handling --- */ #else else if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); #endif err = 0; } out: kfree(seglist); dprintk(KERN_DEBUG "xout: binfmt_xout: result = %d\n", err); /* * If we are using the [2]86 emulation overlay we enter this * rather than the real program and give it the information * it needs to start the ball rolling. */ /* * Xenix 386 programs expect the initial brk value to be in eax * on start up. Hence if we succeeded we need to pass back * the brk value rather than the status. Ultimately the * ret_from_sys_call assembly will place this in eax before * resuming (starting) the process. */ return (err < 0 ? err : current->mm->brk); }
static int load_fn_file(struct linux_binprm * bprm,unsigned long *extra_stack) { unsigned long stack_len; unsigned long stack_start; unsigned long start_code, end_code; unsigned long result; unsigned long rlim; stack_len = USERSPACE_STACK_SIZE; if (extra_stack) { stack_len += *extra_stack; *extra_stack = stack_len; } /* * Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; /* Flush all traces of the currently running executable */ result = flush_old_exec(bprm); if (result) return result; /* OK, This is the point of no return */ set_personality(PER_LINUX); /* * there are a couple of cases here, the separate code/data * case, and then the fully copied to RAM case which lumps * it all together. */ down_write(¤t->mm->mmap_sem); stack_start= do_mmap(0, 0,stack_len, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); if (!stack_start|| stack_start >= (unsigned long) -4096) { if (!stack_start) stack_start = (unsigned long) -ENOMEM; printk("Unable to allocate RAM for process text/data, errno %d\n", (int)-stack_start); return(stack_start); } /* The main program needs a little extra setup in the task structure */ start_code = (unsigned long)bprm->filename; end_code = start_code + PAGE_SIZE*2; current->mm->start_code = start_code; current->mm->end_code = end_code; current->mm->start_data = 0; current->mm->end_data = 0; /* * set up the brk stuff, uses any slack left in data/bss/stack * allocation. We put the brk after the bss (between the bss * and stack) like other platforms. */ current->mm->start_brk = 0; current->mm->brk = 0; current->mm->context.end_brk = stack_start; set_mm_counter(current->mm, rss, 0); flush_icache_range(start_code, end_code); memset((unsigned char*)stack_start,0,stack_len); return 0; }
static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) { struct vm_area_struct * mpnt, *tmp, **pprev; struct rb_node **rb_link, *rb_parent; int retval; unsigned long charge; struct mempolicy *pol; down_write(&oldmm->mmap_sem); flush_cache_mm(current->mm); mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; mm->free_area_cache = oldmm->mmap_base; mm->cached_hole_size = ~0UL; mm->map_count = 0; set_mm_counter(mm, rss, 0); set_mm_counter(mm, anon_rss, 0); cpus_clear(mm->cpu_vm_mask); mm->mm_rb = RB_ROOT; rb_link = &mm->mm_rb.rb_node; rb_parent = NULL; pprev = &mm->mmap; for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { struct file *file; if (mpnt->vm_flags & VM_DONTCOPY) { long pages = vma_pages(mpnt); mm->total_vm -= pages; __vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file, -pages); continue; } charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if (security_vm_enough_memory(len)) goto fail_nomem; charge = len; } tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) goto fail_nomem; *tmp = *mpnt; pol = mpol_copy(vma_policy(mpnt)); retval = PTR_ERR(pol); if (IS_ERR(pol)) goto fail_nomem_policy; vma_set_policy(tmp, pol); tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; tmp->vm_next = NULL; anon_vma_link(tmp); file = tmp->vm_file; if (file) { struct inode *inode = file->f_dentry->d_inode; get_file(file); if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); /* insert tmp into the share list, just after mpnt */ spin_lock(&file->f_mapping->i_mmap_lock); tmp->vm_truncate_count = mpnt->vm_truncate_count; flush_dcache_mmap_lock(file->f_mapping); vma_prio_tree_add(tmp, mpnt); flush_dcache_mmap_unlock(file->f_mapping); spin_unlock(&file->f_mapping->i_mmap_lock); } /* * Link in the new vma and copy the page table entries: * link in first so that swapoff can see swap entries. * Note that, exceptionally, here the vma is inserted * without holding mm->mmap_sem. */ spin_lock(&mm->page_table_lock); *pprev = tmp; pprev = &tmp->vm_next; __vma_link_rb(mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; rb_parent = &tmp->vm_rb; mm->map_count++; retval = copy_page_range(mm, current->mm, tmp); spin_unlock(&mm->page_table_lock); if (tmp->vm_ops && tmp->vm_ops->open) tmp->vm_ops->open(tmp); if (retval) goto out; }
/* These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. */ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct elfhdr elf_ex, interp_elf_ex; struct file *interpreter; struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr; unsigned int load_addr, elf_bss, elf_brk; unsigned int elf_entry, interp_load_addr = 0; unsigned int start_code, end_code, end_data, elf_stack; int retval, has_interp, has_ephdr, size, i; char *elf_interpreter; mm_segment_t old_fs; load_addr = 0; has_interp = has_ephdr = 0; elf_ihdr = elf_ephdr = NULL; elf_ex = *((struct elfhdr *) bprm->buf); retval = -ENOEXEC; if (verify_binary(&elf_ex, bprm)) goto out; /* * Telling -o32 static binaries from Linux and Irix apart from each * other is difficult. There are 2 differences to be noted for static * binaries from the 2 operating systems: * * 1) Irix binaries have their .text section before their .init * section. Linux binaries are just the opposite. * * 2) Irix binaries usually have <= 12 sections and Linux * binaries have > 20. * * We will use Method #2 since Method #1 would require us to read in * the section headers which is way too much overhead. This appears * to work for everything we have ran into so far. If anyone has a * better method to tell the binaries apart, I'm listening. */ if (elf_ex.e_shnum > 20) goto out; #ifdef DEBUG print_elfhdr(&elf_ex); #endif /* Now read in all of the header information */ size = elf_ex.e_phentsize * elf_ex.e_phnum; if (size > 65536) goto out; elf_phdata = kmalloc(size, GFP_KERNEL); if (elf_phdata == NULL) { retval = -ENOMEM; goto out; } retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size); if (retval < 0) goto out_free_ph; #ifdef DEBUG dump_phdrs(elf_phdata, elf_ex.e_phnum); #endif /* Set some things for later. */ for(i = 0; i < elf_ex.e_phnum; i++) { switch(elf_phdata[i].p_type) { case PT_INTERP: has_interp = 1; elf_ihdr = &elf_phdata[i]; break; case PT_PHDR: has_ephdr = 1; elf_ephdr = &elf_phdata[i]; break; }; } pr_debug("\n"); elf_bss = 0; elf_brk = 0; elf_stack = 0xffffffff; elf_interpreter = NULL; start_code = 0xffffffff; end_code = 0; end_data = 0; /* * If we get a return value, we change the value to be ENOEXEC * so that we can exit gracefully and the main binary format * search loop in 'fs/exec.c' will move onto the next handler * which should be the normal ELF binary handler. */ retval = look_for_irix_interpreter(&elf_interpreter, &interpreter, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); if (retval) { retval = -ENOEXEC; goto out_free_file; } if (elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); if(retval) goto out_free_interp; } /* OK, we are done with that, now set up the arg stuff, * and then start this sucker up. */ retval = -E2BIG; if (!bprm->sh_bang && !bprm->p) goto out_free_interp; /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; /* OK, This is the point of no return */ current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; elf_entry = (unsigned int) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will * change some of these later. */ set_mm_counter(current->mm, rss, 0); setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); current->mm->start_stack = bprm->p; /* At this point, we assume that the image should be loaded at * fixed address, not at a variable address. */ old_fs = get_fs(); set_fs(get_ds()); map_executable(bprm->file, elf_phdata, elf_ex.e_phnum, &elf_stack, &load_addr, &start_code, &elf_bss, &end_code, &end_data, &elf_brk); if(elf_interpreter) { retval = map_interpreter(elf_phdata, &interp_elf_ex, interpreter, &interp_load_addr, elf_ex.e_phnum, old_fs, &elf_entry); kfree(elf_interpreter); if(retval) { set_fs(old_fs); printk("Unable to load IRIX ELF interpreter\n"); send_sig(SIGSEGV, current, 0); retval = 0; goto out_free_file; } } set_fs(old_fs); kfree(elf_phdata); set_personality(PER_IRIX32); set_binfmt(&irix_format); compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) create_irix_tables((char *)bprm->p, bprm->argc, bprm->envc, (elf_interpreter ? &elf_ex : NULL), load_addr, interp_load_addr, regs, elf_ephdr); current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; /* Calling set_brk effectively mmaps the pages that we need for the * bss and break sections. */ set_brk(elf_bss, elf_brk); /* * IRIX maps a page at 0x200000 which holds some system * information. Programs depend on this. */ irix_map_prda_page(); padzero(elf_bss); pr_debug("(start_brk) %lx\n" , (long) current->mm->start_brk); pr_debug("(end_code) %lx\n" , (long) current->mm->end_code); pr_debug("(start_code) %lx\n" , (long) current->mm->start_code); pr_debug("(end_data) %lx\n" , (long) current->mm->end_data); pr_debug("(start_stack) %lx\n" , (long) current->mm->start_stack); pr_debug("(brk) %lx\n" , (long) current->mm->brk); #if 0 /* XXX No f*****g way dude... */ /* Why this, you ask??? Well SVr4 maps page 0 as read-only, * and some applications "depend" upon this behavior. * Since we do not have the power to recompile these, we * emulate the SVr4 behavior. Sigh. */ down_write(¤t->mm->mmap_sem); (void) do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); #endif start_thread(regs, elf_entry, bprm->p); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); return 0; out: return retval; out_free_dentry: allow_write_access(interpreter); fput(interpreter); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); out_free_file: out_free_ph: kfree (elf_phdata); goto out; }
/* * load an fdpic binary into various bits of memory */ static int load_elf_fdpic_binary(struct linux_binprm *bprm, struct pt_regs *regs) { struct elf_fdpic_params exec_params, interp_params; struct elf_phdr *phdr; unsigned long stack_size; struct file *interpreter = NULL; /* to shut gcc up */ char *interpreter_name = NULL; int executable_stack; int retval, i; memset(&exec_params, 0, sizeof(exec_params)); memset(&interp_params, 0, sizeof(interp_params)); exec_params.hdr = *(struct elfhdr *) bprm->buf; exec_params.flags = ELF_FDPIC_FLAG_PRESENT | ELF_FDPIC_FLAG_EXECUTABLE; /* check that this is a binary we know how to deal with */ retval = -ENOEXEC; if (!is_elf_fdpic(&exec_params.hdr, bprm->file)) goto error; /* read the program header table */ retval = elf_fdpic_fetch_phdrs(&exec_params, bprm->file); if (retval < 0) goto error; /* scan for a program header that specifies an interpreter */ phdr = exec_params.phdrs; for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) { switch (phdr->p_type) { case PT_INTERP: retval = -ENOMEM; if (phdr->p_filesz > PATH_MAX) goto error; retval = -ENOENT; if (phdr->p_filesz < 2) goto error; /* read the name of the interpreter into memory */ interpreter_name = (char *) kmalloc(phdr->p_filesz, GFP_KERNEL); if (!interpreter_name) goto error; retval = kernel_read(bprm->file, phdr->p_offset, interpreter_name, phdr->p_filesz); if (retval < 0) goto error; retval = -ENOENT; if (interpreter_name[phdr->p_filesz - 1] != '\0') goto error; kdebug("Using ELF interpreter %s", interpreter_name); /* replace the program with the interpreter */ interpreter = open_exec(interpreter_name); retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) { interpreter = NULL; goto error; } retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); if (retval < 0) goto error; interp_params.hdr = *((struct elfhdr *) bprm->buf); break; case PT_LOAD: #ifdef CONFIG_MMU if (exec_params.load_addr == 0) exec_params.load_addr = phdr->p_vaddr; #endif break; } } if (elf_check_const_displacement(&exec_params.hdr)) exec_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; /* perform insanity checks on the interpreter */ if (interpreter_name) { retval = -ELIBBAD; if (!is_elf_fdpic(&interp_params.hdr, interpreter)) goto error; interp_params.flags = ELF_FDPIC_FLAG_PRESENT; /* read the interpreter's program header table */ retval = elf_fdpic_fetch_phdrs(&interp_params, interpreter); if (retval < 0) goto error; } stack_size = exec_params.stack_size; if (stack_size < interp_params.stack_size) stack_size = interp_params.stack_size; if (exec_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) executable_stack = EXSTACK_ENABLE_X; else if (exec_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) executable_stack = EXSTACK_DISABLE_X; else if (interp_params.flags & ELF_FDPIC_FLAG_EXEC_STACK) executable_stack = EXSTACK_ENABLE_X; else if (interp_params.flags & ELF_FDPIC_FLAG_NOEXEC_STACK) executable_stack = EXSTACK_DISABLE_X; else executable_stack = EXSTACK_DEFAULT; retval = -ENOEXEC; if (stack_size == 0) goto error; if (elf_check_const_displacement(&interp_params.hdr)) interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; /* flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto error; /* there's now no turning back... the old userspace image is dead, * defunct, deceased, etc. after this point we have to exit via * error_kill */ set_personality(PER_LINUX_FDPIC); set_binfmt(&elf_fdpic_format); current->mm->start_code = 0; current->mm->end_code = 0; current->mm->start_stack = 0; current->mm->start_data = 0; current->mm->end_data = 0; current->mm->context.exec_fdpic_loadmap = 0; current->mm->context.interp_fdpic_loadmap = 0; current->flags &= ~PF_FORKNOEXEC; #ifdef CONFIG_MMU elf_fdpic_arch_lay_out_mm(&exec_params, &interp_params, ¤t->mm->start_stack, ¤t->mm->start_brk); #endif /* do this so that we can load the interpreter, if need be * - we will change some of these later */ set_mm_counter(current->mm, rss, 0); #ifdef CONFIG_MMU retval = setup_arg_pages(bprm, current->mm->start_stack, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); goto error_kill; } #endif /* load the executable and interpreter into memory */ retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, "executable"); if (retval < 0) goto error_kill; if (interpreter_name) { retval = elf_fdpic_map_file(&interp_params, interpreter, current->mm, "interpreter"); if (retval < 0) { printk(KERN_ERR "Unable to load interpreter\n"); goto error_kill; } allow_write_access(interpreter); fput(interpreter); interpreter = NULL; } #ifdef CONFIG_MMU if (!current->mm->start_brk) current->mm->start_brk = current->mm->end_data; current->mm->brk = current->mm->start_brk = PAGE_ALIGN(current->mm->start_brk); #else /* create a stack and brk area big enough for everyone * - the brk heap starts at the bottom and works up * - the stack starts at the top and works down */ stack_size = (stack_size + PAGE_SIZE - 1) & PAGE_MASK; if (stack_size < PAGE_SIZE * 2) stack_size = PAGE_SIZE * 2; 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, 0); if (IS_ERR((void *) current->mm->start_brk)) { up_write(¤t->mm->mmap_sem); retval = current->mm->start_brk; current->mm->start_brk = 0; goto error_kill; } if (do_mremap(current->mm->start_brk, stack_size, ksize((char *) current->mm->start_brk), 0, 0 ) == current->mm->start_brk ) stack_size = ksize((char *) current->mm->start_brk); up_write(¤t->mm->mmap_sem); current->mm->brk = current->mm->start_brk; current->mm->context.end_brk = current->mm->start_brk; current->mm->context.end_brk += (stack_size > PAGE_SIZE) ? (stack_size - PAGE_SIZE) : 0; current->mm->start_stack = current->mm->start_brk + stack_size; #endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (create_elf_fdpic_tables(bprm, current->mm, &exec_params, &interp_params) < 0) goto error_kill; kdebug("- start_code %lx", (long) current->mm->start_code); kdebug("- end_code %lx", (long) current->mm->end_code); kdebug("- start_data %lx", (long) current->mm->start_data); kdebug("- end_data %lx", (long) current->mm->end_data); kdebug("- start_brk %lx", (long) current->mm->start_brk); kdebug("- brk %lx", (long) current->mm->brk); kdebug("- start_stack %lx", (long) current->mm->start_stack); #ifdef ELF_FDPIC_PLAT_INIT /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. This macro performs whatever initialization to * the regs structure is required. */ ELF_FDPIC_PLAT_INIT(regs, exec_params.map_addr, interp_params.map_addr, interp_params.dynamic_addr ?: exec_params.dynamic_addr ); #endif /* everything is now ready... get the userspace context ready to roll */ start_thread(regs, interp_params.entry_addr ?: exec_params.entry_addr, current->mm->start_stack); if (unlikely(current->ptrace & PT_PTRACED)) { if (current->ptrace & PT_TRACE_EXEC) ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); else send_sig(SIGTRAP, current, 0); } retval = 0; error: if (interpreter) { allow_write_access(interpreter); fput(interpreter); } if (interpreter_name) kfree(interpreter_name); if (exec_params.phdrs) kfree(exec_params.phdrs); if (exec_params.loadmap) kfree(exec_params.loadmap); if (interp_params.phdrs) kfree(interp_params.phdrs); if (interp_params.loadmap) kfree(interp_params.loadmap); return retval; /* unrecoverable error - kill the process */ error_kill: send_sig(SIGSEGV, current, 0); goto error; } /* end load_elf_fdpic_binary() */
/* * Helper function to process the load operation. */ static int coff_load_object(struct linux_binprm *bprm, struct pt_regs *regs, int binary) { COFF_FILHDR *coff_hdr = NULL; COFF_SCNHDR *text_sect = NULL, *data_sect = NULL, *bss_sect = NULL, *sect_bufr = NULL, *sect_ptr = NULL; int text_count = 0, data_count = 0, bss_count = 0, lib_count = 0; coff_section text, data, bss; u_long start_addr = 0, p = bprm->p, m_addr, lPers; short flags, aout_size = 0; int pageable = 1, sections = 0, status = 0, i, ce; int coff_exec_fileno; mm_segment_t old_fs; lPers = abi_personality((char *)_BX(regs)); ce = cap_mmap(0); coff_hdr = (COFF_FILHDR *)bprm->buf; /* * Validate the magic value for the object file. */ if (COFF_I386BADMAG(*coff_hdr)) return -ENOEXEC; flags = COFF_SHORT(coff_hdr->f_flags); /* * The object file should have 32 BIT little endian format. Do not allow * it to have the 16 bit object file flag set as Linux is not able to run * on the 80286/80186/8086. */ if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) return -ENOEXEC; /* * If the file is not executable then reject the execution. This means * that there must not be external references. */ if ((flags & COFF_F_EXEC) == 0) return -ENOEXEC; /* * Extract the header information which we need. */ sections = COFF_SHORT(coff_hdr->f_nscns); /* Number of sections */ aout_size = COFF_SHORT(coff_hdr->f_opthdr); /* Size of opt. headr */ /* * There must be at least one section. */ if (!sections) return -ENOEXEC; if (!bprm->file->f_op->mmap) pageable = 0; if (!(sect_bufr = kmalloc(sections * COFF_SCNHSZ, GFP_KERNEL))) { printk(KERN_WARNING "coff: kmalloc failed\n"); return -ENOMEM; } status = kernel_read(bprm->file, aout_size + COFF_FILHSZ, (char *)sect_bufr, sections * COFF_SCNHSZ); if (status < 0) { printk(KERN_WARNING "coff: unable to read\n"); goto out_free_buf; } status = get_unused_fd(); if (status < 0) { printk(KERN_WARNING "coff: unable to get free fs\n"); goto out_free_buf; } get_file(bprm->file); fd_install(coff_exec_fileno = status, bprm->file); /* * Loop through the sections and find the various types */ sect_ptr = sect_bufr; for (i = 0; i < sections; i++) { long int sect_flags = COFF_LONG(sect_ptr->s_flags); switch (sect_flags) { case COFF_STYP_TEXT: status |= coff_isaligned(sect_ptr); text_sect = sect_ptr; text_count++; break; case COFF_STYP_DATA: status |= coff_isaligned(sect_ptr); data_sect = sect_ptr; data_count++; break; case COFF_STYP_BSS: bss_sect = sect_ptr; bss_count++; break; case COFF_STYP_LIB: lib_count++; break; default: break; } sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ]; } /* * If any of the sections weren't properly aligned we aren't * going to be able to demand page this executable. Note that * at this stage the *only* excuse for having status <= 0 is if * the alignment test failed. */ if (status < 0) pageable = 0; /* * Ensure that there are the required sections. There must be one * text sections and one each of the data and bss sections for an * executable. A library may or may not have a data / bss section. */ if (text_count != 1) { status = -ENOEXEC; goto out_free_file; } if (binary && (data_count != 1 || bss_count != 1)) { status = -ENOEXEC; goto out_free_file; } /* * If there is no additional header then assume the file starts * at the first byte of the text section. This may not be the * proper place, so the best solution is to include the optional * header. A shared library __MUST__ have an optional header to * indicate that it is a shared library. */ if (aout_size == 0) { if (!binary) { status = -ENOEXEC; goto out_free_file; } start_addr = COFF_LONG(text_sect->s_vaddr); } else if (aout_size < (short) COFF_AOUTSZ) { status = -ENOEXEC; goto out_free_file; } else { COFF_AOUTHDR *aout_hdr; short aout_magic; aout_hdr = (COFF_AOUTHDR *) &((char *)coff_hdr)[COFF_FILHSZ]; aout_magic = COFF_SHORT(aout_hdr->magic); /* * Validate the magic number in the a.out header. If it is valid then * update the starting symbol location. Do not accept these file formats * when loading a shared library. */ switch (aout_magic) { case COFF_OMAGIC: case COFF_ZMAGIC: case COFF_STMAGIC: if (!binary) { status = -ENOEXEC; goto out_free_file; } start_addr = (u_int)COFF_LONG(aout_hdr->entry); break; /* * Magic value for a shared library. This is valid only when * loading a shared library. * * (There is no need for a start_addr. It won't be used.) */ case COFF_SHMAGIC: if (!binary) break; /* FALLTHROUGH */ default: status = -ENOEXEC; goto out_free_file; } } /* * Generate the proper values for the text fields * * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD. */ text.scnptr = COFF_LONG(text_sect->s_scnptr); text.size = COFF_LONG(text_sect->s_size); text.vaddr = COFF_LONG(text_sect->s_vaddr); /* * Generate the proper values for the data fields */ if (data_sect != NULL) { data.scnptr = COFF_LONG(data_sect->s_scnptr); data.size = COFF_LONG(data_sect->s_size); data.vaddr = COFF_LONG(data_sect->s_vaddr); } else { data.scnptr = 0; data.size = 0; data.vaddr = 0; } /* * Generate the proper values for the bss fields */ if (bss_sect != NULL) { bss.size = COFF_LONG(bss_sect->s_size); bss.vaddr = COFF_LONG(bss_sect->s_vaddr); } else { bss.size = 0; bss.vaddr = 0; } /* * Flush the executable from memory. At this point the executable is * committed to being defined or a segmentation violation will occur. */ if (binary) { COFF_SCNHDR *sect_ptr2 = sect_bufr; u_long personality = PER_SVR3; int i; if ((status = flush_old_exec(bprm))) goto out_free_file; /* * Look for clues as to the system this binary was compiled * on in the comments section(s). * * Only look at the main binary, not the shared libraries * (or would it be better to prefer shared libraries over * binaries? Or could they be different???) */ for (i = 0; i < sections; i++) { long sect_flags = COFF_LONG(sect_ptr2->s_flags); if (sect_flags == COFF_STYP_INFO && (status = coff_parse_comments(bprm->file, sect_ptr2, &personality)) > 0) goto found; sect_ptr2 = (COFF_SCNHDR *) &((char *)sect_ptr2)[COFF_SCNHSZ]; } /* * If no .comments section was found there is no way to * figure out the personality. Odds on it is SCO though... */ personality = PER_SCOSVR3; found: if (lPers) personality = lPers; if ( (personality & 0xFF) == (current->personality & 0xFF) ) set_personality(0); set_personality(personality); #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_UNIMPL,"Personality %08lX assigned\n",personality); #endif #ifdef CONFIG_64BIT set_thread_flag(TIF_IA32); clear_thread_flag(TIF_ABI_PENDING); #endif current->mm->start_data = 0; current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; #ifdef set_mm_counter #if _KSL > 14 set_mm_counter(current->mm, file_rss, 0); #else set_mm_counter(current->mm, rss, 0); #endif #else current->mm->rss = 0; #endif /* * Construct the parameter and environment * string table entries. */ #if _KSL > 10 if ((status = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT)) < 0) #else if ((status = setup_arg_pages(bprm, EXSTACK_DEFAULT)) < 0) #endif goto sigsegv; p = (u_long)coff_mktables((char *)bprm->p, bprm->argc, bprm->envc); current->mm->end_code = text.size + (current->mm->start_code = text.vaddr); current->mm->end_data = data.size + (current->mm->start_data = data.vaddr); current->mm->brk = bss.size + (current->mm->start_brk = bss.vaddr); current->mm->start_stack = p; #if _KSL > 28 install_exec_creds(bprm); #else compute_creds(bprm); #endif #if _KSL < 15 #ifdef CONFIG_64BIT __asm__ volatile ( "movl %0,%%fs; movl %0,%%es; movl %0,%%ds" : :"r" (0)); __asm__ volatile ( "pushf; cli; swapgs; movl %0,%%gs; mfence; swapgs; popf" : :"r" (0)); write_pda(oldrsp,p); _FLG(regs) = 0x200; #else __asm__ volatile ( "movl %0,%%fs ; movl %0,%%gs" : :"r" (0)); _DS(regs) = _ES(regs) = __USER_DS; #endif _SS(regs) = __USER_DS; _SP(regs) = p; _CS(regs) = __USER_CS; _IP(regs) = start_addr; set_fs(USER_DS); #else start_thread(regs, start_addr, p); #endif #ifdef CONFIG_64BIT __asm__ volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); _SS(regs) = __USER32_DS; _CS(regs) = __USER32_CS; #endif } old_fs = get_fs(); set_fs(get_ds()); if (!pageable) { /* * Read the file from disk... * * XXX: untested. */ loff_t pos = data.scnptr; status = do_brk(text.vaddr, text.size); bprm->file->f_op->read(bprm->file, (char *)data.vaddr, data.scnptr, &pos); status = do_brk(data.vaddr, data.size); bprm->file->f_op->read(bprm->file, (char *)text.vaddr, text.scnptr, &pos); status = 0; } else { /* map the text pages...*/ cap_mmap(1); m_addr = map_coff(bprm->file, &text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, text.scnptr & PAGE_MASK); if(!ce) cap_mmap(2); if (m_addr != (text.vaddr & PAGE_MASK)) { status = -ENOEXEC; set_fs(old_fs); goto out_free_file; } /* map the data pages */ if (data.size != 0) { cap_mmap(1); m_addr = map_coff(bprm->file, &data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, data.scnptr & PAGE_MASK); if(!ce) cap_mmap(2); if (m_addr != (data.vaddr & PAGE_MASK)) { status = -ENOEXEC; set_fs(old_fs); goto out_free_file; } } status = 0; } /* * Construct the bss data for the process. The bss ranges from the * end of the data (which may not be on a page boundary) to the end * of the bss section. Allocate any necessary pages for the data. */ if (bss.size != 0) { cap_mmap(1); down_write(¤t->mm->mmap_sem); do_mmap(NULL, PAGE_ALIGN(bss.vaddr), bss.size + bss.vaddr - PAGE_ALIGN(bss.vaddr), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_32BIT, 0); up_write(¤t->mm->mmap_sem); if(!ce) cap_mmap(2); if ((status = coff_clear_memory(bss.vaddr, bss.size)) < 0) { set_fs(old_fs); goto out_free_file; } } set_fs(old_fs); if (!binary) goto out_free_file; /* * Load any shared library for the executable. */ if (lib_count) status = coff_preload_shlibs(bprm, sect_bufr, sections); set_binfmt(&coff_format); /* * Generate any needed trap for this process. If an error occured then * generate a segmentation violation. If the process is being debugged * then generate the load trap. (Note: If this is a library load then * do not generate the trap here. Pass the error to the caller who * will do it for the process in the outer lay of this procedure call.) */ if (status < 0) { sigsegv: printk(KERN_WARNING "coff: trapping process with SEGV\n"); send_sig(SIGSEGV, current, 0); /* Generate the error trap */ } #ifdef CONFIG_PTRACE /* --- Red Hat specific handling --- */ #else else if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); #endif /* We are committed. It can't fail */ status = 0; out_free_file: SYS(close,coff_exec_fileno); out_free_buf: kfree(sect_bufr); return (status); }
static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) { int som_exec_fileno; int retval; unsigned int size; unsigned long som_entry; struct som_hdr *som_ex; struct som_exec_auxhdr *hpuxhdr; /* Get the exec-header */ som_ex = (struct som_hdr *) bprm->buf; retval = check_som_header(som_ex); if (retval != 0) goto out; /* Now read in the auxiliary header information */ retval = -ENOMEM; size = som_ex->aux_header_size; if (size > SOM_PAGESIZE) goto out; hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL); if (!hpuxhdr) goto out; retval = kernel_read(bprm->file, som_ex->aux_header_location, (char *) hpuxhdr, size); if (retval < 0) goto out_free; #error "Fix security hole before enabling me" retval = get_unused_fd(); if (retval < 0) goto out_free; get_file(bprm->file); fd_install(som_exec_fileno = retval, bprm->file); /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free; /* OK, This is the point of no return */ current->flags &= ~PF_FORKNOEXEC; current->personality = PER_HPUX; /* Set the task size for HP-UX processes such that * the gateway page is outside the address space. * This can be fixed later, but for now, this is much * easier. */ current->thread.task_size = 0xc0000000; /* Set map base to allow enough room for hp-ux heap growth */ current->thread.map_base = 0x80000000; retval = map_som_binary(bprm->file, hpuxhdr); if (retval < 0) goto out_free; som_entry = hpuxhdr->exec_entry; kfree(hpuxhdr); set_binfmt(&som_format); compute_creds(bprm); setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); create_som_tables(bprm); current->mm->start_stack = bprm->p; set_mm_counter(current->mm, rss, 0); #if 0 printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); printk("(end_code) %08lx\n" , (unsigned long) current->mm->end_code); printk("(start_code) %08lx\n" , (unsigned long) current->mm->start_code); printk("(end_data) %08lx\n" , (unsigned long) current->mm->end_data); printk("(start_stack) %08lx\n" , (unsigned long) current->mm->start_stack); printk("(brk) %08lx\n" , (unsigned long) current->mm->brk); #endif map_hpux_gateway_page(current,current->mm); start_thread_som(regs, som_entry, bprm->p); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); return 0; /* error cleanup */ out_free: kfree(hpuxhdr); out: return retval; }