Example #1
0
/*
 * kobj_load_file:
 *
 *	Load an object located in the file system.
 */
int
kobj_load_file(kobj_t *kop, const char *filename, const char *base,
	       bool autoload)
{
	struct nameidata nd;
	kauth_cred_t cred;
	char *path;
	int error;
	kobj_t ko;

	cred = kauth_cred_get();

	ko = kmem_zalloc(sizeof(*ko), KM_SLEEP);
	if (ko == NULL) {
		return ENOMEM;
	}

	if (autoload) {
		error = ENOENT;
	} else {
		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename);
		error = vn_open(&nd, FREAD, 0);
	}
	if (error != 0) {
		if (error != ENOENT) {
			goto out;
		}
		path = PNBUF_GET();
		snprintf(path, MAXPATHLEN - 1, "%s/%s/%s.kmod", base,
		    filename, filename);
		NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, UIO_SYSSPACE, path);
		error = vn_open(&nd, FREAD, 0);
		if (error != 0) {
			strlcat(path, ".o", MAXPATHLEN);
			NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, UIO_SYSSPACE,
			    path);
			error = vn_open(&nd, FREAD, 0);
		}
		PNBUF_PUT(path);
		if (error != 0) {
			goto out;
		}
	}

 out:
 	if (error != 0) {
	 	kmem_free(ko, sizeof(*ko));
	 	return error;
	}

	ko->ko_type = KT_VNODE;
	ko->ko_source = nd.ni_vp;
	*kop = ko;
	return kobj_load(ko);
}
/*
 * Look for native NetBSD compatibility libraries, usually interp-ABI.
 * It returns 0 if it changed the interpreter, otherwise it returns
 * the error from namei().  Callers should not try any more processing
 * if this returns 0, and probably should just ignore the return value.
 */
int
compat_elf_check_interp(struct exec_package *epp,
			char *interp,
			const char *interp_suffix)
{
	int error = 0;

	/*
	 * Don't look for something else, if someone has already found and
	 * setup the ep_interp already.
	 */
	if (interp && epp->ep_interp == NULL) {
		/*
		 * If the path is exactly "/usr/libexec/ld.elf_so", first
		 * try to see if "/usr/libexec/ld.elf_so-<abi>" exists
		 * and if so, use that instead.
		 */
		if (strcmp(interp, "/usr/libexec/ld.elf_so") == 0 ||
		    strcmp(interp, "/libexec/ld.elf_so") == 0) {
			struct vnode *vp;
			char *path;

			path = PNBUF_GET();
			snprintf(path, MAXPATHLEN, "%s-%s", interp, interp_suffix);
			error = namei_simple_kernel(path,
					NSM_FOLLOW_NOEMULROOT, &vp);
			/*
			 * If that worked, replace interpreter in case we
			 * actually need to load it.
			 */
			if (error == 0) {
				epp->ep_interp = vp;
				snprintf(interp, MAXPATHLEN, "%s", path);
			}
			PNBUF_PUT(path);
		}
	}
	return error;
}
Example #3
0
int
cd9660_readlink(void *v)
{
	struct vop_readlink_args /* {
		struct vnode *a_vp;
		struct uio *a_uio;
		kauth_cred_t a_cred;
	} */ *ap = v;
	ISONODE	*ip;
	ISODIR	*dirp;
	ISOMNT	*imp;
	struct	buf *bp;
	struct	uio *uio;
	u_short	symlen;
	int	error;
	char	*symname;
	bool use_pnbuf;

	ip  = VTOI(ap->a_vp);
	imp = ip->i_mnt;
	uio = ap->a_uio;

	if (imp->iso_ftype != ISO_FTYPE_RRIP)
		return (EINVAL);

	/*
	 * Get parents directory record block that this inode included.
	 */
	error = bread(imp->im_devvp,
		      (ip->i_number >> imp->im_bshift) <<
		      (imp->im_bshift - DEV_BSHIFT),
		      imp->logical_block_size, NOCRED, 0, &bp);
	if (error) {
		return (EINVAL);
	}

	/*
	 * Setup the directory pointer for this inode
	 */
	dirp = (ISODIR *)((char *)bp->b_data + (ip->i_number & imp->im_bmask));

	/*
	 * Just make sure, we have a right one....
	 *   1: Check not cross boundary on block
	 */
	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
	    > imp->logical_block_size) {
		brelse(bp, 0);
		return (EINVAL);
	}

	/*
	 * Now get a buffer
	 * Abuse a namei buffer for now.
	 */
	use_pnbuf = !VMSPACE_IS_KERNEL_P(uio->uio_vmspace) ||
	    uio->uio_iov->iov_len < MAXPATHLEN;
	if (use_pnbuf) {
		symname = PNBUF_GET();
	} else {
		symname = uio->uio_iov->iov_base;
	}

	/*
	 * Ok, we just gathering a symbolic name in SL record.
	 */
	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
		if (use_pnbuf) {
			PNBUF_PUT(symname);
		}
		brelse(bp, 0);
		return (EINVAL);
	}
	/*
	 * Don't forget before you leave from home ;-)
	 */
	brelse(bp, 0);

	/*
	 * return with the symbolic name to caller's.
	 */
	if (use_pnbuf) {
		error = uiomove(symname, symlen, uio);
		PNBUF_PUT(symname);
		return (error);
	}
	uio->uio_resid -= symlen;
	uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
	uio->uio_iov->iov_len -= symlen;
	return (0);
}
Example #4
0
/*
 * Dump core, into a file named "progname.core" or "core" (depending on the
 * value of shortcorename), unless the process was setuid/setgid.
 */
