changeset 4971:b721af044177

6560317 TX NFS server needs to support NFSv3 clients 6596123 TX NFSv4 should not allow a read-up mount via WebNFS
author jarrett
date Fri, 31 Aug 2007 10:09:18 -0700
parents 1cbc767b641b
children b6da5df14183
files usr/src/cmd/fs.d/nfs/mountd/Makefile usr/src/cmd/fs.d/nfs/mountd/mountd.c 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_srv.c usr/src/uts/common/fs/nfs/nfs_subr.c usr/src/uts/common/inet/udp/udp.c usr/src/uts/common/os/tlabel.c usr/src/uts/common/sys/tsol/label.h
diffstat 9 files changed, 626 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/nfs/mountd/Makefile	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/mountd/Makefile	Fri Aug 31 10:09:18 2007 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,7 +36,7 @@
 		nfsauth_xdr.o exportlist.o hashset.o
 OBJS	  = 	$(LOCAL) $(COMMON)
 SRCS	  =	$(LOCAL:%.o=%.c) $(FSLIBSRC) ../lib/nfs_sec.c ../lib/sharetab.c
-LDLIBS	 +=	-lrpcsvc -lnsl -lbsm -lsocket -ldoor
+LDLIBS	 +=	-lrpcsvc -lnsl -lbsm -lsocket -ldoor -ltsnet -ltsol
 CPPFLAGS +=	-D_REENTRANT
 
 $(TYPEPROG):	$(OBJS)
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Fri Aug 31 10:09:18 2007 -0700
@@ -74,6 +74,9 @@
 #include <sharefs/sharetab.h>
 #include "../lib/sharetab.h"
 #include "mountd.h"
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+#include <libtsnet.h>
 
 struct sh_list *share_list;
 
@@ -101,6 +104,7 @@
 static int netmatch(struct netbuf *, char *);
 static void sigexit(int);
 static int newopts(char *);
+static tsol_tpent_t *get_client_template(struct sockaddr *);
 
 static int verbose;
 static int rejecting;
@@ -826,6 +830,7 @@
 	int flavor_list[MAX_FLAVORS];
 	int flavor_count;
 	struct netbuf *nb;
+	ucred_t	*uc = NULL;
 
 	transp = rqstp->rq_xprt;
 	version = rqstp->rq_vers;
