Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/vfs_lookup.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/vfs_lookup.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.35 retrieving revision 1.35.2.6 diff -u -p -r1.35 -r1.35.2.6 --- src/sys/kern/vfs_lookup.c 2000/08/03 20:41:23 1.35 +++ src/sys/kern/vfs_lookup.c 2002/08/13 02:20:09 1.35.2.6 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_lookup.c,v 1.35 2000/08/03 20:41:23 thorpej Exp $ */ +/* $NetBSD: vfs_lookup.c,v 1.35.2.6 2002/08/13 02:20:09 nathanw Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -40,6 +40,9 @@ * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 */ +#include +__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.35.2.6 2002/08/13 02:20:09 nathanw Exp $"); + #include "opt_ktrace.h" #include @@ -50,15 +53,18 @@ #include #include #include -#include #include +#include +#include #include +#include #ifdef KTRACE #include #endif struct pool pnbuf_pool; /* pathname buffer pool */ +struct pool_cache pnbuf_cache; /* pathname buffer cache */ /* * Convert a pathname into a pointer to a locked inode. @@ -92,7 +98,6 @@ namei(ndp) int error, linklen; struct componentname *cnp = &ndp->ni_cnd; - ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; #ifdef DIAGNOSTIC if (!cnp->cn_cred || !cnp->cn_proc) panic ("namei: bad cred/proc"); @@ -233,6 +238,34 @@ namei(ndp) } /* + * Determine the namei hash (for cn_hash) for name. + * If *ep != NULL, hash from name to ep-1. + * If *ep == NULL, hash from name until the first NUL or '/', and + * return the location of this termination character in *ep. + * + * This function returns an equivalent hash to the MI hash32_strn(). + * The latter isn't used because in the *ep == NULL case, determining + * the length of the string to the first NUL or `/' and then calling + * hash32_strn() involves unnecessary double-handling of the data. + */ +uint32_t +namei_hash(const char *name, const char **ep) +{ + uint32_t hash; + + hash = HASH32_STR_INIT; + if (*ep != NULL) { + for (; name < *ep; name++) + hash = hash * 33 + *(uint8_t *)name; + } else { + for (; *name != '\0' && *name != '/'; name++) + hash = hash * 33 + *(uint8_t *)name; + *ep = name; + } + return (hash + (hash >> 5)); +} + +/* * Search a pathname. * This is a very central and rather complicated routine. * @@ -346,9 +379,8 @@ dirloop: * responsibility for freeing the pathname buffer. */ cnp->cn_consume = 0; - cnp->cn_hash = 0; - for (cp = cnp->cn_nameptr; *cp != '\0' && *cp != '/'; cp++) - cnp->cn_hash += (unsigned char)*cp; + cp = NULL; + cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp); cnp->cn_namelen = cp - cnp->cn_nameptr; if (cnp->cn_namelen > NAME_MAX) { error = ENAMETOOLONG; @@ -356,9 +388,9 @@ dirloop: } #ifdef NAMEI_DIAGNOSTIC { char c = *cp; - *cp = '\0'; + *(char *)cp = '\0'; printf("{%s}: ", cnp->cn_nameptr); - *cp = c; } + *(char *)cp = c; } #endif ndp->ni_pathlen -= cnp->cn_namelen; ndp->ni_next = cp; @@ -404,6 +436,8 @@ dirloop: * 1. If at root directory (e.g. after chroot) * or at absolute root directory * then ignore it so can't get out. + * 1a. If we have somehow gotten out of a jail, warn + * and also ignore it so we can't get farther out. * 2. If this vnode is the root of a mounted * filesystem, then replace it with the * vnode which was mounted on so we take the @@ -417,6 +451,31 @@ dirloop: VREF(dp); goto nextname; } + if (ndp->ni_rootdir != rootvnode) { + int retval; + VOP_UNLOCK(dp, 0); + retval = vn_isunder(dp, ndp->ni_rootdir, + cnp->cn_proc); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); + if (!retval) { + /* Oops! We got out of jail! */ + log(LOG_WARNING, + "chrooted pid %d uid %d (%s) " + "detected outside of its chroot\n", + cnp->cn_proc->p_pid, + cnp->cn_proc->p_ucred->cr_uid, + cnp->cn_proc->p_comm); + /* Put us at the jail root. */ + vput(dp); + dp = ndp->ni_rootdir; + ndp->ni_dvp = dp; + ndp->ni_vp = dp; + VREF(dp); + VREF(dp); + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); + goto nextname; + } + } if ((dp->v_flag & VROOT) == 0 || (cnp->cn_flags & NOCROSSMOUNT)) break; @@ -608,7 +667,7 @@ relookup(dvp, vpp, cnp) int error = 0; #ifdef NAMEI_DIAGNOSTIC int newhash; /* DEBUG: check name hash */ - char *cp; /* DEBUG: check name ptr/len */ + const char *cp; /* DEBUG: check name ptr/len */ #endif /* @@ -635,8 +694,8 @@ relookup(dvp, vpp, cnp) * responsibility for freeing the pathname buffer. */ #ifdef NAMEI_DIAGNOSTIC - for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) - newhash += (unsigned char)*cp; + cp = NULL; + newhash = namei_hash(cnp->cn_nameptr, &cp); if (newhash != cnp->cn_hash) panic("relookup: bad hash"); if (cnp->cn_namelen != cp - cnp->cn_nameptr)