static int
coredump(struct lwp *l, const char *pattern)
{
	struct vnode		*vp;
	struct proc		*p;
	struct vmspace		*vm;
	kauth_cred_t		cred;
	struct pathbuf		*pb;
	struct nameidata	nd;
	struct vattr		vattr;
	struct coredump_iostate	io;
	struct plimit		*lim;
	int			error, error1;
	char			*name, *lastslash;

	name = PNBUF_GET();

	p = l->l_proc;
	vm = p->p_vmspace;

	mutex_enter(proc_lock);		/* p_session */
	mutex_enter(p->p_lock);

	/*
	 * Refuse to core if the data + stack + user size is larger than
	 * the core dump limit.  XXX THIS IS WRONG, because of mapped
	 * data.
	 */
	if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >=
	    p->p_rlimit[RLIMIT_CORE].rlim_cur) {
		error = EFBIG;		/* better error code? */
		mutex_exit(p->p_lock);
		mutex_exit(proc_lock);
		goto done;
	}

	/*
	 * It may well not be curproc, so grab a reference to its current
	 * credentials.
	 */
	kauth_cred_hold(p->p_cred);
	cred = p->p_cred;

	/*
	 * Make sure the process has not set-id, to prevent data leaks,
	 * unless it was specifically requested to allow set-id coredumps.
	 */
	if (p->p_flag & PK_SUGID) {
		if (!security_setidcore_dump) {
			error = EPERM;
			mutex_exit(p->p_lock);
			mutex_exit(proc_lock);
			goto done;
		}
		pattern = security_setidcore_path;
	}

	/* Lock, as p_limit and pl_corename might change. */
	lim = p->p_limit;
	mutex_enter(&lim->pl_lock);
	if (pattern == NULL) {
		pattern = lim->pl_corename;
	}
	error = coredump_buildname(p, name, pattern, MAXPATHLEN);
	mutex_exit(&lim->pl_lock);

	if (error) {
		mutex_exit(p->p_lock);
		mutex_exit(proc_lock);
		goto done;
	}

	/*
	 * On a simple filename, see if the filesystem allow us to write
	 * core dumps there.
	 */
	lastslash = strrchr(name, '/');
	if (!lastslash) {
		vp = p->p_cwdi->cwdi_cdir;
		if (vp->v_mount == NULL ||
		    (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0)
			error = EPERM;
	}

	mutex_exit(p->p_lock);
	mutex_exit(proc_lock);
	if (error)
		goto done;

	/*
	 * On a complex filename, see if the filesystem allow us to write
	 * core dumps there.
	 *
	 * XXX: We should have an API that avoids double lookups
	 */
	if (lastslash) {
		char c[2];

		if (lastslash - name >= MAXPATHLEN - 2) {
			error = EPERM;
			goto done;
		}

		c[0] = lastslash[1];
		c[1] = lastslash[2];
		lastslash[1] = '.';
		lastslash[2] = '\0';
		error = namei_simple_kernel(name, NSM_FOLLOW_NOEMULROOT, &vp);
		if (error)
			goto done;
		if (vp->v_mount == NULL ||
		    (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0)
			error = EPERM;
		vrele(vp);
		if (error)
			goto done;
		lastslash[1] = c[0];
		lastslash[2] = c[1];
	}

	pb = pathbuf_create(name);
	if (pb == NULL) {
		error = ENOMEM;
		goto done;
	}
	NDINIT(&nd, LOOKUP, NOFOLLOW, pb);
	if ((error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE,
	    S_IRUSR | S_IWUSR)) != 0) {
		pathbuf_destroy(pb);
		goto done;
	}
	vp = nd.ni_vp;
	pathbuf_destroy(pb);

	/*
	 * Don't dump to:
	 * 	- non-regular files
	 * 	- files with links
	 * 	- files we don't own
	 */
	if (vp->v_type != VREG ||
	    VOP_GETATTR(vp, &vattr, cred) || vattr.va_nlink != 1 ||
	    vattr.va_uid != kauth_cred_geteuid(cred)) {
		error = EACCES;
		goto out;
	}
	vattr_null(&vattr);
	vattr.va_size = 0;

	if ((p->p_flag & PK_SUGID) && security_setidcore_dump) {
		vattr.va_uid = security_setidcore_owner;
		vattr.va_gid = security_setidcore_group;
		vattr.va_mode = security_setidcore_mode;
	}

	VOP_SETATTR(vp, &vattr, cred);
	p->p_acflag |= ACORE;

	io.io_lwp = l;
	io.io_vp = vp;
	io.io_cred = cred;
	io.io_offset = 0;

	/* Now dump the actual core file. */
	error = (*p->p_execsw->es_coredump)(l, &io);
 out:
	VOP_UNLOCK(vp);
	error1 = vn_close(vp, FWRITE, cred);
	if (error == 0)
		error = error1;
done:
	if (name != NULL)
		PNBUF_PUT(name);
	return error;
}
Example #5
0
void
rump_vfs_builddevs(struct devsw_conv *dcvec, size_t dcvecsize)
{
	char *pnbuf = PNBUF_GET();
	devminor_t themin;
	struct devsw_conv *dc;
	size_t i;
	int v1, v2;

	rump_vfs_makeonedevnode = makeonedevnode;
	rump_vfs_makedevnodes = makedevnodes;
	rump_vfs_makesymlink = makesymlink;

	for (i = 0; i < dcvecsize; i++) {
		dc = &dcvec[i];

		switch (dc->d_class) {
		case DEVNODE_DONTBOTHER:
			break;
		case DEVNODE_SINGLE:
			if (dc->d_flags & DEVNODE_FLAG_ISMINOR0) {
				themin = dc->d_vectdim[0];
			} else {
				themin = 0;
			}
			makeonenode(pnbuf, MAXPATHLEN,
			    dc->d_bmajor, dc->d_cmajor, themin,
			    dc->d_name, -1, -1);
			break;
		case DEVNODE_VECTOR:
			for (v1 = 0; v1 < dc->d_vectdim[0]; v1++) {
				if (dc->d_vectdim[1] == 0) {
					makeonenode(pnbuf, MAXPATHLEN,
					    dc->d_bmajor, dc->d_cmajor,
					    v1, dc->d_name, v1, -1);
				} else {
					for (v2 = 0;
					    v2 < dc->d_vectdim[1]; v2++) {
						makeonenode(pnbuf, MAXPATHLEN,
						    dc->d_bmajor, dc->d_cmajor,
						    v1 * dc->d_vectdim[1] + v2,
						    dc->d_name, v1, v2);
					}
				}
			}

			/* add some extra sanity checks here */
			if (dc->d_flags & DEVNODE_FLAG_LINKZERO) {
				/*
				 * ok, so we cheat a bit since
				 * symlink isn't supported on rumpfs ...
				 */
				makeonenode(pnbuf, MAXPATHLEN,
				    -1, dc->d_cmajor, 0, dc->d_name, -1, -1);
				    
			}
			break;
		}
	}

	PNBUF_PUT(pnbuf);
}
Example #6
0
int
module_load_vfs(const char *name, int flags, bool autoload,
	module_t *mod, prop_dictionary_t *filedictp)
{
	char *path;
	bool nochroot;
	int error;
	prop_bool_t noload;
	prop_dictionary_t moduledict;

	nochroot = false;
	error = 0;
	path = NULL;
	moduledict = NULL;
	if (filedictp)
		*filedictp = NULL;
	path = PNBUF_GET();

	if (!autoload) {
		if (strchr(name,  '/') != NULL) {
			nochroot = false;
			snprintf(path, MAXPATHLEN, "%s", name);
			error = kobj_load_vfs(&mod->mod_kobj, path, nochroot);
		} else
			error = ENOENT;
	}
	if (autoload || (error == ENOENT)) {
		if (strchr(name, '/') == NULL) {
			nochroot = true;
			snprintf(path, MAXPATHLEN, "%s/%s/%s.kmod",
			    module_base, name, name);
			error = kobj_load_vfs(&mod->mod_kobj, path, nochroot);
		} else
			error = ENOENT;
	}
	if (error != 0) {
		PNBUF_PUT(path);
		module_print("Cannot %sload kernel object `%s'"
		    " error=%d", autoload ? "auto" : "", name, error);
		return error;
	}

	/*
	 * Load and process <module>.plist if it exists.
	 */
	if (((flags & MODCTL_NO_PROP) == 0 && filedictp) || autoload) {
		error = module_load_plist_vfs(path, nochroot, &moduledict);
		if (error != 0) {
			module_print("plist load returned error %d for `%s'",
			    error, path);
			if (error != ENOENT)
				goto fail;
		} else if (autoload) {
			noload = prop_dictionary_get(moduledict, "noautoload");
			if (noload != NULL && prop_bool_true(noload)) {
				module_error("autoloading is disallowed for %s",
				    path);
				prop_object_release(moduledict);
				error = EPERM;
				goto fail;
			}
		}
		if (error == 0) {	/* can get here if error == ENOENT */
			if ((flags & MODCTL_NO_PROP) == 0 && filedictp)
				*filedictp = moduledict;
			else 
				prop_object_release(moduledict);
		}
	}

	PNBUF_PUT(path);
	return 0;

 fail:
	kobj_unload(mod->mod_kobj);
	PNBUF_PUT(path);
	return error;
}
Example #7
0
/*
 * module_load_plist_vfs:
 *
 *	Load a plist located in the file system into memory.
 */
