Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Mar 2002 07:51:06 -0800 (PST)
From:      Brian Feldman <green@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 8059 for review
Message-ID:  <200203201551.g2KFp6C87310@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://people.freebsd.org/~peter/p4db/chv.cgi?CH=8059

Change 8059 by green@green_laptop_2 on 2002/03/20 07:50:35

	Make vn_fullpath() more reliable by adding a "directory" argument,
	and store the executable's directory vnode in proc.p_textdvp.
	The code for this is partially from LOMAC code, and is a bit
	scary, but does seem to be at least on the surface doing what I
	expect it to :)

Affected files ...

... //depot/projects/trustedbsd/mac/sys/compat/linprocfs/linprocfs.c#5 edit
... //depot/projects/trustedbsd/mac/sys/fs/procfs/procfs.c#5 edit
... //depot/projects/trustedbsd/mac/sys/kern/kern_exec.c#14 edit
... //depot/projects/trustedbsd/mac/sys/kern/kern_exit.c#8 edit
... //depot/projects/trustedbsd/mac/sys/kern/kern_fork.c#6 edit
... //depot/projects/trustedbsd/mac/sys/kern/kern_proc.c#5 edit
... //depot/projects/trustedbsd/mac/sys/kern/vfs_aio.c#9 edit
... //depot/projects/trustedbsd/mac/sys/kern/vfs_cache.c#6 edit
... //depot/projects/trustedbsd/mac/sys/net/if.c#13 edit
... //depot/projects/trustedbsd/mac/sys/security/babyaudit/babyaudit.c#3 edit
... //depot/projects/trustedbsd/mac/sys/sys/proc.h#9 edit
... //depot/projects/trustedbsd/mac/sys/sys/vnode.h#16 edit

Differences ...

==== //depot/projects/trustedbsd/mac/sys/compat/linprocfs/linprocfs.c#5 (text+ko) ====

@@ -345,12 +345,18 @@
 	int error;
 
 	/* resolve symlinks etc. in the emulation tree prefix */
-	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
+	NDINIT(&nd, LOOKUP, FOLLOW | SAVESTART, UIO_SYSSPACE, linux_emul_path,
+	    td);
 	flep = NULL;
-	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
+	if (namei(&nd) == 0) {
+		if (vn_fullpath(td, nd.ni_dvp, nd.ni_vp, &dlep, &flep) == 0)
+			lep = dlep;
+		else
+			lep = linux_emul_path;
+		NDFREE(&nd, 0);
+	} else {
 		lep = linux_emul_path;
-	else
-		lep = dlep;
+	}
 	lep_len = strlen(lep);
 	
 	mtx_lock(&mountlist_mtx);

==== //depot/projects/trustedbsd/mac/sys/fs/procfs/procfs.c#5 (text+ko) ====

@@ -70,7 +70,7 @@
 	char *fullpath = "unknown";
 	char *freepath = NULL;
 
-	vn_fullpath(td, p->p_textvp, &fullpath, &freepath);
+	vn_fullpath(td, p->p_textdvp, p->p_textvp, &fullpath, &freepath);
 	sbuf_printf(sb, "%s", fullpath);
 	if (freepath)
 		free(freepath, M_TEMP);

==== //depot/projects/trustedbsd/mac/sys/kern/kern_exec.c#14 (text+ko) ====

@@ -189,7 +189,7 @@
 	 *	in ni_vp amoung other things.
 	 */
 	ndp = &nd;
-	NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
+	NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME | SAVESTART,
 	    UIO_USERSPACE, uap->fname, td);
 
 interpret:
@@ -258,8 +258,9 @@
 		/* free name buffer and old vnode */
 		NDFREE(ndp, NDF_ONLY_PNBUF);
 		vrele(ndp->ni_vp);
+		vrele(ndp->ni_dvp);
 		/* set new name to that of the interpreter */
