/* * Load a file (interpreter/library) pointed to by path [stolen from * coff_load_shlib()]. Made slightly generic so it might be used externally. */ int ELFNAME(load_file)(struct proc *p, char *path, struct exec_package *epp, struct elf_args *ap, Elf_Addr *last) { int error, i; struct nameidata nd; Elf_Ehdr eh; Elf_Phdr *ph = NULL; u_long phsize; char *bp = NULL; Elf_Addr addr; struct vnode *vp; u_int8_t os; /* Just a dummy in this routine */ Elf_Phdr *base_ph = NULL; struct interp_ld_sec { Elf_Addr vaddr; u_long memsz; } loadmap[ELF_MAX_VALID_PHDR]; int nload, idx = 0; Elf_Addr pos = *last; int file_align; bp = path; NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p); if ((error = namei(&nd)) != 0) { return (error); } vp = nd.ni_vp; if (vp->v_type != VREG) { error = EACCES; goto bad; } if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0) goto bad; if (vp->v_mount->mnt_flag & MNT_NOEXEC) { error = EACCES; goto bad; } if ((error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) != 0) goto bad1; if ((error = ELFNAME(read_from)(p, nd.ni_vp, 0, (caddr_t)&eh, sizeof(eh))) != 0) goto bad1; if (ELFNAME(check_header)(&eh, ET_DYN) && ELFNAME(olf_check_header)(&eh, ET_DYN, &os)) { error = ENOEXEC; goto bad1; } phsize = eh.e_phnum * sizeof(Elf_Phdr); ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK); if ((error = ELFNAME(read_from)(p, nd.ni_vp, eh.e_phoff, (caddr_t)ph, phsize)) != 0) goto bad1; for (i = 0; i < eh.e_phnum; i++) { if (ph[i].p_type == PT_LOAD) { loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr); loadmap[idx].memsz = round_page (ph[i].p_vaddr + ph[i].p_memsz - loadmap[idx].vaddr); file_align = ph[i].p_align; idx++; } } nload = idx; /* * If no position to load the interpreter was set by a probe * function, pick the same address that a non-fixed mmap(0, ..) * would (i.e. something safely out of the way). */ if (pos == ELFDEFNNAME(NO_ADDR)) { pos = uvm_map_hint(p, VM_PROT_EXECUTE); } pos = ELF_ROUND(pos, file_align); *last = epp->ep_interp_pos = pos; for (i = 0; i < nload;/**/) { vaddr_t addr; struct uvm_object *uobj; off_t uoff; size_t size; #ifdef this_needs_fixing if (i == 0) { uobj = &vp->v_uvm.u_obj; /* need to fix uoff */ } else { #endif uobj = NULL; uoff = 0; #ifdef this_needs_fixing } #endif addr = trunc_page(pos + loadmap[i].vaddr); size = round_page(addr + loadmap[i].memsz) - addr; /* CRAP - map_findspace does not avoid daddr+MAXDSIZ */ if ((addr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (addr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) addr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size, &addr, uobj, uoff, 0, UVM_FLAG_FIXED) == NULL) { if (uvm_map_findspace(&p->p_vmspace->vm_map, addr, size, &addr, uobj, uoff, 0, 0) == NULL) { error = ENOMEM; /* XXX */ goto bad1; } } if (addr != pos + loadmap[i].vaddr) { /* base changed. */ pos = addr - trunc_page(loadmap[i].vaddr); pos = ELF_ROUND(pos,file_align); epp->ep_interp_pos = *last = pos; i = 0; continue; } i++; } /* * Load all the necessary sections */ for (i = 0; i < eh.e_phnum; i++) { Elf_Addr size = 0; int prot = 0; int flags; switch (ph[i].p_type) { case PT_LOAD: if (base_ph == NULL) { flags = VMCMD_BASE; addr = *last; base_ph = &ph[i]; } else { flags = VMCMD_RELATIVE; addr = ph[i].p_vaddr - base_ph->p_vaddr; } ELFNAME(load_psection)(&epp->ep_vmcmds, nd.ni_vp, &ph[i], &addr, &size, &prot, flags); /* If entry is within this section it must be text */ if (eh.e_entry >= ph[i].p_vaddr && eh.e_entry < (ph[i].p_vaddr + size)) { epp->ep_entry = addr + eh.e_entry - ELF_TRUNC(ph[i].p_vaddr,ph[i].p_align); ap->arg_interp = addr; } addr += size; break; case PT_DYNAMIC: case PT_PHDR: case PT_NOTE: break; default: break; } } vn_marktext(nd.ni_vp); bad1: VOP_CLOSE(nd.ni_vp, FREAD, p->p_ucred, p); bad: if (ph != NULL) free((char *)ph, M_TEMP); *last = addr; vput(nd.ni_vp); return (error); }
int darwin_sys_load_shared_file(struct lwp *l, const struct darwin_sys_load_shared_file_args *uap, register_t *retval) { /* { syscallarg(char *) filename; syscallarg(void *) addr; syscallarg(u_long) len; syscallarg(void **) base; syscallarg(int) count: syscallarg(mach_sf_mapping_t *) mappings; syscallarg(int *) flags; } */ struct file *fp; struct vnode *vp = NULL; vaddr_t base; struct proc *p = l->l_proc; int flags; char *filename; mach_sf_mapping_t *mapp = NULL; size_t maplen; struct sys_open_args open_cup; struct sys_close_args close_cup; register_t fdc; int fd; int i; int error; vaddr_t max_addr, addr; size_t len; vaddr_t uaddr; int need_relocation; struct exec_vmcmd evc; filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyin(SCARG(uap, filename), filename, MAXPATHLEN)) != 0) goto bad1; if ((error = copyin(SCARG(uap, base), &base, sizeof(base))) != 0) goto bad1; if ((error = copyin(SCARG(uap, flags), &flags, sizeof(base))) != 0) goto bad1; #ifdef DEBUG_DARWIN DPRINTF(("darwin_sys_load_shared_file: filename = %p ", SCARG(uap, filename))); DPRINTF(("addr = %p len = 0x%08lx base = %p ", SCARG(uap, addr), SCARG(uap, len), SCARG(uap, base))); DPRINTF(("count = %d mappings = %p flags = %p ", SCARG(uap, count), SCARG(uap, mappings), SCARG(uap, flags))); DPRINTF(("*base = 0x%08lx *flags = %d filename=`%s'\n", base, flags, filename)); #endif SCARG(&open_cup, path) = SCARG(uap, filename); SCARG(&open_cup, flags) = O_RDONLY; SCARG(&open_cup, mode) = 0; if ((error = sys_open(l, &open_cup, &fdc)) != 0) goto bad1; fd = (int)fdc; fp = fd_getfile(fd); if (fp == NULL) { error = EBADF; goto bad1point5; } vp = fp->f_data; vref(vp); if (SCARG(uap, count) < 0 || SCARG(uap, count) > PAGE_SIZE / sizeof(*mapp)) { error = EINVAL; goto bad2; } maplen = SCARG(uap, count) * sizeof(*mapp); mapp = malloc(maplen, M_TEMP, M_WAITOK); if ((error = copyin(SCARG(uap, mappings), mapp, maplen)) != 0) goto bad2; #ifdef DEBUG_DARWIN for (i = 0; i < SCARG(uap, count); i++) { DPRINTF(("mapp[%d].mapping_offset = 0x%08lx\n", i, mapp[i].mapping_offset)); DPRINTF(("mapp[%d].size = 0x%08lx\n", i, (long)mapp[i].size)); DPRINTF(("mapp[%d].file_offset = 0x%08lx\n", i, mapp[i].file_offset)); DPRINTF(("mapp[%d].protection = %d\n", i, mapp[i].protection)); DPRINTF(("mapp[%d].cksum = %ld\n", i, mapp[i].cksum)); } #endif /* Check if we can load at the default addresses */ need_relocation = 0; vm_map_lock(&p->p_vmspace->vm_map); for (i = 0; i < SCARG(uap, count); i++) if ((uvm_map_findspace(&p->p_vmspace->vm_map, base + mapp[i].mapping_offset, mapp[i].size, &uaddr, NULL, 0, 0, UVM_FLAG_FIXED)) == NULL) need_relocation = 1; vm_map_unlock(&p->p_vmspace->vm_map); /* If we cannot, we need a relocation */ if (need_relocation) { DPRINTF(("Relocating\n")); /* Compute the length of the region enclosing all sections */ max_addr = 0; for (i = 0; i < SCARG(uap, count); i++) { addr = (vaddr_t)(mapp[i].mapping_offset + base + mapp[i].size); if (addr > max_addr) max_addr = addr; } len = max_addr - base; DPRINTF(("base = 0x%08lx max_addr = 0x%08lx len = 0x%08x\n", base, max_addr, len)); /* Find some place to map this region */ vm_map_lock(&p->p_vmspace->vm_map); if ((uvm_map_findspace(&p->p_vmspace->vm_map, base, len, &uaddr, NULL, 0, PAGE_SIZE, 0)) == NULL) { DPRINTF(("Impossible to find some space\n")); vm_map_unlock(&p->p_vmspace->vm_map); error = ENOMEM; goto bad2; } vm_map_unlock(&p->p_vmspace->vm_map); /* Update the base address */ base = uaddr; DPRINTF(("New base address: base = 0x%08lx\n", base)); } /* Do the actual mapping */ for (i = 0; i < SCARG(uap, count); i++) { bzero(&evc, sizeof(evc)); evc.ev_addr = base + mapp[i].mapping_offset; evc.ev_len = mapp[i].size; evc.ev_prot = mapp[i].protection & VM_PROT_ALL; evc.ev_flags = 0; if (mapp[i].protection & MACH_VM_PROT_ZF) evc.ev_proc = vmcmd_map_zero; else evc.ev_proc = vmcmd_map_readvn; evc.ev_offset = mapp[i].file_offset; evc.ev_vp = vp; DPRINTF(("map section %d: start = 0x%08lx, len = 0x%08lx\n", i, evc.ev_addr, evc.ev_len)); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if ((error = (*evc.ev_proc)(l, &evc)) != 0) { VOP_UNLOCK(vp, 0); DPRINTF(("Failed\n")); goto bad2; } VOP_UNLOCK(vp, 0); DPRINTF(("Success\n")); } bad2: if (mapp) free(mapp, M_TEMP); vrele(vp); fd_putfile(fd); bad1point5: SCARG(&close_cup, fd) = fd; if ((error = sys_close(l, &close_cup, retval)) != 0) goto bad1; if ((error = copyout(&base, SCARG(uap, base), sizeof(base))) != 0) goto bad1; if ((error = copyout(&flags, SCARG(uap, flags), sizeof(base))) != 0) goto bad1; bad1: free(filename, M_TEMP); return error; }
int sys_mquery(struct proc *p, void *v, register_t *retval) { struct sys_mquery_args /* { syscallarg(void *) addr; syscallarg(size_t) len; syscallarg(int) prot; syscallarg(int) flags; syscallarg(int) fd; syscallarg(long) pad; syscallarg(off_t) pos; } */ *uap = v; struct file *fp; struct uvm_object *uobj; voff_t uoff; int error; vaddr_t vaddr; int flags = 0; vsize_t size; vm_prot_t prot; int fd; vaddr = (vaddr_t) SCARG(uap, addr); prot = SCARG(uap, prot); size = (vsize_t) SCARG(uap, len); fd = SCARG(uap, fd); if ((prot & VM_PROT_ALL) != prot) return (EINVAL); if (SCARG(uap, flags) & MAP_FIXED) flags |= UVM_FLAG_FIXED; if (fd >= 0) { if ((error = getvnode(p->p_fd, fd, &fp)) != 0) return (error); uobj = &((struct vnode *)fp->f_data)->v_uvm.u_obj; uoff = SCARG(uap, pos); } else { fp = NULL; uobj = NULL; uoff = 0; } if (vaddr == 0) vaddr = uvm_map_hint(p, prot); /* prevent a user requested address from falling in heap space */ if ((vaddr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (vaddr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) { if (flags & UVM_FLAG_FIXED) { error = EINVAL; goto done; } vaddr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); } vm_map_lock(&p->p_vmspace->vm_map); again: if (uvm_map_findspace(&p->p_vmspace->vm_map, vaddr, size, &vaddr, uobj, uoff, 0, flags) == NULL) { if (flags & UVM_FLAG_FIXED) error = EINVAL; else error = ENOMEM; } else { /* prevent a returned address from falling in heap space */ if ((vaddr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (vaddr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) { vaddr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); goto again; } error = 0; *retval = (register_t)(vaddr); } vm_map_unlock(&p->p_vmspace->vm_map); done: if (fp != NULL) FRELE(fp); return (error); }