static int
module_load_plist_vfs(const char *modpath, const bool nochroot,
    prop_dictionary_t *filedictp)
{
	struct pathbuf *pb;
	struct nameidata nd;
	struct stat sb;
	void *base;
	char *proppath;
	const size_t plistsize = 8192;
	size_t resid;
	int error, pathlen;

	KASSERT(filedictp != NULL);
	base = NULL;

	proppath = PNBUF_GET();
	strcpy(proppath, modpath);
	pathlen = strlen(proppath);
	if ((pathlen >= 6) && (strcmp(&proppath[pathlen - 5], ".kmod") == 0)) {
		strcpy(&proppath[pathlen - 5], ".plist");
	} else if (pathlen < MAXPATHLEN - 6) {
			strcat(proppath, ".plist");
	} else {
		error = ENOENT;
		goto out1;
	}

	/* XXX this makes an unnecessary extra copy of the path */
	pb = pathbuf_create(proppath);
	if (pb == NULL) {
		error = ENOMEM;
		goto out1;
	}
	
	NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), pb);

	error = vn_open(&nd, FREAD, 0);
 	if (error != 0) {
	 	goto out2;
	}

	error = vn_stat(nd.ni_vp, &sb);
	if (error != 0) {
		goto out3;
	}
	if (sb.st_size >= (plistsize - 1)) {	/* leave space for term \0 */
		error = EFBIG;
		goto out3;
	}

	base = kmem_alloc(plistsize, KM_SLEEP);
	if (base == NULL) {
		error = ENOMEM;
		goto out3;
	}

	error = vn_rdwr(UIO_READ, nd.ni_vp, base, sb.st_size, 0,
	    UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, curlwp);
	*((uint8_t *)base + sb.st_size) = '\0';
	if (error == 0 && resid != 0) {
		error = EFBIG;
	}
	if (error != 0) {
		kmem_free(base, plistsize);
		base = NULL;
		goto out3;
	}

	*filedictp = prop_dictionary_internalize(base);
	if (*filedictp == NULL) {
		error = EINVAL;
	}
	kmem_free(base, plistsize);
	base = NULL;
	KASSERT(error == 0);