@@ -862,16 +867,19 @@
 	}
 
 	/*
-	 * Trusted Extension doesn't support older versions of nfs(v2, v3).
-	 * To prevent circumventing TX label policy via using an older
-	 * version of nfs client, reject the mount request and log an
-	 * error.
+	 * Trusted Extension doesn't support nfsv2. nfsv2 client
+	 * uses MOUNT protocol v1 and v2. To prevent circumventing
+	 * TX label policy via using nfsv2 client, reject a mount
+	 * request with version less than 3 and log an error.
 	 */
 	if (is_system_labeled()) {
-		syslog(LOG_ERR,
-		    "mount rejected: Solaris TX only supports nfs4 clients");
-		error = EACCES;
-		goto reply;
+		if (version < 3) {
+			if (verbose)
+				syslog(LOG_ERR,
+				    "Rejected mount: TX doesn't support NFSv2");
+			error = EACCES;
+			goto reply;
+		}
 	}
 
 	/*
@@ -916,6 +924,74 @@
 	}
 
 	/*
+	 * Check MAC policy here. The server side policy should be
+	 * consistent with client side mount policy, i.e.
+	 * - we disallow an admin_low unlabeled client to mount
+	 * - we disallow mount from a lower labeled client.
+	 */
+	if (is_system_labeled()) {
+		m_label_t *clabel = NULL;
+		m_label_t *slabel = NULL;
+		m_label_t admin_low;
+
+		if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
+			syslog(LOG_ERR,
+			    "mount request: Failed to get caller's ucred : %m");
+			error = EACCES;
+			goto reply;
+		}
+		if ((clabel = ucred_getlabel(uc)) == NULL) {
+			syslog(LOG_ERR,
+			    "mount request: can't get client label from ucred");
+			error = EACCES;
+			goto reply;
+		}
+
+		bsllow(&admin_low);
+		if (blequal(&admin_low, clabel)) {
+			struct sockaddr *ca;
+			tsol_tpent_t	*tp;
+
+			ca = (struct sockaddr *)(void *)svc_getrpccaller(
+			    rqstp->rq_xprt)->buf;
+			if (ca == NULL) {
+				error = EACCES;
+				goto reply;
+			}
+			/*
+			 * get trusted network template associated
+			 * with the client.
+			 */
+			tp = get_client_template(ca);
+			if (tp == NULL || tp->host_type != SUN_CIPSO) {
+				if (tp != NULL)
+					tsol_freetpent(tp);
+				error = EACCES;
+				goto reply;
+			}
+			tsol_freetpent(tp);
+		} else {
+			if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
+				error = EACCES;
+				goto reply;
+			}
+
+			if (getlabel(rpath, slabel) != 0) {
+				m_label_free(slabel);
+				error = EACCES;
+				goto reply;
+			}
+
+			if (!bldominates(clabel, slabel)) {
+				m_label_free(slabel);
+				error = EACCES;
+				goto reply;
+			}
+			m_label_free(slabel);
+		}
+	}
+
+	/*
 	 * Now get the filehandle.
 	 *
 	 * NFS V2 clients get a 32 byte filehandle.
@@ -945,6 +1021,8 @@
 	}
 
 reply:
+	if (uc != NULL)
+		ucred_free(uc);
 	switch (version) {
 	case MOUNTVERS:
 	case MOUNTVERS_POSIX:
@@ -2139,3 +2217,44 @@
 		_exit(0);
 	_exit(1);
 }
+
+static tsol_tpent_t *
+get_client_template(struct sockaddr *sock)
+{
+	in_addr_t	v4client;
+	in6_addr_t	v6client;
+	char		v4_addr[INET_ADDRSTRLEN];
+	char		v6_addr[INET6_ADDRSTRLEN];
+	tsol_rhent_t	*rh;
+	tsol_tpent_t	*tp;
+
+	switch (sock->sa_family) {
+	case AF_INET:
+		v4client = ((struct sockaddr_in *)(void *)sock)->
+		    sin_addr.s_addr;
+		if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
+		    NULL)
+			return (NULL);
+		rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
+		if (rh == NULL)
+			return (NULL);
+		tp = tsol_gettpbyname(rh->rh_template);
+		tsol_freerhent(rh);
+		return (tp);
+		break;
+	case AF_INET6:
+		v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
+		if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
+		    NULL)
+			return (NULL);
+		rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
+		if (rh == NULL)
+			return (NULL);
+		tp = tsol_gettpbyname(rh->rh_template);
+		tsol_freerhent(rh);
+		return (tp);
+		break;
+	default:
+		return (NULL);
+	}
+}
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c	Fri Aug 31 10:09:18 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,6 +47,7 @@
 #include <sys/flock.h>
 #include <sys/nbmlock.h>
 #include <sys/policy.h>
+#include <sys/sdt.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -57,6 +58,12 @@
 
 #include <sys/strsubr.h>
 
+#include <sys/tsol/label.h>
+#include <sys/tsol/tndb.h>
+
+#include <inet/ip.h>
+#include <inet/ip6.h>
+
 /*
  * These are the interface routines for the server side of the
  * Network File System.  See the NFS version 3 protocol specification
@@ -148,6 +155,21 @@
 	if (error)
 		goto out;
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__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, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	/*
 	 * We need to specially handle size changes because of
 	 * possible conflicting NBMAND locks. Get into critical
@@ -380,12 +402,64 @@
 		error = rfs_publicfh_mclookup(args->what.name, dvp, cr, &vp,
 					&exi, &sec);
 		if (error && exi != NULL)
-			exi_rele(exi);  /* See the comment below */
+			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.
+		 */
+		if (is_system_labeled() && error == 0) {
+			struct sockaddr *ca;
+			int		addr_type;
+			void		*ipaddr;
+			tsol_tpc_t	*tp;
+
+			ca = (struct sockaddr *)svc_getrpccaller(
+			    req->rq_xprt)->buf;
+			if (ca->sa_family == AF_INET) {
+				addr_type = IPV4_VERSION;
+				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
+			} else if (ca->sa_family == AF_INET6) {
+				addr_type = IPV6_VERSION;
+				ipaddr = &((struct sockaddr_in6 *)
+				    ca)->sin6_addr;
+			}
+			tp = find_tpc(ipaddr, addr_type, B_FALSE);
+			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;
+			}
+			if (tp != NULL)
+				TPC_RELE(tp);
+		}
 	} else {
 		error = VOP_LOOKUP(dvp, args->what.name, &vp,
 				NULL, 0, NULL, cr);
 	}
 
