Subject: kern/25963: incorrect refcounting in coda symlink vnops leads to panic
To: None <gnats-bugs@gnats.netbsd.org>
From: None <gdt@ir.bbn.com>
List: netbsd-bugs
Date: 06/18/2004 09:28:51
>Number:         25963
>Category:       kern
>Synopsis:       incorrect refcounting in coda symlink vnops leads to panic
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 18 13:29:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Greg Troxel
>Release:        NetBSD 1.6ZI
>Organization:
        Greg Troxel <gdt@ir.bbn.com>
>Environment:
	
	
System: netbsd-current from early february, but note that this file
has not changed since 2003-10-30
Architecture: i386
Machine: i386
>Description:
The coda symlink code has not been updated for the new lookup locking rules.

>How-To-Repeat:

Make a lot of symlinks in coda.  Note the eventual crash.

>Fix:

Thanks to Bill Studenmund for helping me through figuring this out and
suggesting how to fix.

Index: src/sys/coda/coda_vnops.c
===================================================================
RCS file: /SINEW-CVS/netbsd/src/sys/coda/coda_vnops.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/sys/coda/coda_vnops.c	30 Oct 2003 02:07:38 -0000	1.1.1.1
+++ src/sys/coda/coda_vnops.c	18 Jun 2004 12:31:56 -0000	1.2
@@ -1584,6 +1584,7 @@
     struct proc *p = cnp->cn_proc;
 /* locals */
     int error;
+    u_long saved_cn_flags;
     /* 
      * XXX I'm assuming the following things about coda_symlink's
      * arguments: 
@@ -1629,26 +1630,28 @@
     /* Invalidate the parent's attr cache, the modification time has changed */
     tdcp->c_flags &= ~C_VATTR;
 
-    if (!error)
-    {
-	struct nameidata nd;
-	NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, nm, p);
-	nd.ni_cnd.cn_cred = cred;
-	nd.ni_loopcnt = 0;
-	nd.ni_startdir = tdvp;
-	nd.ni_cnd.cn_pnbuf = (char *)nm;
-	nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
-	nd.ni_pathlen = len;
-	vput(tdvp);
-	error = lookup(&nd);
-	*ap->a_vpp = nd.ni_vp;
-    }
-
-    /* 
-     * Free the name buffer 
-     */
-    if ((cnp->cn_flags & SAVESTART) == 0) {
-	PNBUF_PUT(cnp->cn_pnbuf);
+    if (!error) {
+	/*
+	 * VOP_SYMLINK is not defined to pay attention to cnp->cn_flags;
+	 * these are defined only for VOP_LOOKUP.   We desire to reuse
+	 * cnp for a VOP_LOOKUP operation, and must be sure to not pass
+	 * stray flags passed to us.  Such stray flags can occur because
+	 * sys_symlink makes a namei call and then reuses the
+	 * componentname structure.
+	 */
+	/*
+	 * XXX Arguably we should create our own componentname structure
+	 * and not reuse the one that was passed in.
+	 */
+	saved_cn_flags = cnp->cn_flags;
+	cnp->cn_flags &= ~(MODMASK | OPMASK);
+	cnp->cn_flags |= LOOKUP;
+	error = VOP_LOOKUP(tdvp, ap->a_vpp, cnp);
+	cnp->cn_flags = saved_cn_flags;
+	/* Either an error occurs, or ap->a_vpp is locked. */
+    } else {
+	/* error, so unlock and deference parent */
+        vput(tdvp);
     }
 
  exit:    

>Release-Note:
>Audit-Trail:
>Unformatted: