/* * 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; }
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); }
/* * 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; }
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); }
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; }
/* * 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; }
/* * 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; }