+	if (is_system_labeled() && error == 0) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__oplookup__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, dvp,
+			    DOMINANCE_CHECK)) {
+				if (publicfh_flag && exi != NULL)
+					exi_rele(exi);
+				VN_RELE(vp);
+				resp->status = NFS3ERR_ACCES;
+				error = 1;
+			}
+		}
+	}
+
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
 		dva.va_mask = AT_ALL;
@@ -481,6 +555,9 @@
 	struct vattr *vap;
 	struct vattr va;
 	int checkwriteperm;
+	boolean_t dominant_label = B_FALSE;
+	boolean_t equal_label = B_FALSE;
+	boolean_t admin_low_client;
 
 	vap = NULL;
 
@@ -521,12 +598,33 @@
 
 	resp->resok.access = 0;
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
+		    "got client label from request(1)", struct svc_req *, req);
+
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if ((equal_label = do_rfs_label_check(clabel, vp,
+			    EQUALITY_CHECK)) == B_FALSE) {
+				dominant_label = do_rfs_label_check(clabel,
+				    vp, DOMINANCE_CHECK);
+			} else
+				dominant_label = B_TRUE;
+			admin_low_client = B_FALSE;
+		} else
+			admin_low_client = B_TRUE;
+	}
+
 	if (args->access & ACCESS3_READ) {
 		error = VOP_ACCESS(vp, VREAD, 0, cr);
 		if (error) {
 			if (curthread->t_flag & T_WOULDBLOCK)
 				goto out;
-		} else if (!MANDLOCK(vp, va.va_mode))
+		} else if (!MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client ||
+		    dominant_label))
 			resp->resok.access |= ACCESS3_READ;
 	}
 	if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
@@ -534,7 +632,8 @@
 		if (error) {
 			if (curthread->t_flag & T_WOULDBLOCK)
 				goto out;
-		} else
+		} else if (!is_system_labeled() || admin_low_client ||
+		    dominant_label)
 			resp->resok.access |= ACCESS3_LOOKUP;
 	}
 	if (checkwriteperm &&
@@ -543,7 +642,8 @@
 		if (error) {
 			if (curthread->t_flag & T_WOULDBLOCK)
 				goto out;
-		} else if (!MANDLOCK(vp, va.va_mode)) {
+		} else if (!MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client || equal_label)) {
 			resp->resok.access |=
 			    (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
 		}
@@ -554,7 +654,8 @@
 		if (error) {
 			if (curthread->t_flag & T_WOULDBLOCK)
 				goto out;
-		} else
+		} else if (!is_system_labeled() || admin_low_client ||
+		    equal_label)
 			resp->resok.access |= ACCESS3_DELETE;
 	}
 	if (args->access & ACCESS3_EXECUTE) {
@@ -562,7 +663,9 @@
 		if (error) {
 			if (curthread->t_flag & T_WOULDBLOCK)
 				goto out;
-		} else if (!MANDLOCK(vp, va.va_mode))
+		} else if (!MANDLOCK(vp, va.va_mode) &&
+		    (!is_system_labeled() || admin_low_client ||
+		    dominant_label))
 			resp->resok.access |= ACCESS3_EXECUTE;
 	}
 
@@ -644,6 +747,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
 
 	iov.iov_base = data;
