Author: des
Date: Sun Jun 21 19:39:34 2009
New Revision: 194604
URL: http://svn.freebsd.org/changeset/base/194604

Log:
  merge r193027, r193557, r192900, r193028: fix trailing-slash symlink bug
  
  PR:           kern/21768

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/kern/vfs_lookup.c
  stable/7/sys/sys/namei.h

Modified: stable/7/sys/kern/vfs_lookup.c
==============================================================================
--- stable/7/sys/kern/vfs_lookup.c      Sun Jun 21 19:31:41 2009        
(r194603)
+++ stable/7/sys/kern/vfs_lookup.c      Sun Jun 21 19:39:34 2009        
(r194604)
@@ -138,6 +138,9 @@ namei(struct nameidata *ndp)
                cnp->cn_flags &= ~LOCKSHARED;
        fdp = p->p_fd;
 
+       /* We will set this ourselves if we need it. */
+       cnp->cn_flags &= ~TRAILINGSLASH;
+
        /*
         * Get a buffer for the name to be translated, and copy the
         * name into the buffer.
@@ -224,7 +227,7 @@ namei(struct nameidata *ndp)
                vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
                ndp->ni_cnd.cn_flags &= ~GIANTHELD;
                /*
-                * Check for symbolic link
+                * If not a symbolic link, we're done.
                 */
                if ((cnp->cn_flags & ISSYMLINK) == 0) {
                        if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
@@ -367,7 +370,6 @@ lookup(struct nameidata *ndp)
        int docache;                    /* == 0 do not cache last component */
        int wantparent;                 /* 1 => wantparent or lockparent flag */
        int rdonly;                     /* lookup read-only flag bit */
-       int trailing_slash;
        int error = 0;
        int dpunlocked = 0;             /* dp has already been unlocked */
        struct componentname *cnp = &ndp->ni_cnd;
@@ -439,13 +441,12 @@ dirloop:
         * trailing slashes to handle symlinks, existing non-directories
         * and non-existing files that won't be directories specially later.
         */
-       trailing_slash = 0;
        while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
                cp++;
                ndp->ni_pathlen--;
                if (*cp == '\0') {
-                       trailing_slash = 1;
-                       *ndp->ni_next = '\0';   /* XXX for direnter() ... */
+                       *ndp->ni_next = '\0';
+                       cnp->cn_flags |= TRAILINGSLASH;
                }
        }
        ndp->ni_next = cp;
@@ -604,27 +605,24 @@ unionlookup:
                if (error != EJUSTRETURN)
                        goto bad;
                /*
-                * If creating and at end of pathname, then can consider
-                * allowing file to be created.
+                * At this point, we know we're at the end of the
+                * pathname.  If creating / renaming, we can consider
+                * allowing the file or directory to be created / renamed,
+                * provided we're not on a read-only filesystem.
                 */
                if (rdonly) {
                        error = EROFS;
                        goto bad;
                }
