changeset 9871:6f02df7ca581

6746299 assertion !vn_ismntpt(vp) fail in snv_98 6833224 TX NFS client file access returns EACCES randomly for non-ADMIN_LOW labeled resources
author Jarrett Lu <Jarrett.Lu@Sun.COM>
date Mon, 15 Jun 2009 15:18:04 -0700
parents b2e907fa2ec2
children bb47b7225612
files usr/src/uts/common/fs/nfs/nfs3_srv.c usr/src/uts/common/fs/nfs/nfs4_srv.c usr/src/uts/common/fs/nfs/nfs_server.c usr/src/uts/common/fs/nfs/nfs_subr.c usr/src/uts/common/nfs/nfs.h usr/src/uts/common/os/tlabel.c usr/src/uts/common/sys/tsol/label.h
diffstat 7 files changed, 145 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c	Mon Jun 15 15:18:04 2009 -0700
@@ -187,7 +187,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -508,7 +509,7 @@
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, dvp,
-			    DOMINANCE_CHECK)) {
+			    DOMINANCE_CHECK, exi)) {
 				if (publicfh_flag && exi != NULL)
 					exi_rele(exi);
 				VN_RELE(vp);
@@ -674,9 +675,9 @@
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if ((equal_label = do_rfs_label_check(clabel, vp,
-			    EQUALITY_CHECK)) == B_FALSE) {
+			    EQUALITY_CHECK, exi)) == B_FALSE) {
 				dominant_label = do_rfs_label_check(clabel,
-				    vp, DOMINANCE_CHECK);
+				    vp, DOMINANCE_CHECK, exi);
 			} else
 				dominant_label = B_TRUE;
 			admin_low_client = B_FALSE;
@@ -834,7 +835,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -980,7 +982,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -1282,7 +1285,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -1572,7 +1576,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -1957,7 +1962,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -2137,7 +2143,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -2344,7 +2351,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -2572,7 +2580,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -2731,7 +2740,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -2854,7 +2864,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -2927,7 +2938,8 @@
 
 	if (is_system_labeled()) {
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto err1;
 			}
@@ -3131,7 +3143,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -3180,7 +3193,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -3332,7 +3346,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -3619,7 +3634,8 @@
 		    struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -3990,7 +4006,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -4060,7 +4077,6 @@
 	return (&args->fsroot);
 }
 
-/* ARGSUSED */
 void
 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
 	struct svc_req *req, cred_t *cr)
@@ -4095,7 +4111,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_STALE;
 				vattr_to_post_op_attr(NULL,
 				    &resp->resfail.obj_attributes);
@@ -4194,7 +4211,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
@@ -4329,7 +4347,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    exi)) {
 				resp->status = NFS3ERR_ACCES;
 				goto out1;
 			}
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c	Mon Jun 15 15:18:04 2009 -0700
@@ -1301,7 +1301,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if ((tslabel = nfs_getflabel(vp)) == NULL) {
+			if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) {
 				*cs->statusp = resp->status = puterrno4(EACCES);
 				goto out;
 			}
@@ -2774,7 +2774,8 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    cs->exi)) {
 				error = EACCES;
 				goto err_out;
 			}
@@ -3353,23 +3354,6 @@
 		goto out;
 	}
 
-	if (is_system_labeled()) {
-		bslabel_t *clabel;
-
-		ASSERT(req->rq_label != NULL);
-		clabel = req->rq_label;
-		DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
-		    "got client label from request(1)",
-		    struct svc_req *, req);
-		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
-				*cs->statusp = resp->status =
-				    NFS4ERR_SERVERFAULT;
-				return;
-			}
-		}
-	}
-
 	error = makefh4(&cs->fh, vp, exi_public);
 	if (error != 0) {
 		*cs->statusp = resp->status = puterrno4(error);
@@ -3399,6 +3383,24 @@
 		cs->exi = exi_public;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel;
+
+		ASSERT(req->rq_label != NULL);
+		clabel = req->rq_label;
+		DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
+		    "got client label from request(1)",
+		    struct svc_req *, req);
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
+			    cs->exi)) {
+				*cs->statusp = resp->status =
+				    NFS4ERR_SERVERFAULT;
+				goto out;
+			}
+		}
+	}
+
 	VN_HOLD(vp);
 	cs->vp = vp;
 
