changeset 13985:ad441dd34478

Back out hg changeset 829c00a55a37, bug 2986 -- introduces vulnerability Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Christopher Siden <christopher.siden@delphix.com> Approved by: Dan McDonald <danmcd@nexenta.com>
author Marcel Telka <marcel.telka@nexenta.com>
date Thu, 14 Mar 2013 17:58:04 -0400
parents dc0c7baefe32
children 341879d91372
files usr/src/uts/common/fs/nfs/nfs3_srv.c usr/src/uts/common/fs/nfs/nfs_server.c usr/src/uts/common/fs/nfs/nfs_srv.c
diffstat 3 files changed, 30 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c	Tue Mar 12 19:31:47 2013 -0400
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c	Thu Mar 14 17:58:04 2013 -0400
@@ -433,25 +433,16 @@
 		goto out1;
 	}
 
-	exi_hold(exi);
-
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup
 	 */
 	if (PUBLIC_FH3(&args->what.dir)) {
-		struct exportinfo *new;
-
 		publicfh_flag = TRUE;
-
 		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
-		    &new, &sec);
-
-		if (error == 0) {
-			exi_rele(exi);
-			exi = new;
-		}
-
+		    &exi, &sec);
+		if (error && exi != NULL)
+			exi_rele(exi); /* See comment below Re: publicfh_flag */
 		/*
 		 * Since WebNFS may bypass MOUNT, we need to ensure this
 		 * request didn't come from an unlabeled admin_low client.
@@ -473,6 +464,8 @@
 			if (tp == NULL || tp->tpc_tp.tp_doi !=
 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 			    SUN_CIPSO) {
+				if (exi != NULL)
+					exi_rele(exi);
 				VN_RELE(vp);
 				resp->status = NFS3ERR_ACCES;
 				error = 1;
@@ -498,6 +491,8 @@
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, dvp,
 			    DOMINANCE_CHECK, exi)) {
+				if (publicfh_flag && exi != NULL)
+					exi_rele(exi);
 				VN_RELE(vp);
 				resp->status = NFS3ERR_ACCES;
 				error = 1;
@@ -524,10 +519,18 @@
 		goto out;
 	}
 
+	/*
+	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
+	 * and have obtained a new exportinfo in exi which needs to be
+	 * released. Note the the original exportinfo pointed to by exi
+	 * will be released by the caller, common_dispatch.
+	 */
+	if (publicfh_flag)
+		exi_rele(exi);
+
 	va.va_mask = AT_ALL;
 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 
-	exi_rele(exi);
 	VN_RELE(vp);
 
 	resp->status = NFS3_OK;
@@ -549,12 +552,6 @@
 	return;
 
 out:
-	/*
-	 * The passed argument exportinfo is released by the
-	 * caller, common_dispatch
-	 */
-	exi_rele(exi);
-
 	if (curthread->t_flag & T_WOULDBLOCK) {
 		curthread->t_flag &= ~T_WOULDBLOCK;
 		resp->status = NFS3ERR_JUKEBOX;
--- a/usr/src/uts/common/fs/nfs/nfs_server.c	Tue Mar 12 19:31:47 2013 -0400
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c	Thu Mar 14 17:58:04 2013 -0400
@@ -21,7 +21,6 @@
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -2801,8 +2800,8 @@
 			 */
 
 			/* Release the reference on the old exi value */
+			ASSERT(*exi != NULL);
 			exi_rele(*exi);
-			*exi = NULL;
 
 			if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
 				VN_RELE(*vpp);
@@ -2815,9 +2814,6 @@
 	if (mc_dvp)
 		VN_RELE(mc_dvp);
 
-	if (error && *exi != NULL)
-		exi_rele(*exi);
-
 	return (error);
 }
 
@@ -2963,19 +2959,16 @@
 /*
  * Get the export information for the lookup vnode, and verify its
  * useable.
- *
- * Set @exip only in success
  */
 int
 nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
-    struct exportinfo **exip)
+    struct exportinfo **exi)
 {
 	int walk;
 	int error = 0;
-	struct exportinfo *exi;
-
-	exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
-	if (exi == NULL)
+
+	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
+	if (*exi == NULL)
 		error = EACCES;
 	else {
 		/*
@@ -2984,13 +2977,10 @@
 		 * must not terminate below the
 		 * exported directory.
 		 */
-		if (exi->exi_export.ex_flags & EX_NOSUB && walk > 0) {
+		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
 			error = EACCES;
-			exi_rele(exi);
-		}
 	}
-	if (error == 0)
-		*exip = exi;
+
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c	Tue Mar 12 19:31:47 2013 -0400
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c	Thu Mar 14 17:58:04 2013 -0400
@@ -20,7 +20,6 @@
  */
 /*
  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -400,8 +399,6 @@
 		return;
 	}
 
-	exi_hold(exi);
-
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup, i.e. evaluate
@@ -412,16 +409,9 @@
 	 * which is OK as long as the filesystem is exported.
 	 */
 	if (PUBLIC_FH2(fhp)) {
-		struct exportinfo *new;
-
 		publicfh_flag = TRUE;
-		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &new,
+		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 		    &sec);
-
-		if (error == 0) {
-			exi_rele(exi);
-			exi = new;
-		}
 	} else {
 		/*
 		 * Do a normal single component lookup.
@@ -462,10 +452,13 @@
 	VN_RELE(dvp);
 
 	/*
-	 * The passed argument exportinfo is released by the
-	 * caller, comon_dispatch
+	 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
+	 * and have obtained a new exportinfo in exi which needs to be
+	 * released. Note the the original exportinfo pointed to by exi
+	 * will be released by the caller, comon_dispatch.
 	 */
-	exi_rele(exi);
+	if (publicfh_flag && exi != NULL)
+		exi_rele(exi);
 
 	/*
 	 * If it's public fh, no 0x81, and client's flavor is