-		NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
+		NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME | SAVESTART,
 		    UIO_SYSSPACE, imgp->interpreter_name, td);
 		goto interpret;
 	}
@@ -442,8 +443,12 @@
 	 */
 	if (p->p_textvp)		/* release old reference */
 		vrele(p->p_textvp);
+	if (p->p_textdvp)		/* release old reference */
+		vrele(p->p_textdvp);
 	VREF(ndp->ni_vp);
+	VREF(ndp->ni_dvp);
 	p->p_textvp = ndp->ni_vp;
+	p->p_textdvp = ndp->ni_dvp;
 
 	/*
 	 * Notify others that we exec'd, and clear the P_INEXEC flag
@@ -504,6 +509,7 @@
 	if (imgp->vp) {
 		NDFREE(ndp, NDF_ONLY_PNBUF);
 		vrele(imgp->vp);
+		vrele(ndp->ni_dvp);
 	}
 
 	if (error == 0)

==== //depot/projects/trustedbsd/mac/sys/kern/kern_exit.c#8 (text+ko) ====

@@ -306,6 +306,10 @@
 		p->p_textvp = NULL;
 		vrele(vtmp);
 	}
+	if ((vtmp = p->p_textdvp) != NULL) {
+		p->p_textdvp = NULL;
+		vrele(vtmp);
+	}
 
 	/*
 	 * Remove proc from allproc queue and pidhash chain.

==== //depot/projects/trustedbsd/mac/sys/kern/kern_fork.c#6 (text+ko) ====

@@ -528,10 +528,13 @@
 
 	/* bump references to the text vnode (for procfs) */
 	p2->p_textvp = p1->p_textvp;
+	p2->p_textdvp = p1->p_textdvp;
 	PROC_UNLOCK(p1);
 	PROC_UNLOCK(p2);
 	if (p2->p_textvp)
 		VREF(p2->p_textvp);
+	if (p2->p_textdvp)
+		VREF(p2->p_textdvp);
 
 	if (flags & RFCFDG)
 		fd = fdinit(td);

==== //depot/projects/trustedbsd/mac/sys/kern/kern_proc.c#5 (text+ko) ====


==== //depot/projects/trustedbsd/mac/sys/kern/vfs_aio.c#9 (text+ko) ====

@@ -784,6 +784,10 @@
 		vrele(mycp->p_textvp);
 		mycp->p_textvp = NULL;
 	}
+	if (mycp->p_textdvp) {
+		vrele(mycp->p_textdvp);
+		mycp->p_textdvp = NULL;
+	}
 
 	/*
 	 * Allocate and ready the aio control info.  There is one aiop structure

==== //depot/projects/trustedbsd/mac/sys/kern/vfs_cache.c#6 (text+ko) ====

@@ -49,6 +49,7 @@
 #include <sys/malloc.h>
 #include <sys/sysproto.h>
 #include <sys/proc.h>
+#include <sys/dirent.h>
 #include <sys/filedesc.h>
 #include <sys/fnv_hash.h>
 
@@ -797,106 +798,202 @@
  * Thus begins the fullpath magic.
  */
 
-#undef STATNODE
-#define STATNODE(name)							\
-	static u_int name;						\
-	SYSCTL_UINT(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, "")
-
 static int disablefullpath;
 SYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0,
 	"Disable the vn_fullpath function");
 