@@ -745,6 +863,21 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opread__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	/*
 	 * Check to see if the v4 side of the server has delegated
 	 * this file.  If so, then we return JUKEBOX to allow the
@@ -995,6 +1128,21 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opwrite__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, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	/*
 	 * Check to see if the v4 side of the server has delegated
 	 * this file.  If so, then we return JUKEBOX to allow the
@@ -1251,6 +1399,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opcreate__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, dvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	if (args->how.mode == EXCLUSIVE) {
 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
 		va.va_type = VREG;
@@ -1591,6 +1754,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__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, dvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	error = sattr3_to_vattr(&args->attributes, &va);
 	if (error)
 		goto out;
@@ -1732,6 +1910,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__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, dvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
 	if (error)
 		goto out;
@@ -1890,6 +2083,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opmknod__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, dvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	switch (args->what.type) {
 	case NF3CHR:
 	case NF3BLK:
@@ -2077,6 +2285,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opremove__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, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	/*
 	 * Check for a conflict with a non-blocking mandatory share
 	 * reservation and V4 delegations
@@ -2201,6 +2424,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__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, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	error = VOP_RMDIR(vp, args->object.name, rootdir, cr);
 
 #ifdef DEBUG
@@ -2275,6 +2513,7 @@
 	nfs_fh3 *fh3;
 	struct exportinfo *to_exi;
 	vnode_t *srcvp = NULL;
+	bslabel_t *clabel;
 
 	fbvap = NULL;
 	favap = NULL;
@@ -2288,6 +2527,20 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		clabel = req->rq_label;
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__oprename__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, fvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 #ifdef DEBUG
 	if (rfs3_do_pre_op_attr) {
 		fbva.va_mask = AT_ALL;
@@ -2352,6 +2605,15 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		if (!blequal(&l_admin_low->tsl_label, clabel)) {
+			if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	/*
 	 * Check for a conflict with a non-blocking mandatory share
 	 * reservation or V4 delegations.
@@ -2486,6 +2748,7 @@
 	struct vattr ava;
 	nfs_fh3	*fh3;
 	struct exportinfo *to_exi;
+	bslabel_t *clabel;
 
 	vap = NULL;
 	bvap = NULL;
@@ -2522,6 +2785,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__oplink__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	dvp = nfs3_fhtovp(&args->link.dir, exi);
 	if (dvp == NULL) {
 		error = ESTALE;
@@ -2559,6 +2837,18 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__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, dvp, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	error = VOP_LINK(dvp, vp, args->link.name, cr);
 
 #ifdef DEBUG
@@ -2671,6 +2961,21 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
 #ifdef DEBUG
@@ -2915,6 +3220,22 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
 #ifdef DEBUG
@@ -3236,6 +3557,21 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	error = VFS_STATVFS(vp->v_vfsp, &sb);
 
 #ifdef DEBUG
@@ -3250,6 +3586,7 @@
 #endif
 
 	VN_RELE(vp);
+	vp = NULL;
 
 	if (error)
 		goto out;
@@ -3280,6 +3617,9 @@
 		resp->status = NFS3ERR_JUKEBOX;
 	} else
 		resp->status = puterrno3(error);
+out1:
+	if (vp != NULL)
+		VN_RELE(vp);
 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 }
 
@@ -3313,6 +3653,23 @@
 		return;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__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)) {
+				resp->status = NFS3ERR_STALE;
+				vattr_to_post_op_attr(NULL,
+				    &resp->resfail.obj_attributes);
+				return;
+			}
+		}
+	}
+
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
 		va.va_mask = AT_ALL;
@@ -3380,6 +3737,21 @@
 		goto out;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__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)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
 		va.va_mask = AT_ALL;
@@ -3431,6 +3803,7 @@
 		resp->status = NFS3ERR_JUKEBOX;
 	} else
 		resp->status = puterrno3(error);
+out1:
 	if (vp != NULL)
 		VN_RELE(vp);
 	vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
@@ -3492,6 +3865,21 @@
 		goto out1;
 	}
 
+	if (is_system_labeled()) {
+		bslabel_t *clabel = req->rq_label;
+
+		ASSERT(clabel != NULL);
+		DTRACE_PROBE2(tx__rfs3__log__info__opcommit__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, EQUALITY_CHECK)) {
+				resp->status = NFS3ERR_ACCES;
+				goto out1;
+			}
+		}
+	}
+
 	if (crgetuid(cr) != bva.va_uid &&
 	    (error = VOP_ACCESS(vp, VWRITE, 0, cr)))
 		goto out;
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c	Fri Aug 31 10:09:18 2007 -0700
@@ -140,12 +140,6 @@
 #define	DIRENT64_TO_DIRCOUNT(dp) \
 	(3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
 
-/*
- * types of label comparison
- */
-#define	EQUALITY_CHECK	0
-#define	DOMINANCE_CHECK	1
-
 time_t rfs4_start_time;			/* Initialized in rfs4_srvrinit */
 
 static sysid_t lockt_sysid;		/* dummy sysid for all LOCKT calls */