-               if (*cp == '\0' && trailing_slash &&
-                    !(cnp->cn_flags & WILLBEDIR)) {
+               /* trailing slash only allowed for directories */
+               if ((cnp->cn_flags & TRAILINGSLASH) &&
+                   !(cnp->cn_flags & WILLBEDIR)) {
                        error = ENOENT;
                        goto bad;
                }
                if ((cnp->cn_flags & LOCKPARENT) == 0)
                        VOP_UNLOCK(dp, 0, td);
                /*
-                * This is a temporary assert to make sure I know what the
-                * behavior here was.
-                */
-               KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
-                  ("lookup: Unhandled case."));
-               /*
                 * We return with ni_vp NULL to indicate that the entry
                 * doesn't currently exist, leaving a pointer to the
                 * (possibly locked) directory vnode in ndp->ni_dvp.
@@ -687,7 +685,7 @@ unionlookup:
         * Check for symbolic link
         */
        if ((dp->v_type == VLNK) &&
-           ((cnp->cn_flags & FOLLOW) || trailing_slash ||
+           ((cnp->cn_flags & FOLLOW) || (cnp->cn_flags & TRAILINGSLASH) ||
             *ndp->ni_next == '/')) {
                cnp->cn_flags |= ISSYMLINK;
                if (dp->v_iflag & VI_DOOMED) {
@@ -710,18 +708,10 @@ unionlookup:
                goto success;
        }
 
-       /*
-        * Check for bogus trailing slashes.
-        */
-       if (trailing_slash && dp->v_type != VDIR) {
-               error = ENOTDIR;
-               goto bad2;
-       }
-
 nextname:
        /*
-        * Not a symbolic link.  If more pathname,
-        * continue at next component, else return.
+        * Not a symbolic link that we will follow.  Continue with the
+        * next component if there is any; otherwise, we're done.
         */
        KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/',
            ("lookup: invalid path state."));
@@ -741,6 +731,14 @@ nextname:
                goto dirloop;
        }
        /*
+        * If we're processing a path with a trailing slash,
+        * check that the end result is a directory.
+        */
+       if ((cnp->cn_flags & TRAILINGSLASH) && dp->v_type != VDIR) {
+               error = ENOTDIR;
+               goto bad2;
+       }
+       /*
         * Disallow directory write attempts on read-only filesystems.
         */
        if (rdonly &&
@@ -891,12 +889,6 @@ relookup(struct vnode *dvp, struct vnode
                if ((cnp->cn_flags & LOCKPARENT) == 0)
                        VOP_UNLOCK(dp, 0, td);
                /*
-                * This is a temporary assert to make sure I know what the
-                * behavior here was.
-                */
-               KASSERT((cnp->cn_flags & (WANTPARENT|LOCKPARENT)) != 0,
-                  ("relookup: Unhandled case."));
-               /*
                 * We return with ni_vp NULL to indicate that the entry
                 * doesn't currently exist, leaving a pointer to the
                 * (possibly locked) directory vnode in ndp->ni_dvp.

Modified: stable/7/sys/sys/namei.h
==============================================================================
--- stable/7/sys/sys/namei.h    Sun Jun 21 19:31:41 2009        (r194603)
+++ stable/7/sys/sys/namei.h    Sun Jun 21 19:39:34 2009        (r194604)
@@ -127,26 +127,27 @@ struct nameidata {
  * name being sought. The caller is responsible for releasing the
  * buffer and for vrele'ing ni_startdir.
  */
-#define        RDONLY          0x0000200 /* lookup with read-only semantics */
-#define        HASBUF          0x0000400 /* has allocated pathname buffer */
-#define        SAVENAME        0x0000800 /* save pathname buffer */
-#define        SAVESTART       0x0001000 /* save starting directory */
-#define ISDOTDOT       0x0002000 /* current component name is .. */
-#define MAKEENTRY      0x0004000 /* entry is to be added to name cache */
-#define ISLASTCN       0x0008000 /* this is last component of pathname */
-#define ISSYMLINK      0x0010000 /* symlink needs interpretation */
-#define        ISWHITEOUT      0x0020000 /* found whiteout */
-#define        DOWHITEOUT      0x0040000 /* do whiteouts */
-#define        WILLBEDIR       0x0080000 /* new files will be dirs; allow 
trailing / */
-#define        ISUNICODE       0x0100000 /* current component name is unicode*/
-#define        ISOPEN          0x0200000 /* caller is opening; return a real 
vnode. */
-#define        NOCROSSMOUNT    0x0400000 /* do not cross mount points */
-#define        NOMACCHECK      0x0800000 /* do not perform MAC checks */
-#define        MPSAFE          0x1000000 /* namei() must acquire Giant if 
needed. */
-#define        GIANTHELD       0x2000000 /* namei() is holding giant. */
-#define        AUDITVNODE1     0x4000000 /* audit the looked up vnode 
information */
-#define        AUDITVNODE2     0x8000000 /* audit the looked up vnode 
information */
-#define        PARAMASK        0xffffe00 /* mask of parameter descriptors */
+#define        RDONLY          0x00000200 /* lookup with read-only semantics */
+#define        HASBUF          0x00000400 /* has allocated pathname buffer */
+#define        SAVENAME        0x00000800 /* save pathname buffer */
+#define        SAVESTART       0x00001000 /* save starting directory */
+#define        ISDOTDOT        0x00002000 /* current component name is .. */
+#define        MAKEENTRY       0x00004000 /* entry is to be added to name 
cache */
+#define        ISLASTCN        0x00008000 /* this is last component of 
pathname */
+#define        ISSYMLINK       0x00010000 /* symlink needs interpretation */
+#define        ISWHITEOUT      0x00020000 /* found whiteout */
+#define        DOWHITEOUT      0x00040000 /* do whiteouts */
+#define        WILLBEDIR       0x00080000 /* new files will be dirs; allow 
trailing / */
+#define        ISUNICODE       0x00100000 /* current component name is 
unicode*/
+#define        ISOPEN          0x00200000 /* caller is opening; return a real 
vnode. */
+#define        NOCROSSMOUNT    0x00400000 /* do not cross mount points */
+#define        NOMACCHECK      0x00800000 /* do not perform MAC checks */
+#define        MPSAFE          0x01000000 /* namei() must acquire Giant if 
needed. */
+#define        GIANTHELD       0x02000000 /* namei() is holding giant. */
+#define        AUDITVNODE1     0x04000000 /* audit the looked up vnode 
information */
+#define        AUDITVNODE2     0x08000000 /* audit the looked up vnode 
information */
+#define        TRAILINGSLASH   0x10000000 /* path ended in a slash */
+#define        PARAMASK        0x1ffffe00 /* mask of parameter descriptors */
 
 #define        NDHASGIANT(NDP) (((NDP)->ni_cnd.cn_flags & GIANTHELD) != 0)
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to