@@ -4109,7 +4111,8 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
+			    cs->exi)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				if (name != nm)
 					kmem_free(name, MAXPATHLEN + 1);
@@ -4416,7 +4419,7 @@
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, ndvp,
-			    EQUALITY_CHECK)) {
+			    EQUALITY_CHECK, cs->exi)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				goto err_out;
 			}
@@ -5304,7 +5307,7 @@
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, cs->vp,
-			    EQUALITY_CHECK)) {
+			    EQUALITY_CHECK, cs->exi)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				goto out;
 			}
@@ -6229,7 +6232,8 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
+			    cs->exi)) {
 				return (NFS4ERR_ACCESS);
 			}
 		}
--- a/usr/src/uts/common/fs/nfs/nfs_server.c	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c	Mon Jun 15 15:18:04 2009 -0700
@@ -87,6 +87,8 @@
 #include <sys/cladm.h>
 #include <sys/clconf.h>
 
+#include <sys/tsol/label.h>
+
 #define	MAXHOST 32
 const char *kinet_ntop6(uchar_t *, char *, size_t);
 
@@ -3118,3 +3120,73 @@
 	if (rfs4_dss_numnewpaths > 0)
 		kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *));
 }
+
+/*
+ * Used by NFSv3 and NFSv4 server to query label of
+ * a pathname component during lookup/access ops.
+ */
+ts_label_t *
+nfs_getflabel(vnode_t *vp, struct exportinfo *exi)
+{
+	zone_t *zone;
+	ts_label_t *zone_label;
+	char *path;
+
+	mutex_enter(&vp->v_lock);
+	if (vp->v_path != NULL) {
+		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
+		mutex_exit(&vp->v_lock);
+	} else {
+		/*
+		 * v_path not cached. Fall back on pathname of exported
+		 * file system as we rely on pathname from which we can
+		 * derive a label. The exported file system portion of
+		 * path is sufficient to obtain a label.
+		 */
+		path = exi->exi_export.ex_path;
+		if (path == NULL) {
+			mutex_exit(&vp->v_lock);
+			return (NULL);
+		}
+		zone = zone_find_by_any_path(path, B_FALSE);
+		mutex_exit(&vp->v_lock);
+	}
+	/*
+	 * Caller has verified that the file is either
+	 * exported or visible. So if the path falls in
+	 * global zone, admin_low is returned; otherwise
+	 * the zone's label is returned.
+	 */
+	zone_label = zone->zone_slabel;
+	label_hold(zone_label);
+	zone_rele(zone);
+	return (zone_label);
+}
+
+/*
+ * TX NFS routine used by NFSv3 and NFSv4 to do label check
+ * on client label and server's file object lable.
+ */
+boolean_t
+do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag,
+    struct exportinfo *exi)
+{
+	bslabel_t *slabel;
+	ts_label_t *tslabel;
+	boolean_t result;
+
+	if ((tslabel = nfs_getflabel(vp, exi)) == NULL) {
+		return (B_FALSE);
+	}
+	slabel = label2bslabel(tslabel);
+	DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *,
+	    "comparing server's file label(1) with client label(2) (vp(3))",
+	    bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
+
+	if (flag == EQUALITY_CHECK)
+		result = blequal(clabel, slabel);
+	else
+		result = bldominates(clabel, slabel);
+	label_rele(tslabel);
+	return (result);
+}
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c	Mon Jun 15 15:18:04 2009 -0700
@@ -5125,33 +5125,6 @@
 }
 
 /*
- * TX NFS routine used by NFSv3 and NFSv4 to do label check
- * on client label and server's file object lable.
- */
-boolean_t
-do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag)
-{
-	bslabel_t *slabel;
-	ts_label_t *tslabel;
-	boolean_t result;
-
-	if ((tslabel = nfs_getflabel(vp)) == NULL) {
-		return (B_FALSE);
-	}
-	slabel = label2bslabel(tslabel);
-	DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *,
-	    "comparing server's file label(1) with client label(2) (vp(3))",
-	    bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
-
-	if (flag == EQUALITY_CHECK)
-		result = blequal(clabel, slabel);
-	else
-		result = bldominates(clabel, slabel);
-	label_rele(tslabel);
-	return (result);
-}
-
-/*
  * See if xattr directory to see if it has any generic user attributes
  */
 int
--- a/usr/src/uts/common/nfs/nfs.h	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/nfs/nfs.h	Mon Jun 15 15:18:04 2009 -0700
@@ -2318,6 +2318,9 @@
 
 extern int do_xattr_exists_check(vnode_t *, ulong_t *, cred_t *);
 
+extern ts_label_t	*nfs_getflabel(vnode_t *, struct exportinfo *);
+extern boolean_t	do_rfs_label_check(bslabel_t *, vnode_t *, int,
+			    struct exportinfo *);
 #endif	/* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/os/tlabel.c	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/os/tlabel.c	Mon Jun 15 15:18:04 2009 -0700
@@ -44,7 +44,6 @@
 #include <nfs/nfs.h>
 #include <nfs/nfs4.h>
 #include <nfs/nfs_clnt.h>
-#include <sys/dnlc.h>
 
 
 int sys_labeling = 0;			/* the default is "off" */
@@ -540,54 +539,3 @@
 	else
 		return (0);
 }
-
-/*
- * Used by NFSv3 and NFSv4 server to query label of
- * a pathname component during lookup/access ops.
- */
-ts_label_t *
-nfs_getflabel(vnode_t *vp)
-{
-	zone_t *zone;
-	ts_label_t *zone_label;
-	char path[MAXNAMELEN];
-	vnode_t *pvp, *tvp;
-
-	mutex_enter(&vp->v_lock);
-	/*
-	 * mount traverse has been done by caller
-	 * before calling this routine.
-	 */
-	ASSERT(!vn_ismntpt(vp));
-	if (vp->v_path != NULL) {
-		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
-		mutex_exit(&vp->v_lock);
-	} else {
-		/*
-		 * v_path not cached. Since we rely on path
-		 * of an obj to get its label, we need to get
-		 * path corresponding to the parent vnode.
-		 */
-		tvp = vp;
-		do {
-			mutex_exit(&tvp->v_lock);
-			if ((pvp = dnlc_reverse_lookup(tvp, path,
-			    sizeof (path))) == NULL)
-				return (NULL);
-			mutex_enter(&pvp->v_lock);
-			tvp = pvp;
-		} while (pvp->v_path == NULL);
-		zone = zone_find_by_any_path(pvp->v_path, B_FALSE);
-		mutex_exit(&pvp->v_lock);
-	}
-	/*
-	 * Caller has verified that the file is either
-	 * exported or visible. So if the path falls in
-	 * global zone, admin_low is returned; otherwise
-	 * the zone's label is returned.
-	 */
-	zone_label = zone->zone_slabel;
-	label_hold(zone_label);
-	zone_rele(zone);
-	return (zone_label);
-}
--- a/usr/src/uts/common/sys/tsol/label.h	Mon Jun 15 13:26:03 2009 -0700
+++ b/usr/src/uts/common/sys/tsol/label.h	Mon Jun 15 15:18:04 2009 -0700
@@ -130,8 +130,6 @@
 extern int		fgetlabel(int, m_label_t *);
 extern int		_blinrange(const m_label_t *, const brange_t *);
 extern int		blinlset(const m_label_t *, const blset_t);
-extern ts_label_t	*nfs_getflabel(vnode_t *);
-extern boolean_t	do_rfs_label_check(bslabel_t *, vnode_t *, int);
 
 /*
  * The use of '!!' here prevents users from referencing this function-like