out3:
	VOP_UNLOCK(nd.ni_vp);
	vn_close(nd.ni_vp, FREAD, kauth_cred_get());

out2:
	pathbuf_destroy(pb);

out1:
	PNBUF_PUT(proppath);
	return error;
}
Example #8
0
/*
 * Dump core, into a file named "progname.core" or "core" (depending on the
 * value of shortcorename), unless the process was setuid/setgid.
 */
int
coredump(struct lwp *l, const char *pattern)
{
	struct vnode		*vp;
	struct proc		*p;
	struct vmspace		*vm;
	kauth_cred_t		cred;
	struct nameidata	nd;
	struct vattr		vattr;
	struct coredump_iostate	io;
	struct plimit		*lim;
	int			error, error1;
	char			*name;

	name = PNBUF_GET();

	p = l->l_proc;
	vm = p->p_vmspace;

	mutex_enter(proc_lock);		/* p_session */
	mutex_enter(p->p_lock);

	/*
	 * Refuse to core if the data + stack + user size is larger than
	 * the core dump limit.  XXX THIS IS WRONG, because of mapped
	 * data.
	 */
	if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >=
	    p->p_rlimit[RLIMIT_CORE].rlim_cur) {
		error = EFBIG;		/* better error code? */
		mutex_exit(p->p_lock);
		mutex_exit(proc_lock);
		goto done;
	}

	/*
	 * It may well not be curproc, so grab a reference to its current
	 * credentials.
	 */
	kauth_cred_hold(p->p_cred);
	cred = p->p_cred;

	/*
	 * The core dump will go in the current working directory.  Make
	 * sure that the directory is still there and that the mount flags
	 * allow us to write core dumps there.
	 *
	 * XXX: this is partially bogus, it should be checking the directory
	 * into which the file is actually written - which probably needs
	 * a flag on namei()
	 */
	vp = p->p_cwdi->cwdi_cdir;
	if (vp->v_mount == NULL ||
	    (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0) {
		error = EPERM;
		mutex_exit(p->p_lock);
		mutex_exit(proc_lock);
		goto done;
	}

	/*
	 * Make sure the process has not set-id, to prevent data leaks,
	 * unless it was specifically requested to allow set-id coredumps.
	 */
	if (p->p_flag & PK_SUGID) {
		if (!security_setidcore_dump) {
			error = EPERM;
			mutex_exit(p->p_lock);
			mutex_exit(proc_lock);
			goto done;
		}
		pattern = security_setidcore_path;
	}

	/* It is (just) possible for p_limit and pl_corename to change */
	lim = p->p_limit;
	mutex_enter(&lim->pl_lock);
	if (pattern == NULL)
		pattern = lim->pl_corename;
	error = coredump_buildname(p, name, pattern, MAXPATHLEN);
	mutex_exit(&lim->pl_lock);
	mutex_exit(p->p_lock);
	mutex_exit(proc_lock);
	if (error)
		goto done;
	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name);
	if ((error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE,
	    S_IRUSR | S_IWUSR)) != 0)
		goto done;
	vp = nd.ni_vp;

	/* Don't dump to non-regular files or files with links. */
	if (vp->v_type != VREG ||
	    VOP_GETATTR(vp, &vattr, cred) || vattr.va_nlink != 1) {
		error = EINVAL;
		goto out;
	}
	VATTR_NULL(&vattr);
	vattr.va_size = 0;

	if ((p->p_flag & PK_SUGID) && security_setidcore_dump) {
		vattr.va_uid = security_setidcore_owner;
		vattr.va_gid = security_setidcore_group;
		vattr.va_mode = security_setidcore_mode;
	}

	VOP_SETATTR(vp, &vattr, cred);
	p->p_acflag |= ACORE;

	io.io_lwp = l;
	io.io_vp = vp;
	io.io_cred = cred;
	io.io_offset = 0;

	/* Now dump the actual core file. */
	error = (*p->p_execsw->es_coredump)(l, &io);
 out:
	VOP_UNLOCK(vp, 0);
	error1 = vn_close(vp, FWRITE, cred);
	if (error == 0)
		error = error1;
done:
	if (name != NULL)
		PNBUF_PUT(name);
	return error;
}