@@ -1202,32 +1196,6 @@
 	resp->SECINFO4resok_val = NULL;
 }
 
-/*
- * do label check on client label and server's file lable.
- */
-static boolean_t
-do_rfs4_label_check(bslabel_t *clabel, vnode_t *vp, int flag)
-{
-	bslabel_t *slabel;
-	ts_label_t *tslabel;
-	boolean_t result;
-
-	if ((tslabel = nfs4_getflabel(vp)) == NULL) {
-		return (B_FALSE);
-	}
-	slabel = label2bslabel(tslabel);
-	DTRACE_PROBE4(tx__rfs4__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);
-}
-
 /* ARGSUSED */
 static void
 rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
@@ -1294,7 +1262,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if ((tslabel = nfs4_getflabel(vp)) == NULL) {
+			if ((tslabel = nfs_getflabel(vp)) == NULL) {
 				*cs->statusp = resp->status = puterrno4(EACCES);
 				return;
 			}
@@ -2657,7 +2625,7 @@
 		    "got client label from request(1)", struct svc_req *, req);
 
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs4_label_check(clabel, vp, DOMINANCE_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) {
 				error = EACCES;
 				goto err_out;
 			}
@@ -2686,9 +2654,12 @@
 			if (tp == NULL || tp->tpc_tp.tp_doi !=
 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 			    SUN_CIPSO) {
+				if (tp != NULL)
+					TPC_RELE(tp);
 				error = EACCES;
 				goto err_out;
 			}
+			TPC_RELE(tp);
 		}
 	}
 
@@ -3159,6 +3130,23 @@
 		return;
 	}
 
