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>