LCOV - code coverage report
Current view: top level - kern - vfs_lookup.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 348 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: vfs_lookup.c,v 1.74 2018/08/13 23:11:44 deraadt Exp $ */
       2             : /*      $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1989, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  * (c) UNIX System Laboratories, Inc.
       8             :  * All or some portions of this file are derived from material licensed
       9             :  * to the University of California by American Telephone and Telegraph
      10             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      11             :  * the permission of UNIX System Laboratories, Inc.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  * 3. Neither the name of the University nor the names of its contributors
      22             :  *    may be used to endorse or promote products derived from this software
      23             :  *    without specific prior written permission.
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      26             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      27             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      28             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      29             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      30             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      31             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      33             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      34             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      35             :  * SUCH DAMAGE.
      36             :  *
      37             :  *      @(#)vfs_lookup.c        8.6 (Berkeley) 11/21/94
      38             :  */
      39             : 
      40             : #include <sys/param.h>
      41             : #include <sys/systm.h>
      42             : #include <sys/syslimits.h>
      43             : #include <sys/time.h>
      44             : #include <sys/namei.h>
      45             : #include <sys/vnode.h>
      46             : #include <sys/lock.h>
      47             : #include <sys/mount.h>
      48             : #include <sys/errno.h>
      49             : #include <sys/pool.h>
      50             : #include <sys/filedesc.h>
      51             : #include <sys/proc.h>
      52             : #include <sys/pledge.h>
      53             : #include <sys/file.h>
      54             : #include <sys/fcntl.h>
      55             : 
      56             : #ifdef KTRACE
      57             : #include <sys/ktrace.h>
      58             : #endif
      59             : 
      60             : void unveil_check_component(struct proc *p, struct nameidata *ni, struct vnode *dp );
      61             : int unveil_check_final(struct proc *p, struct nameidata *ni);
      62             : 
      63             : void
      64           0 : ndinitat(struct nameidata *ndp, u_long op, u_long flags,
      65             :     enum uio_seg segflg, int dirfd, const char *namep, struct proc *p)
      66             : {
      67           0 :         memset(ndp, 0, sizeof(*ndp));
      68           0 :         ndp->ni_cnd.cn_nameiop = op;
      69           0 :         ndp->ni_cnd.cn_flags = flags;
      70           0 :         ndp->ni_segflg = segflg;
      71           0 :         ndp->ni_dirfd = dirfd;
      72           0 :         ndp->ni_dirp = namep;
      73           0 :         ndp->ni_cnd.cn_proc = p;
      74           0 : }
      75             : 
      76             : /*
      77             :  * Convert a pathname into a pointer to a vnode.
      78             :  *
      79             :  * The FOLLOW flag is set when symbolic links are to be followed
      80             :  * when they occur at the end of the name translation process.
      81             :  * Symbolic links are always followed for all other pathname
      82             :  * components other than the last.
      83             :  *
      84             :  * If the LOCKLEAF flag is set, a locked vnode is returned.
      85             :  *
      86             :  * The segflg defines whether the name is to be copied from user
      87             :  * space or kernel space.
      88             :  *
      89             :  * Overall outline of namei:
      90             :  *
      91             :  *      copy in name
      92             :  *      get starting directory
      93             :  *      while (!done && !error) {
      94             :  *              call lookup to search path.
      95             :  *              if symbolic link, massage name in buffer and continue
      96             :  *      }
      97             :  */
      98             : int
      99           0 : namei(struct nameidata *ndp)
     100             : {
     101             :         struct filedesc *fdp;           /* pointer to file descriptor state */
     102             :         char *cp;                       /* pointer into pathname argument */
     103             :         struct vnode *dp;               /* the directory we are searching */
     104           0 :         struct iovec aiov;              /* uio for reading symbolic links */
     105           0 :         struct uio auio;
     106             :         int error, linklen;
     107           0 :         struct componentname *cnp = &ndp->ni_cnd;
     108           0 :         struct proc *p = cnp->cn_proc;
     109             : 
     110           0 :         ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
     111             : #ifdef DIAGNOSTIC
     112           0 :         if (!cnp->cn_cred || !cnp->cn_proc)
     113           0 :                 panic ("namei: bad cred/proc");
     114           0 :         if (cnp->cn_nameiop & (~OPMASK))
     115           0 :                 panic ("namei: nameiop contaminated with flags");
     116           0 :         if (cnp->cn_flags & OPMASK)
     117           0 :                 panic ("namei: flags contaminated with nameiops");
     118             : #endif
     119           0 :         fdp = cnp->cn_proc->p_fd;
     120             : 
     121             :         /*
     122             :          * Get a buffer for the name to be translated, and copy the
     123             :          * name into the buffer.
     124             :          */
     125           0 :         if ((cnp->cn_flags & HASBUF) == 0)
     126           0 :                 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
     127           0 :         if (ndp->ni_segflg == UIO_SYSSPACE)
     128           0 :                 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
     129             :                             MAXPATHLEN, &ndp->ni_pathlen);
     130             :         else
     131           0 :                 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
     132             :                             MAXPATHLEN, &ndp->ni_pathlen);
     133             : 
     134             :         /*
     135             :          * Fail on null pathnames
     136             :          */
     137           0 :         if (error == 0 && ndp->ni_pathlen == 1)
     138           0 :                 error = ENOENT;
     139             : 
     140           0 :         if (error) {
     141             : fail:
     142           0 :                 pool_put(&namei_pool, cnp->cn_pnbuf);
     143           0 :                 ndp->ni_vp = NULL;
     144           0 :                 return (error);
     145             :         }
     146             : 
     147             : #ifdef KTRACE
     148           0 :         if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
     149           0 :                 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
     150             : #endif
     151             : 
     152             :         /*
     153             :          *  Strip trailing slashes, as requested
     154             :          */
     155           0 :         if (cnp->cn_flags & STRIPSLASHES) {
     156           0 :                 char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
     157             : 
     158             :                 cp = end;
     159           0 :                 while (cp >= cnp->cn_pnbuf && (*cp == '/'))
     160           0 :                         cp--;
     161             : 
     162             :                 /* Still some remaining characters in the buffer */
     163           0 :                 if (cp >= cnp->cn_pnbuf) {
     164           0 :                         ndp->ni_pathlen -= (end - cp);
     165           0 :                         *(cp + 1) = '\0';
     166           0 :                 }
     167           0 :         }
     168             : 
     169           0 :         ndp->ni_loopcnt = 0;
     170             : 
     171             :         /*
     172             :          * Get starting point for the translation.
     173             :          */
     174           0 :         if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL ||
     175           0 :             (ndp->ni_cnd.cn_flags & KERNELPATH))
     176           0 :                 ndp->ni_rootdir = rootvnode;
     177             : 
     178           0 :         if (ndp->ni_cnd.cn_flags & KERNELPATH) {
     179           0 :                 ndp->ni_cnd.cn_flags |= BYPASSUNVEIL;
     180           0 :         } else {
     181           0 :                 error = pledge_namei(p, ndp, cnp->cn_pnbuf);
     182           0 :                 if (error)
     183             :                         goto fail;
     184             :         }
     185             : 
     186             :         /*
     187             :          * Check if starting from root directory or current directory.
     188             :          */
     189           0 :         if (cnp->cn_pnbuf[0] == '/') {
     190           0 :                 curproc->p_p->ps_uvpcwd = NULL;
     191           0 :                 curproc->p_p->ps_uvpcwdgone = 0;
     192           0 :                 dp = ndp->ni_rootdir;
     193           0 :                 vref(dp);
     194           0 :         } else if (ndp->ni_dirfd == AT_FDCWD) {
     195           0 :                 dp = fdp->fd_cdir;
     196           0 :                 vref(dp);
     197           0 :                 unveil_check_component(p, ndp, dp);
     198           0 :         } else {
     199           0 :                 struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
     200           0 :                 if (fp == NULL) {
     201           0 :                         pool_put(&namei_pool, cnp->cn_pnbuf);
     202           0 :                         return (EBADF);
     203             :                 }
     204           0 :                 dp = (struct vnode *)fp->f_data;
     205           0 :                 if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) {
     206           0 :                         FRELE(fp, p);
     207           0 :                         pool_put(&namei_pool, cnp->cn_pnbuf);
     208           0 :                         return (ENOTDIR);
     209             :                 }
     210           0 :                 vref(dp);
     211           0 :                 unveil_check_component(p, ndp, dp);
     212           0 :                 FRELE(fp, p);
     213           0 :         }
     214           0 :         for (;;) {
     215           0 :                 if (!dp->v_mount) {
     216             :                         /* Give up if the directory is no longer mounted */
     217           0 :                         pool_put(&namei_pool, cnp->cn_pnbuf);
     218           0 :                         vrele(dp);
     219           0 :                         ndp->ni_vp = NULL;
     220           0 :                         return (ENOENT);
     221             :                 }
     222           0 :                 cnp->cn_nameptr = cnp->cn_pnbuf;
     223           0 :                 ndp->ni_startdir = dp;
     224           0 :                 if ((error = vfs_lookup(ndp)) != 0) {
     225           0 :                         pool_put(&namei_pool, cnp->cn_pnbuf);
     226           0 :                         return (error);
     227             :                 }
     228             :                 /*
     229             :                  * If not a symbolic link, return search result.
     230             :                  */
     231           0 :                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
     232           0 :                         if ((error = unveil_check_final(p, ndp))) {
     233           0 :                                 pool_put(&namei_pool, cnp->cn_pnbuf);
     234           0 :                                 if ((cnp->cn_flags & LOCKPARENT) &&
     235           0 :                                     (cnp->cn_flags & ISLASTCN) &&
     236           0 :                                     (ndp->ni_vp != ndp->ni_dvp))
     237           0 :                                         VOP_UNLOCK(ndp->ni_dvp);
     238           0 :                                 if (ndp->ni_vp) {
     239           0 :                                         if ((cnp->cn_flags & LOCKLEAF))
     240           0 :                                                 vput(ndp->ni_vp);
     241             :                                         else
     242           0 :                                                 vrele(ndp->ni_vp);
     243             :                                 }
     244           0 :                                 ndp->ni_vp = NULL;
     245           0 :                                 return (error);
     246             :                         }
     247           0 :                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
     248           0 :                                 pool_put(&namei_pool, cnp->cn_pnbuf);
     249             :                         else
     250           0 :                                 cnp->cn_flags |= HASBUF;
     251           0 :                         return(0);
     252             :                 }
     253           0 :                 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
     254           0 :                         VOP_UNLOCK(ndp->ni_dvp);
     255           0 :                 if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) {
     256             :                         error = ELOOP;
     257           0 :                         break;
     258             :                 }
     259           0 :                 if (ndp->ni_pathlen > 1)
     260           0 :                         cp = pool_get(&namei_pool, PR_WAITOK);
     261             :                 else
     262           0 :                         cp = cnp->cn_pnbuf;
     263           0 :                 aiov.iov_base = cp;
     264           0 :                 aiov.iov_len = MAXPATHLEN;
     265           0 :                 auio.uio_iov = &aiov;
     266           0 :                 auio.uio_iovcnt = 1;
     267           0 :                 auio.uio_offset = 0;
     268           0 :                 auio.uio_rw = UIO_READ;
     269           0 :                 auio.uio_segflg = UIO_SYSSPACE;
     270           0 :                 auio.uio_procp = cnp->cn_proc;
     271           0 :                 auio.uio_resid = MAXPATHLEN;
     272           0 :                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
     273           0 :                 if (error) {
     274             : badlink:
     275           0 :                         if (ndp->ni_pathlen > 1)
     276           0 :                                 pool_put(&namei_pool, cp);
     277             :                         break;
     278             :                 }
     279           0 :                 linklen = MAXPATHLEN - auio.uio_resid;
     280           0 :                 if (linklen == 0) {
     281             :                         error = ENOENT;
     282           0 :                         goto badlink;
     283             :                 }
     284           0 :                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
     285             :                         error = ENAMETOOLONG;
     286           0 :                         goto badlink;
     287             :                 }
     288           0 :                 if (ndp->ni_pathlen > 1) {
     289           0 :                         memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
     290           0 :                         pool_put(&namei_pool, cnp->cn_pnbuf);
     291           0 :                         cnp->cn_pnbuf = cp;
     292           0 :                 } else
     293           0 :                         cnp->cn_pnbuf[linklen] = '\0';
     294           0 :                 ndp->ni_pathlen += linklen;
     295           0 :                 vput(ndp->ni_vp);
     296           0 :                 dp = ndp->ni_dvp;
     297             :                 /*
     298             :                  * Check if root directory should replace current directory.
     299             :                  */
     300           0 :                 if (cnp->cn_pnbuf[0] == '/') {
     301           0 :                         vrele(dp);
     302           0 :                         dp = ndp->ni_rootdir;
     303           0 :                         vref(dp);
     304           0 :                         ndp->ni_unveil_match = NULL;
     305           0 :                         curproc->p_p->ps_uvpcwd = NULL;
     306           0 :                         unveil_check_component(p, ndp, dp);
     307           0 :                 } else {
     308             :                         /*
     309             :                          * this is a relative link, so remember our
     310             :                          * unveil match from this point
     311             :                          */
     312           0 :                         curproc->p_p->ps_uvpcwd = ndp->ni_unveil_match;
     313             :                 }
     314             : 
     315             :         }
     316           0 :         pool_put(&namei_pool, cnp->cn_pnbuf);
     317           0 :         vrele(ndp->ni_dvp);
     318           0 :         vput(ndp->ni_vp);
     319           0 :         ndp->ni_vp = NULL;
     320           0 :         return (error);
     321           0 : }
     322             : 
     323             : /*
     324             :  * Search a pathname.
     325             :  * This is a very central and rather complicated routine.
     326             :  *
     327             :  * The pathname is pointed to by ni_cnd.cn_nameptr and is of length
     328             :  * ni_pathlen.  The starting directory is taken from ni_startdir. The
     329             :  * pathname is descended until done, or a symbolic link is encountered.
     330             :  * If the path is completed the flag ISLASTCN is set in ni_cnd.cn_flags.
     331             :  * If a symbolic link need interpretation is encountered, the flag ISSYMLINK
     332             :  * is set in ni_cnd.cn_flags.
     333             :  *
     334             :  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
     335             :  * whether the name is to be looked up, created, renamed, or deleted.
     336             :  * When CREATE, RENAME, or DELETE is specified, information usable in
     337             :  * creating, renaming, or deleting a directory entry may be calculated.
     338             :  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
     339             :  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
     340             :  * returned unlocked. Otherwise the parent directory is not returned. If
     341             :  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
     342             :  * the target is returned locked, otherwise it is returned unlocked.
     343             :  * When creating or renaming and LOCKPARENT is specified, the target may not
     344             :  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
     345             :  *
     346             :  * Overall outline of lookup:
     347             :  *
     348             :  * dirloop:
     349             :  *      identify next component of name at ndp->ni_ptr
     350             :  *      handle degenerate case where name is null string
     351             :  *      if .. and crossing mount points and on mounted filesys, find parent
     352             :  *      call VOP_LOOKUP routine for next component name
     353             :  *          directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
     354             :  *          component vnode returned in ni_vp (if it exists), locked.
     355             :  *      if result vnode is mounted on and crossing mount points,
     356             :  *          find mounted on vnode
     357             :  *      if more components of name, do next level at dirloop
     358             :  *      return the answer in ni_vp, locked if LOCKLEAF set
     359             :  *          if LOCKPARENT set, return locked parent in ni_dvp
     360             :  *          if WANTPARENT set, return unlocked parent in ni_dvp
     361             :  */
     362             : int
     363           0 : vfs_lookup(struct nameidata *ndp)
     364             : {
     365             :         char *cp;                       /* pointer into pathname argument */
     366             :         struct vnode *dp = 0;           /* the directory we are searching */
     367           0 :         struct vnode *tdp;              /* saved dp */
     368             :         struct mount *mp;               /* mount table entry */
     369             :         int docache;                    /* == 0 do not cache last component */
     370             :         int wantparent;                 /* 1 => wantparent or lockparent flag */
     371             :         int rdonly;                     /* lookup read-only flag bit */
     372             :         int error = 0;
     373             :         int dpunlocked = 0;             /* dp has already been unlocked */
     374             :         int slashes;
     375           0 :         struct componentname *cnp = &ndp->ni_cnd;
     376             :         /*
     377             :          * Setup: break out flag bits into variables.
     378             :          */
     379           0 :         wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
     380           0 :         docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
     381           0 :         if (cnp->cn_nameiop == DELETE ||
     382           0 :             (wantparent && cnp->cn_nameiop != CREATE))
     383           0 :                 docache = 0;
     384           0 :         rdonly = cnp->cn_flags & RDONLY;
     385           0 :         ndp->ni_dvp = NULL;
     386           0 :         cnp->cn_flags &= ~ISSYMLINK;
     387           0 :         dp = ndp->ni_startdir;
     388           0 :         ndp->ni_startdir = NULLVP;
     389           0 :         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
     390             : 
     391             :         /*
     392             :          * If we have a leading string of slashes, remove them, and just make
     393             :          * sure the current node is a directory.
     394             :          */
     395           0 :         cp = cnp->cn_nameptr;
     396           0 :         if (*cp == '/') {
     397           0 :                 do {
     398           0 :                         cp++;
     399           0 :                 } while (*cp == '/');
     400           0 :                 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
     401           0 :                 cnp->cn_nameptr = cp;
     402             : 
     403           0 :                 if (dp->v_type != VDIR) {
     404             :                         error = ENOTDIR;
     405           0 :                         goto bad;
     406             :                 }
     407             : 
     408             :                 /*
     409             :                  * If we've exhausted the path name, then just return the
     410             :                  * current node.  If the caller requested the parent node (i.e.
     411             :                  * it's a CREATE, DELETE, or RENAME), and we don't have one
     412             :                  * (because this is the root directory), then we must fail.
     413             :                  */
     414           0 :                 if (cnp->cn_nameptr[0] == '\0') {
     415           0 :                         if (ndp->ni_dvp == NULL && wantparent) {
     416             :                                 error = EISDIR;
     417           0 :                                 goto bad;
     418             :                         }
     419           0 :                         ndp->ni_vp = dp;
     420           0 :                         cnp->cn_flags |= ISLASTCN;
     421           0 :                         goto terminal;
     422             :                 }
     423             :         }
     424             : 
     425             : dirloop:
     426             :         /*
     427             :          * Search a new directory.
     428             :          *
     429             :          * The last component of the filename is left accessible via
     430             :          * cnp->cn_nameptr for callers that need the name. Callers needing
     431             :          * the name set the SAVENAME flag. When done, they assume
     432             :          * responsibility for freeing the pathname buffer.
     433             :          */
     434           0 :         cnp->cn_consume = 0;
     435             : 
     436             :         /* XXX: Figure out the length of the last component. */
     437           0 :         cp = cnp->cn_nameptr;
     438           0 :         while (*cp && (*cp != '/'))
     439           0 :                 cp++;
     440           0 :         cnp->cn_namelen = cp - cnp->cn_nameptr;
     441           0 :         if (cnp->cn_namelen > NAME_MAX) {
     442             :                 error = ENAMETOOLONG;
     443           0 :                 goto bad;
     444             :         }
     445             : 
     446             : #ifdef NAMEI_DIAGNOSTIC
     447             :         { char c = *cp;
     448             :         *cp = '\0';
     449             :         printf("{%s}: ", cnp->cn_nameptr);
     450             :         *cp = c; }
     451             : #endif
     452           0 :         ndp->ni_pathlen -= cnp->cn_namelen;
     453           0 :         ndp->ni_next = cp;
     454             :         /*
     455             :          * If this component is followed by a slash, then move the pointer to
     456             :          * the next component forward, and remember that this component must be
     457             :          * a directory.
     458             :          */
     459           0 :         if (*cp == '/') {
     460           0 :                 do {
     461           0 :                         cp++;
     462           0 :                 } while (*cp == '/');
     463           0 :                 slashes = cp - ndp->ni_next;
     464           0 :                 ndp->ni_pathlen -= slashes;
     465           0 :                 ndp->ni_next = cp;
     466           0 :                 cnp->cn_flags |= REQUIREDIR;
     467           0 :         } else {
     468             :                 slashes = 0;
     469           0 :                 cnp->cn_flags &= ~REQUIREDIR;
     470             :         }
     471             :         /*
     472             :          * We do special processing on the last component, whether or not it's
     473             :          * a directory.  Cache all intervening lookups, but not the final one.
     474             :          */
     475           0 :         if (*cp == '\0') {
     476           0 :                 if (docache)
     477           0 :                         cnp->cn_flags |= MAKEENTRY;
     478             :                 else
     479           0 :                         cnp->cn_flags &= ~MAKEENTRY;
     480           0 :                 cnp->cn_flags |= ISLASTCN;
     481           0 :         } else {
     482           0 :                 cnp->cn_flags |= MAKEENTRY;
     483           0 :                 cnp->cn_flags &= ~ISLASTCN;
     484             :         }
     485           0 :         if (cnp->cn_namelen == 2 &&
     486           0 :             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
     487           0 :                 cnp->cn_flags |= ISDOTDOT;
     488             :         else
     489           0 :                 cnp->cn_flags &= ~ISDOTDOT;
     490             : 
     491             :         /*
     492             :          * Handle "..": two special cases.
     493             :          * 1. If at root directory (e.g. after chroot)
     494             :          *    or at absolute root directory
     495             :          *    or we are under unveil restrictions
     496             :          *    then ignore it so can't get out.
     497             :          * 2. If this vnode is the root of a mounted
     498             :          *    filesystem, then replace it with the
     499             :          *    vnode which was mounted on so we take the
     500             :          *    .. in the other file system.
     501             :          */
     502           0 :         if (cnp->cn_flags & ISDOTDOT) {
     503           0 :                 for (;;) {
     504           0 :                         if (curproc->p_p->ps_uvvcount > 0) {
     505             : #if 0
     506             :                                 error = ENOENT;
     507             :                                 goto bad;
     508             : #else
     509           0 :                                 ndp->ni_unveil_match = NULL;
     510             : #endif
     511           0 :                         }
     512           0 :                         if (dp == ndp->ni_rootdir || dp == rootvnode) {
     513           0 :                                 ndp->ni_dvp = dp;
     514           0 :                                 ndp->ni_vp = dp;
     515           0 :                                 vref(dp);
     516           0 :                                 curproc->p_p->ps_uvpcwd = NULL;
     517           0 :                                 curproc->p_p->ps_uvpcwdgone = 0;
     518           0 :                                 goto nextname;
     519             :                         }
     520           0 :                         if ((dp->v_flag & VROOT) == 0 ||
     521           0 :                             (cnp->cn_flags & NOCROSSMOUNT))
     522             :                                 break;
     523           0 :                         tdp = dp;
     524           0 :                         dp = dp->v_mount->mnt_vnodecovered;
     525           0 :                         vput(tdp);
     526           0 :                         vref(dp);
     527           0 :                         unveil_check_component(curproc, ndp, dp);
     528           0 :                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
     529             :                 }
     530             :         }
     531             : 
     532             :         /*
     533             :          * We now have a segment name to search for, and a directory to search.
     534             :          */
     535           0 :         ndp->ni_dvp = dp;
     536           0 :         ndp->ni_vp = NULL;
     537           0 :         cnp->cn_flags &= ~PDIRUNLOCK;
     538           0 :         unveil_check_component(curproc, ndp, dp);
     539             : 
     540           0 :         if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
     541             : #ifdef DIAGNOSTIC
     542           0 :                 if (ndp->ni_vp != NULL)
     543           0 :                         panic("leaf should be empty");
     544             : #endif
     545             : #ifdef NAMEI_DIAGNOSTIC
     546             :                 printf("not found\n");
     547             : #endif
     548             :                 /*
     549             :                  * Allow for unveiling of a file in a directory
     550             :                  * where we don't have access to create it ourselves
     551             :                  */
     552           0 :                 if (ndp->ni_pledge == PLEDGE_UNVEIL && error == EACCES)
     553           0 :                         error = EJUSTRETURN;
     554             : 
     555           0 :                 if (error != EJUSTRETURN)
     556             :                         goto bad;
     557             :                 /*
     558             :                  * If this was not the last component, or there were trailing
     559             :                  * slashes, then the name must exist.
     560             :                  */
     561           0 :                 if (cnp->cn_flags & REQUIREDIR) {
     562             :                         error = ENOENT;
     563           0 :                         goto bad;
     564             :                 }
     565             :                 /*
     566             :                  * If creating and at end of pathname, then can consider
     567             :                  * allowing file to be created. Check for a read only
     568             :                  * filesystem and disallow this unless we are unveil'ing
     569             :                  */
     570           0 :                 if (ndp->ni_pledge != PLEDGE_UNVEIL && (rdonly ||
     571           0 :                     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
     572             :                             error = EROFS;
     573           0 :                             goto bad;
     574             :                 }
     575             :                 /*
     576             :                  * We return with ni_vp NULL to indicate that the entry
     577             :                  * doesn't currently exist, leaving a pointer to the
     578             :                  * (possibly locked) directory inode in ndp->ni_dvp.
     579             :                  */
     580           0 :                 if (cnp->cn_flags & SAVESTART) {
     581           0 :                         ndp->ni_startdir = ndp->ni_dvp;
     582           0 :                         vref(ndp->ni_startdir);
     583           0 :                 }
     584           0 :                 return (0);
     585             :         }
     586             : #ifdef NAMEI_DIAGNOSTIC
     587             :                 printf("found\n");
     588             : #endif
     589             : 
     590             :         /*
     591             :          * Take into account any additional components consumed by the
     592             :          * underlying filesystem.  This will include any trailing slashes after
     593             :          * the last component consumed.
     594             :          */
     595           0 :         if (cnp->cn_consume > 0) {
     596           0 :                 if (cnp->cn_consume >= slashes) {
     597           0 :                         cnp->cn_flags &= ~REQUIREDIR;
     598           0 :                 }
     599             : 
     600           0 :                 ndp->ni_pathlen -= cnp->cn_consume - slashes;
     601           0 :                 ndp->ni_next += cnp->cn_consume - slashes;
     602           0 :                 cnp->cn_consume = 0;
     603           0 :                 if (ndp->ni_next[0] == '\0')
     604           0 :                         cnp->cn_flags |= ISLASTCN;
     605             :         }
     606             : 
     607           0 :         dp = ndp->ni_vp;
     608             :         /*
     609             :          * Check to see if the vnode has been mounted on;
     610             :          * if so find the root of the mounted file system.
     611             :          */
     612           0 :         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
     613           0 :             (cnp->cn_flags & NOCROSSMOUNT) == 0) {
     614           0 :                 if (vfs_busy(mp, VB_READ|VB_WAIT))
     615           0 :                         continue;
     616           0 :                 VOP_UNLOCK(dp);
     617           0 :                 error = VFS_ROOT(mp, &tdp);
     618           0 :                 vfs_unbusy(mp);
     619           0 :                 if (error) {
     620             :                         dpunlocked = 1;
     621           0 :                         goto bad2;
     622             :                 }
     623           0 :                 vrele(dp);
     624           0 :                 ndp->ni_vp = dp = tdp;
     625             :         }
     626             : 
     627             :         /*
     628             :          * Check for symbolic link.  Back up over any slashes that we skipped,
     629             :          * as we will need them again.
     630             :          */
     631           0 :         if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
     632           0 :                 ndp->ni_pathlen += slashes;
     633           0 :                 ndp->ni_next -= slashes;
     634           0 :                 cnp->cn_flags |= ISSYMLINK;
     635           0 :                 return (0);
     636             :         }
     637             : 
     638             :         /*
     639             :          * Check for directory, if the component was followed by a series of
     640             :          * slashes.
     641             :          */
     642           0 :         if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
     643             :                 error = ENOTDIR;
     644           0 :                 goto bad2;
     645             :         }
     646             : 
     647             : nextname:
     648             :         /*
     649             :          * Not a symbolic link.  If this was not the last component, then
     650             :          * continue at the next component, else return.
     651             :          */
     652           0 :         if (!(cnp->cn_flags & ISLASTCN)) {
     653           0 :                 cnp->cn_nameptr = ndp->ni_next;
     654           0 :                 vrele(ndp->ni_dvp);
     655           0 :                 goto dirloop;
     656             :         }
     657             : 
     658             : terminal:
     659             :         /*
     660             :          * Check for read-only file systems.
     661             :          */
     662           0 :         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
     663             :                 /*
     664             :                  * Disallow directory write attempts on read-only
     665             :                  * file systems.
     666             :                  */
     667           0 :                 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
     668           0 :                     (wantparent &&
     669           0 :                     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
     670             :                         error = EROFS;
     671           0 :                         goto bad2;
     672             :                 }
     673             :         }
     674           0 :         if (ndp->ni_dvp != NULL) {
     675           0 :                 if (cnp->cn_flags & SAVESTART) {
     676           0 :                         ndp->ni_startdir = ndp->ni_dvp;
     677           0 :                         vref(ndp->ni_startdir);
     678           0 :                 }
     679           0 :                 if (!wantparent)
     680           0 :                         vrele(ndp->ni_dvp);
     681             :         }
     682           0 :         if ((cnp->cn_flags & LOCKLEAF) == 0)
     683           0 :                 VOP_UNLOCK(dp);
     684           0 :         return (0);
     685             : 
     686             : bad2:
     687           0 :         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
     688           0 :             ((cnp->cn_flags & PDIRUNLOCK) == 0))
     689           0 :                 VOP_UNLOCK(ndp->ni_dvp);
     690           0 :         vrele(ndp->ni_dvp);
     691             : bad:
     692           0 :         if (dpunlocked)
     693           0 :                 vrele(dp);
     694             :         else
     695           0 :                 vput(dp);
     696           0 :         ndp->ni_vp = NULL;
     697           0 :         return (error);
     698           0 : }
     699             : 
     700             : /*
     701             :  * Reacquire a path name component.
     702             :  */
     703             : int
     704           0 : vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
     705             : {
     706             :         struct vnode *dp = 0;           /* the directory we are searching */
     707             :         int wantparent;                 /* 1 => wantparent or lockparent flag */
     708             :         int rdonly;                     /* lookup read-only flag bit */
     709             :         int error = 0;
     710             : #ifdef NAMEI_DIAGNOSTIC
     711             :         char *cp;                       /* DEBUG: check name ptr/len */
     712             : #endif
     713             : 
     714             :         /*
     715             :          * Setup: break out flag bits into variables.
     716             :          */
     717           0 :         wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
     718           0 :         rdonly = cnp->cn_flags & RDONLY;
     719           0 :         cnp->cn_flags &= ~ISSYMLINK;
     720             :         dp = dvp;
     721           0 :         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
     722             : 
     723             : /* dirloop: */
     724             :         /*
     725             :          * Search a new directory.
     726             :          *
     727             :          * The last component of the filename is left accessible via
     728             :          * cnp->cn_nameptr for callers that need the name. Callers needing
     729             :          * the name set the SAVENAME flag. When done, they assume
     730             :          * responsibility for freeing the pathname buffer.
     731             :          */
     732             : 
     733             : #ifdef NAMEI_DIAGNOSTIC
     734             :         /* XXX: Figure out the length of the last component. */
     735             :         cp = cnp->cn_nameptr;
     736             :         while (*cp && (*cp != '/')) {
     737             :                 cp++;
     738             :         }
     739             :         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
     740             :                 panic("relookup: bad len");
     741             :         if (*cp != 0)
     742             :                 panic("relookup: not last component");
     743             :         printf("{%s}: ", cnp->cn_nameptr);
     744             : #endif
     745             : 
     746             :         /*
     747             :          * Check for degenerate name (e.g. / or "")
     748             :          * which is a way of talking about a directory,
     749             :          * e.g. like "/." or ".".
     750             :          */
     751           0 :         if (cnp->cn_nameptr[0] == '\0')
     752           0 :                 panic("relookup: null name");
     753             : 
     754           0 :         if (cnp->cn_flags & ISDOTDOT)
     755           0 :                 panic ("relookup: lookup on dot-dot");
     756             : 
     757             :         /*
     758             :          * We now have a segment name to search for, and a directory to search.
     759             :          */
     760           0 :         if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
     761             : #ifdef DIAGNOSTIC
     762           0 :                 if (*vpp != NULL)
     763           0 :                         panic("leaf should be empty");
     764             : #endif
     765           0 :                 if (error != EJUSTRETURN)
     766             :                         goto bad;
     767             :                 /*
     768             :                  * If creating and at end of pathname, then can consider
     769             :                  * allowing file to be created.
     770             :                  */
     771           0 :                 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
     772             :                         error = EROFS;
     773           0 :                         goto bad;
     774             :                 }
     775             :                 /* ASSERT(dvp == ndp->ni_startdir) */
     776           0 :                 if (cnp->cn_flags & SAVESTART)
     777           0 :                         vref(dvp);
     778             :                 /*
     779             :                  * We return with ni_vp NULL to indicate that the entry
     780             :                  * doesn't currently exist, leaving a pointer to the
     781             :                  * (possibly locked) directory inode in ndp->ni_dvp.
     782             :                  */
     783           0 :                 return (0);
     784             :         }
     785             :         dp = *vpp;
     786             : 
     787             : #ifdef DIAGNOSTIC
     788             :         /*
     789             :          * Check for symbolic link
     790             :          */
     791           0 :         if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
     792           0 :                 panic ("relookup: symlink found.");
     793             : #endif
     794             : 
     795             :         /*
     796             :          * Check for read-only file systems.
     797             :          */
     798           0 :         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
     799             :                 /*
     800             :                  * Disallow directory write attempts on read-only
     801             :                  * file systems.
     802             :                  */
     803           0 :                 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
     804           0 :                     (wantparent &&
     805           0 :                     (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
     806             :                         error = EROFS;
     807             :                         goto bad2;
     808             :                 }
     809             :         }
     810             :         /* ASSERT(dvp == ndp->ni_startdir) */
     811           0 :         if (cnp->cn_flags & SAVESTART)
     812           0 :                 vref(dvp);
     813           0 :         if (!wantparent)
     814           0 :                 vrele(dvp);
     815           0 :         if ((cnp->cn_flags & LOCKLEAF) == 0)
     816           0 :                 VOP_UNLOCK(dp);
     817           0 :         return (0);
     818             : 
     819             : bad2:
     820           0 :         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
     821           0 :                 VOP_UNLOCK(dvp);
     822           0 :         vrele(dvp);
     823             : bad:
     824           0 :         vput(dp);
     825           0 :         *vpp = NULL;
     826           0 :         return (error);
     827           0 : }

Generated by: LCOV version 1.13