+	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);
@@ -3830,7 +3818,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs4_label_check(clabel, vp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				kmem_free(nm, len);
 				if (in_crit)
@@ -4085,7 +4073,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs4_label_check(clabel, ndvp,
+			if (!do_rfs_label_check(clabel, ndvp,
 			    EQUALITY_CHECK)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				return;
@@ -4936,7 +4924,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs4_label_check(clabel, cs->vp,
+			if (!do_rfs_label_check(clabel, cs->vp,
 			    EQUALITY_CHECK)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
 				return;
@@ -5813,7 +5801,7 @@
 		    "got client label from request(1)",
 		    struct svc_req *, req);
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
-			if (!do_rfs4_label_check(clabel, dvp, EQUALITY_CHECK)) {
+			if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) {
 				return (NFS4ERR_ACCESS);
 			}
 		}
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c	Fri Aug 31 10:09:18 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -370,6 +370,18 @@
 		"rfs_lookup_start:");
 
 	/*
+	 * Trusted Extension doesn't support NFSv2. MOUNT
+	 * will reject v2 clients. Need to prevent v2 client
+	 * access via WebNFS here.
+	 */
+	if (is_system_labeled() && req->rq_vers == 2) {
+		dr->dr_status = NFSERR_ACCES;
+		TRACE_1(TR_FAC_NFS, TR_RFS_LOOKUP_END,
+			"rfs_lookup_end:(%S)", "access");
+		return;
+	}
+
+	/*
 	 * Disallow NULL paths
 	 */
 	if (da->da_name == NULL || *da->da_name == '\0') {
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c	Fri Aug 31 10:09:18 2007 -0700
@@ -62,6 +62,7 @@
 #include <sys/list.h>
 #include <sys/tsol/tnet.h>
 #include <sys/priv.h>
+#include <sys/sdt.h>
 
 #include <inet/ip6.h>
 
@@ -76,6 +77,8 @@
 #include <nfs/rnode.h>
 #include <nfs/nfs_acl.h>
 
+#include <sys/tsol/label.h>
+
 /*
  * The hash queues for the access to active and cached rnodes
  * are organized as doubly linked lists.  A reader/writer lock
@@ -5128,3 +5131,30 @@
 	mutex_exit(&curproc->p_splock);
 	return (rv);
 }
+
+/*
+ * 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);
+}
--- a/usr/src/uts/common/inet/udp/udp.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/inet/udp/udp.c	Fri Aug 31 10:09:18 2007 -0700
@@ -6422,9 +6422,11 @@
 	ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA);
 
 	/*
-	 * Check if our saved options are valid; update if not
+	 * Check if our saved options are valid; update if not.
 	 * TSOL Note: Since we are not in WRITER mode, UDP packets
-	 * to different destination may require different labels.
+	 * to different destination may require different labels,
+	 * or worse, UDP packets to same IP address may require
+	 * different labels due to use of shared all-zones address.
 	 * We use conn_lock to ensure that lastdst, ip_snd_options,
 	 * and ip_snd_options_len are consistent for the current
 	 * destination and are updated atomically.
@@ -6442,8 +6444,14 @@
 			*error = ECONNREFUSED;
 			goto done;
 		}
+		/*
+		 * update label option for this UDP socket if
+		 * - the destination has changed, or
+		 * - the UDP socket is MLP
+		 */
 		if ((!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6lastdst) ||
-		    V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst) &&
+		    V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst ||
+		    connp->conn_mlp_type != mlptSingle) &&
 		    (*error = udp_update_label(q, mp, v4dst)) != 0) {
 			mutex_exit(&connp->conn_lock);
 			goto done;
@@ -7350,7 +7358,9 @@
 	 * avoid blowing up our stack here.
 	 *
 	 * TSOL Note: Since we are not in WRITER mode, UDP packets
-	 * to different destination may require different labels.
+	 * to different destination may require different labels,
+	 * or worse, UDP packets to same IP address may require
+	 * different labels due to use of shared all-zones address.
 	 * We use conn_lock to ensure that lastdst, sticky ipp_hopopts,
 	 * and sticky ipp_hopoptslen are consistent for the current
 	 * destination and are updated atomically.
@@ -7368,8 +7378,14 @@
 			mutex_exit(&connp->conn_lock);
 			goto done;
 		}
+		/*
+		 * update label option for this UDP socket if
+		 * - the destination has changed, or
+		 * - the UDP socket is MLP
+		 */
 		if ((opt_present ||
-		    !IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst)) &&
+		    !IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst) ||
+		    connp->conn_mlp_type != mlptSingle) &&
 		    (*error = udp_update_label_v6(q, mp, &ip6_dst)) != 0) {
 			mutex_exit(&connp->conn_lock);
 			goto done;
--- a/usr/src/uts/common/os/tlabel.c	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/os/tlabel.c	Fri Aug 31 10:09:18 2007 -0700
@@ -528,11 +528,11 @@
 }
 
 /*
- * Used by NFSv4 to query label of a pathname
- * component during lookup/access ops.
+ * Used by NFSv3 and NFSv4 server to query label of
+ * a pathname component during lookup/access ops.
  */
 ts_label_t *
-nfs4_getflabel(vnode_t *vp)
+nfs_getflabel(vnode_t *vp)
 {
 	zone_t *zone;
 	ts_label_t *zone_label;
--- a/usr/src/uts/common/sys/tsol/label.h	Fri Aug 31 09:25:38 2007 -0700
+++ b/usr/src/uts/common/sys/tsol/label.h	Fri Aug 31 10:09:18 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,6 +39,12 @@
 extern "C" {
 #endif
 
+/*
+ * types of label comparison
+ */
+#define	EQUALITY_CHECK	0
+#define	DOMINANCE_CHECK	1
+
 /* Binary Label Structure Definitions */
 
 typedef	struct _mac_label_impl	m_label_t;
@@ -123,7 +129,8 @@
 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	*nfs4_getflabel(vnode_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