-STATNODE(numfullpathcalls);
-STATNODE(numfullpathfail1);
-STATNODE(numfullpathfail2);
-STATNODE(numfullpathfail3);
-STATNODE(numfullpathfail4);
-STATNODE(numfullpathfound);
+static int
+vn_fullpath_dirents_searchbyid(struct thread *td, struct vnode *dvp,
+    struct dirent *dp, struct dirent *enddp, const struct vattr *vap,
+    struct dirent **retdp)
+{
+	struct vattr pvattr;
+	struct componentname cnp;
+	struct vnode *vp;
+	struct ucred *ucred = td->td_ucred;
+	int error;
+
+	*retdp = NULL;
+	for (; dp != enddp; dp = (struct dirent *)((char *)dp + dp->d_reclen)) {
+		if (dp->d_name[0] == '.' && (dp->d_namlen == 1 ||
+		    (dp->d_namlen == 2 && dp->d_name[1] == '.')))
+			continue;
+		cnp.cn_nameiop = LOOKUP;
+		cnp.cn_flags = LOCKPARENT | ISLASTCN | NOFOLLOW;
+		cnp.cn_thread = td;
+		cnp.cn_cred = ucred;
+		cnp.cn_nameptr = dp->d_name;
+		cnp.cn_namelen = dp->d_namlen;
+		error = VOP_LOOKUP(dvp, &vp, &cnp);
+		if (error)
+			return (error);
+		error = VOP_GETATTR(vp, &pvattr, ucred, td);
+		if (vp != dvp)
+			(void)vput(vp);
+		else
+			vrele(vp);	/* if looking up "." */
+		if (error)
+			return (error);
+		if (pvattr.va_fsid == vap->va_fsid &&
+		    pvattr.va_fileid == vap->va_fileid) {
+			*retdp = dp;
+			break;
+		}
+	}
+	return (0);
+}
 
-/*
- * Retrieve the full filesystem path that correspond to a vnode from the name
- * cache (if available)
- */
 int
-vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
-{
-	char *bp, *buf;
-	int i, slash_prefixed;
-	struct filedesc *fdp;
-	struct namecache *ncp;
-	struct vnode *vp;
+vn_fullpath(struct thread *td, struct vnode *startdvp, struct vnode *startvp,
+    char **buf, char **freebuf) {
+	struct vattr cvattr;
+	struct vnode *vp, *dvp, *fd_rdir;
+	char *bp, *allocedmem, *direntmem;
+	const int direntmem_size = (32 << 10) - MAXPATHLEN;
+	int error, i, slash_prefixed;
 
-	numfullpathcalls++;
 	if (disablefullpath)
-		return (ENODEV);
-	if (vn == NULL)
-		return (EINVAL);
-	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-	bp = buf + MAXPATHLEN - 1;
+		return (EPERM);
+	FILEDESC_LOCK(td->td_proc->p_fd);
+	fd_rdir = td->td_proc->p_fd->fd_rdir;
+	vref(fd_rdir);
+	FILEDESC_UNLOCK(td->td_proc->p_fd);
+	allocedmem = malloc(MAXPATHLEN + direntmem_size, M_TEMP, M_WAITOK);
+	bp = allocedmem;
+	bp += MAXPATHLEN - 1;
 	*bp = '\0';
-	fdp = td->td_proc->p_fd;
+	direntmem = allocedmem + MAXPATHLEN;
 	slash_prefixed = 0;
-	FILEDESC_LOCK(fdp);
-	for (vp = vn; vp != fdp->fd_rdir && vp != rootvnode;) {
+	vref(startvp);
+	for (vp = startvp;; vrele(vp), vp = dvp) {
+		struct iovec diov = {
+			direntmem,
+			direntmem_size
+		};
+		struct uio duio = {
+			&diov,
+			1,
+			0,
+			direntmem_size,
+			UIO_SYSSPACE,
+			UIO_READ,
+			td
+		};
+		struct dirent *dp;
+		int direof;
+
+		if (vp == rootvnode || vp == fd_rdir)
+			break;
 		if (vp->v_flag & VROOT) {
 			if (vp->v_mount == NULL) {	/* forced unmount */
-				FILEDESC_UNLOCK(fdp);
-				free(buf, M_TEMP);
-				return (EBADF);
+				error = EBADF;
+				goto out;
 			}
-			vp = vp->v_mount->mnt_vnodecovered;
+			dvp = vp->v_mount->mnt_vnodecovered;
+			vref(dvp);
 			continue;
 		}
-		if (vp != vn && vp->v_dd->v_id != vp->v_ddid) {
-			FILEDESC_UNLOCK(fdp);
-			numfullpathfail1++;
-			free(buf, M_TEMP);
-			return (ENOTDIR);
+		if (startdvp != NULL) {
+			dvp = startdvp;
+			vref(dvp);
+			startdvp = NULL;
+		} else {
+			if (vp->v_ddid == vp->v_dd->v_id) {
+				dvp = vp->v_dd;
+				vref(dvp);
+			} else {
+				struct componentname cnp;
+
+				if (vp->v_type != VDIR) {
+					error = EBADF;
+					goto out;
+				}
+				cnp.cn_nameiop = LOOKUP;
+				cnp.cn_flags = 0;
+				cnp.cn_thread = td;
+				cnp.cn_cred = td->td_ucred;
+				cnp.cn_nameptr = "..";
+				cnp.cn_namelen = 2;
+				vn_lock(vp, LK_EXCLUSIVE, td);
+				error = VOP_LOOKUP(vp, &dvp, &cnp);
+				if (error) { 
+					VOP_UNLOCK(vp, 0, td);
+					goto out;
+				}
+				VOP_UNLOCK(dvp, 0, td);
+			}
 		}
-		ncp = TAILQ_FIRST(&vp->v_cache_dst);
-		if (!ncp) {
-			FILEDESC_UNLOCK(fdp);
-			numfullpathfail2++;
-			free(buf, M_TEMP);
-			return (ENOENT);
+		if (vp == dvp)
+			break;
+		/*
+		 * Utilize POSIX requirement of files having same
+		 * st_dev and st_ino to be the same  file, in our
+		 * case with vattr.va_fsid and vattr.va_fileid.
+		 */
+		vn_lock(vp, LK_EXCLUSIVE, td);
+		error = VOP_GETATTR(vp, &cvattr, curthread->td_ucred,
+		    curthread);
+		VOP_UNLOCK(vp, 0, td);
+		if (error) {
+			vrele(dvp);
+			goto out;
 		}
-		if (vp != vn && ncp->nc_dvp != vp->v_dd) {
-			FILEDESC_UNLOCK(fdp);
-			numfullpathfail3++;
-			free(buf, M_TEMP);
-			return (EBADF);
-		}
-		for (i = ncp->nc_nlen - 1; i >= 0; i--) {
-			if (bp == buf) {
-				FILEDESC_UNLOCK(fdp);
-				numfullpathfail4++;
-				free(buf, M_TEMP);
-				return (ENOMEM);
+		vn_lock(dvp, LK_EXCLUSIVE, td);
+		for (direof = 0; !direof;) {
+			error = VOP_READDIR(dvp, &duio, td->td_ucred, &direof,
+			    NULL, NULL);
+			if (error)
+				break;
+			error = vn_fullpath_dirents_searchbyid(td, dvp,
+			    (struct dirent *)direntmem,
+			    (struct dirent *)(direntmem +
+			    direntmem_size - duio.uio_resid),
+			    &cvattr, &dp);
+			if (error)
+				break;
+			if (dp != NULL) {
+				for (i = dp->d_namlen - 1; i >= 0; i--) {
+					if (bp == allocedmem) {
+						error = ENOMEM;
+						vput(dvp);
+						goto out;
+					}
+					*--bp = dp->d_name[i];
+				}
+				goto nextcomp;
 			}
-			*--bp = ncp->nc_name[i];
+			diov.iov_base = direntmem;
+			diov.iov_len = direntmem_size;
+			duio.uio_resid = direntmem_size;
 		}
-		if (bp == buf) {
-			FILEDESC_UNLOCK(fdp);
-			numfullpathfail4++;
-			free(buf, M_TEMP);
-			return (ENOMEM);
+		vput(dvp);
+		if (direof)
+			error = ENOENT;
+		goto out;
+nextcomp:
+		if (bp == allocedmem) {
+			error = ENOMEM;
+			vput(dvp);
+			goto out;
 		}
 		*--bp = '/';
 		slash_prefixed = 1;
-		vp = ncp->nc_dvp;
+		VOP_UNLOCK(dvp, 0, td);
 	}
 	if (!slash_prefixed) {
-		if (bp == buf) {
-			FILEDESC_UNLOCK(fdp);
-			numfullpathfail4++;
-			free(buf, M_TEMP);
-			return (ENOMEM);
+		if (bp == allocedmem) {
+			error = ENOMEM;
+			goto out;
 		}
 		*--bp = '/';
 	}
-	FILEDESC_UNLOCK(fdp);
-	numfullpathfound++;
-	*retbuf = bp; 
-	*freebuf = buf;
-	return (0);
+	error = 0;
+	*buf = bp;
+	*freebuf = allocedmem;
+out:
+	vrele(vp);
+	vrele(fd_rdir);
+	if (error)
+		free(allocedmem, M_TEMP);
+	return (error);
 }

==== //depot/projects/trustedbsd/mac/sys/net/if.c#13 (text+ko) ====


==== //depot/projects/trustedbsd/mac/sys/security/babyaudit/babyaudit.c#3 (text+ko) ====

@@ -79,10 +79,10 @@
 	char *freepath1 = NULL, *freepath2 = NULL;
 
 	if (vp1 != NULL) {
-		vn_fullpath(curthread, vp1, &fullpath1, &freepath1);
+		vn_fullpath(curthread, NULL, vp1, &fullpath1, &freepath1);
 	}
 	if (vp2 != NULL) {
-		vn_fullpath(curthread, vp2, &fullpath2, &freepath2);
+		vn_fullpath(curthread, NULL, vp2, &fullpath2, &freepath2);
 	}
 
 	if (vp1 == NULL && vp2 == NULL) {

==== //depot/projects/trustedbsd/mac/sys/sys/proc.h#9 (text+ko) ====

@@ -418,6 +418,7 @@
 	struct vnode	*p_tracep;	/* (j?) Trace to vnode. */
 	sigset_t	p_siglist;	/* (c) Sigs arrived, not delivered. */
 	struct vnode	*p_textvp;	/* (b) Vnode of executable. */
+	struct vnode	*p_textdvp;	/* (b) Dir vnode of executable. */
 	struct mtx	p_mtx;		/* (k) Lock for this struct. */
 	char		p_lock;		/* (c) Proclock (prevent swap) count. */
 	struct klist p_klist;		/* (c) Knotes attached to this proc. */

==== //depot/projects/trustedbsd/mac/sys/sys/vnode.h#16 (text+ko) ====

@@ -586,10 +586,11 @@
 int	lease_check __P((struct vop_lease_args *ap));
 int	spec_vnoperate __P((struct vop_generic_args *));
 int	speedup_syncer __P((void));
-#define textvp_fullpath(p, rb, rfb) \
-	vn_fullpath(FIRST_THREAD_IN_PROC(p), (p)->p_textvp, rb, rfb)
-int	vn_fullpath __P((struct thread *td, struct vnode *vn,
-	    char **retbuf, char **freebuf));
+#define textvp_fullpath(p, rb, rfb)					\
+	vn_fullpath(FIRST_THREAD_IN_PROC(p), (p)->p_textdvp,		\
+	(p)->p_textvp, rb, rfb)
+int	vn_fullpath __P((struct thread *td, struct vnode *optional_dvp,
+	    struct vnode *vp, char **retbuf, char **freebuf));
 int	vnaccess __P((struct vnode *vp, mode_t file_mode, uid_t uid, gid_t gid,
 	    mode_t acc_mode, struct ucred *cred, int *privused));
 int	vaccess_acl_posix1e __P((enum vtype type, uid_t file_uid,

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe p4-projects" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203201551.g2KFp6C87310>