Example #1
0
/*
 * 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);
}
Example #2
0
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;
}
Example #3
0
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);
}