xref: /titanic_54/usr/src/uts/common/os/tlabel.c (revision 5f9878b0212a5bc5924a85d227160bf7f43712f1)
145916cd2Sjpk /*
245916cd2Sjpk  * CDDL HEADER START
345916cd2Sjpk  *
445916cd2Sjpk  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
745916cd2Sjpk  *
845916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
945916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
1045916cd2Sjpk  * See the License for the specific language governing permissions
1145916cd2Sjpk  * and limitations under the License.
1245916cd2Sjpk  *
1345916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
1445916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1545916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
1645916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
1745916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
1845916cd2Sjpk  *
1945916cd2Sjpk  * CDDL HEADER END
2045916cd2Sjpk  */
2145916cd2Sjpk /*
22*5f9878b0Sken Powell - Sun Microsystem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2345916cd2Sjpk  * Use is subject to license terms.
2445916cd2Sjpk  */
2545916cd2Sjpk 
2645916cd2Sjpk #include <sys/types.h>
2745916cd2Sjpk #include <sys/param.h>
2845916cd2Sjpk #include <sys/cmn_err.h>
2945916cd2Sjpk #include <sys/systm.h>
3045916cd2Sjpk #include <sys/cred.h>
3145916cd2Sjpk #include <sys/modctl.h>
3245916cd2Sjpk #include <sys/vfs.h>
3345916cd2Sjpk #include <sys/vnode.h>
3445916cd2Sjpk #include <sys/tiuser.h>
3545916cd2Sjpk #include <sys/kmem.h>
3645916cd2Sjpk #include <sys/pathname.h>
3745916cd2Sjpk #include <sys/zone.h>
3845916cd2Sjpk #include <sys/tsol/label.h>
3945916cd2Sjpk #include <sys/tsol/tnet.h>
4045916cd2Sjpk #include <sys/fs/lofs_node.h>
4145916cd2Sjpk #include <inet/ip6.h>
4245916cd2Sjpk #include <rpc/auth.h>
4345916cd2Sjpk #include <rpc/clnt.h>
4445916cd2Sjpk #include <nfs/nfs.h>
4545916cd2Sjpk #include <nfs/nfs4.h>
4645916cd2Sjpk #include <nfs/nfs_clnt.h>
4745916cd2Sjpk #include <sys/dnlc.h>
4845916cd2Sjpk 
4945916cd2Sjpk 
50f875b4ebSrica int sys_labeling = 0;			/* the default is "off" */
5145916cd2Sjpk 
5245916cd2Sjpk static kmem_cache_t *tslabel_cache;
5345916cd2Sjpk ts_label_t *l_admin_low;
5445916cd2Sjpk ts_label_t *l_admin_high;
5545916cd2Sjpk 
5645916cd2Sjpk uint32_t default_doi = DEFAULT_DOI;
5745916cd2Sjpk 
5845916cd2Sjpk /*
5945916cd2Sjpk  * Initialize labels infrastructure.
6045916cd2Sjpk  * This is called during startup() time (before vfs_mntroot) by thread_init().
6145916cd2Sjpk  * It has to be called early so that the is_system_labeled() function returns
6245916cd2Sjpk  * the right value when called by the networking code on a diskless boot.
6345916cd2Sjpk  */
6445916cd2Sjpk void
6545916cd2Sjpk label_init(void)
6645916cd2Sjpk {
6745916cd2Sjpk 	bslabel_t label;
6845916cd2Sjpk 
6945916cd2Sjpk 	/*
70f875b4ebSrica 	 * sys_labeling will default to "off" unless it is overridden
71f875b4ebSrica 	 * in /etc/system.
7245916cd2Sjpk 	 */
7345916cd2Sjpk 
7445916cd2Sjpk 	tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t),
7545916cd2Sjpk 	    0, NULL, NULL, NULL, NULL, NULL, 0);
7645916cd2Sjpk 	bsllow(&label);
7745916cd2Sjpk 	l_admin_low = labelalloc(&label, default_doi, KM_SLEEP);
7845916cd2Sjpk 	bslhigh(&label);
7945916cd2Sjpk 	l_admin_high = labelalloc(&label, default_doi, KM_SLEEP);
8045916cd2Sjpk }
8145916cd2Sjpk 
8245916cd2Sjpk /*
8345916cd2Sjpk  * Allocate new ts_label_t.
8445916cd2Sjpk  */
8545916cd2Sjpk ts_label_t *
8645916cd2Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag)
8745916cd2Sjpk {
8845916cd2Sjpk 	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
8945916cd2Sjpk 
9045916cd2Sjpk 	if (lab != NULL) {
9145916cd2Sjpk 		lab->tsl_ref = 1;
9245916cd2Sjpk 		lab->tsl_doi = doi;
93e071b5fbSkp158701 		lab->tsl_flags = 0;
9445916cd2Sjpk 		if (val == NULL)
9545916cd2Sjpk 			bzero(&lab->tsl_label, sizeof (bslabel_t));
9645916cd2Sjpk 		else
9745916cd2Sjpk 			bcopy(val, &lab->tsl_label,  sizeof (bslabel_t));
9845916cd2Sjpk 	}
9945916cd2Sjpk 	return (lab);
10045916cd2Sjpk }
10145916cd2Sjpk 
10245916cd2Sjpk /*
103*5f9878b0Sken Powell - Sun Microsystem  * Duplicate an existing ts_label_t to a new one, with only
104*5f9878b0Sken Powell - Sun Microsystem  * the current reference.
105*5f9878b0Sken Powell - Sun Microsystem  */
106*5f9878b0Sken Powell - Sun Microsystem ts_label_t *
107*5f9878b0Sken Powell - Sun Microsystem labeldup(const ts_label_t *val, int flag)
108*5f9878b0Sken Powell - Sun Microsystem {
109*5f9878b0Sken Powell - Sun Microsystem 	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
110*5f9878b0Sken Powell - Sun Microsystem 
111*5f9878b0Sken Powell - Sun Microsystem 	if (lab != NULL) {
112*5f9878b0Sken Powell - Sun Microsystem 		bcopy(val, lab, sizeof (ts_label_t));
113*5f9878b0Sken Powell - Sun Microsystem 		lab->tsl_ref = 1;
114*5f9878b0Sken Powell - Sun Microsystem 	}
115*5f9878b0Sken Powell - Sun Microsystem 	return (lab);
116*5f9878b0Sken Powell - Sun Microsystem }
117*5f9878b0Sken Powell - Sun Microsystem 
118*5f9878b0Sken Powell - Sun Microsystem /*
11945916cd2Sjpk  * Put a hold on a label structure.
12045916cd2Sjpk  */
12145916cd2Sjpk void
12245916cd2Sjpk label_hold(ts_label_t *lab)
12345916cd2Sjpk {
12445916cd2Sjpk 	atomic_add_32(&lab->tsl_ref, 1);
12545916cd2Sjpk }
12645916cd2Sjpk 
12745916cd2Sjpk /*
12845916cd2Sjpk  * Release previous hold on a label structure.  Free it if refcnt == 0.
12945916cd2Sjpk  */
13045916cd2Sjpk void
13145916cd2Sjpk label_rele(ts_label_t *lab)
13245916cd2Sjpk {
13345916cd2Sjpk 	if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0)
13445916cd2Sjpk 		kmem_cache_free(tslabel_cache, lab);
13545916cd2Sjpk }
13645916cd2Sjpk 
13745916cd2Sjpk bslabel_t *
13845916cd2Sjpk label2bslabel(ts_label_t *lab)
13945916cd2Sjpk {
14045916cd2Sjpk 	return (&lab->tsl_label);
14145916cd2Sjpk }
14245916cd2Sjpk 
14345916cd2Sjpk 
14445916cd2Sjpk uint32_t
14545916cd2Sjpk label2doi(ts_label_t *lab)
14645916cd2Sjpk {
14745916cd2Sjpk 	return (lab->tsl_doi);
14845916cd2Sjpk }
14945916cd2Sjpk 
15045916cd2Sjpk /*
15145916cd2Sjpk  * Compare labels. Return 1 if equal, 0 otherwise.
15245916cd2Sjpk  */
15345916cd2Sjpk boolean_t
15445916cd2Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2)
15545916cd2Sjpk {
15645916cd2Sjpk 	return ((l1->tsl_doi == l2->tsl_doi) &&
15745916cd2Sjpk 	    blequal(&l1->tsl_label, &l2->tsl_label));
15845916cd2Sjpk }
15945916cd2Sjpk 
16045916cd2Sjpk /*
16145916cd2Sjpk  * There's no protocol today to obtain the label from the server.
16245916cd2Sjpk  * So we rely on conventions: zones, zone names, and zone paths
16345916cd2Sjpk  * must match across TX servers and their TX clients.  Now use
16445916cd2Sjpk  * the exported name to find the equivalent local zone and its
16545916cd2Sjpk  * label.  Caller is responsible for doing a label_rele of the
16645916cd2Sjpk  * returned ts_label.
16745916cd2Sjpk  */
16845916cd2Sjpk ts_label_t *
16945916cd2Sjpk getflabel_cipso(vfs_t *vfsp)
17045916cd2Sjpk {
17145916cd2Sjpk 	zone_t	*reszone;
17245916cd2Sjpk 	zone_t	*new_reszone;
17345916cd2Sjpk 	char	*nfspath, *respath;
17445916cd2Sjpk 	refstr_t	*resource_ref;
17545916cd2Sjpk 	boolean_t	treat_abs = B_FALSE;
17645916cd2Sjpk 
17745916cd2Sjpk 	if (vfsp->vfs_resource == NULL)
17845916cd2Sjpk 		return (NULL);			/* error */
17945916cd2Sjpk 	resource_ref = vfs_getresource(vfsp);
18045916cd2Sjpk 
18145916cd2Sjpk 	nfspath = (char *)refstr_value(resource_ref);
18245916cd2Sjpk 	respath = strchr(nfspath, ':');		/* skip server name */
18345916cd2Sjpk 	if (respath)
18445916cd2Sjpk 		respath++;			/* skip over ":" */
18545916cd2Sjpk 	if (*respath != '/') {
18645916cd2Sjpk 		/* treat path as absolute but it doesn't have leading '/' */
18745916cd2Sjpk 		treat_abs = B_TRUE;
18845916cd2Sjpk 	}
18945916cd2Sjpk 
19045916cd2Sjpk 	reszone = zone_find_by_any_path(respath, treat_abs);
19145916cd2Sjpk 	if (reszone == global_zone) {
19245916cd2Sjpk 		refstr_rele(resource_ref);
19345916cd2Sjpk 		label_hold(l_admin_low);
19445916cd2Sjpk 		zone_rele(reszone);
19545916cd2Sjpk 		return (l_admin_low);
19645916cd2Sjpk 	}
19745916cd2Sjpk 
19845916cd2Sjpk 	/*
19945916cd2Sjpk 	 * Skip over zonepath (not including "root"), e.g. /zone/internal
20045916cd2Sjpk 	 */
20145916cd2Sjpk 	respath += reszone->zone_rootpathlen - 7;
20245916cd2Sjpk 	if (treat_abs)
20345916cd2Sjpk 		respath--;			/* no leading '/' to skip */
20445916cd2Sjpk 	if (strncmp(respath, "/root/", 6) == 0) {
20545916cd2Sjpk 		/* Check if we now have something like "/zone/public/" */
20645916cd2Sjpk 
20745916cd2Sjpk 		respath += 5;			/* skip "/root" first */
20845916cd2Sjpk 		new_reszone = zone_find_by_any_path(respath, B_FALSE);
20945916cd2Sjpk 		if (new_reszone != global_zone) {
21045916cd2Sjpk 			zone_rele(reszone);
21145916cd2Sjpk 			reszone = new_reszone;
21245916cd2Sjpk 		} else {
21345916cd2Sjpk 			zone_rele(new_reszone);
21445916cd2Sjpk 		}
21545916cd2Sjpk 	}
21645916cd2Sjpk 
21745916cd2Sjpk 	refstr_rele(resource_ref);
21845916cd2Sjpk 	label_hold(reszone->zone_slabel);
21945916cd2Sjpk 	zone_rele(reszone);
22045916cd2Sjpk 
22145916cd2Sjpk 	return (reszone->zone_slabel);
22245916cd2Sjpk }
22345916cd2Sjpk 
22445916cd2Sjpk static ts_label_t *
22545916cd2Sjpk getflabel_nfs(vfs_t *vfsp)
22645916cd2Sjpk {
22745916cd2Sjpk 	bslabel_t	*server_sl;
22845916cd2Sjpk 	ts_label_t	*srv_label;
22945916cd2Sjpk 	tsol_tpc_t	*tp;
23045916cd2Sjpk 	int		addr_type;
23145916cd2Sjpk 	void		*ipaddr;
23245916cd2Sjpk 	struct servinfo *svp;
23345916cd2Sjpk 	struct netbuf	*addr;
23445916cd2Sjpk 	struct knetconfig *knconf;
23545916cd2Sjpk 	mntinfo_t	*mi;
23645916cd2Sjpk 
23745916cd2Sjpk 	mi = VFTOMI(vfsp);
23845916cd2Sjpk 	svp = mi->mi_curr_serv;
23945916cd2Sjpk 	addr = &svp->sv_addr;
24045916cd2Sjpk 	knconf = svp->sv_knconf;
24145916cd2Sjpk 
24245916cd2Sjpk 	if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
24345916cd2Sjpk 		addr_type = IPV4_VERSION;
24445916cd2Sjpk 		/* LINTED: following cast to ipaddr is OK */
24545916cd2Sjpk 		ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
24645916cd2Sjpk 	} else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
24745916cd2Sjpk 		addr_type = IPV6_VERSION;
24845916cd2Sjpk 		/* LINTED: following cast to ipaddr is OK */
24945916cd2Sjpk 		ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
25045916cd2Sjpk 	} else {
25145916cd2Sjpk 		goto errout;
25245916cd2Sjpk 	}
25345916cd2Sjpk 
25445916cd2Sjpk 	tp = find_tpc(ipaddr, addr_type, B_FALSE);
25545916cd2Sjpk 	if (tp == NULL)
25645916cd2Sjpk 		goto errout;
25745916cd2Sjpk 
25845916cd2Sjpk 	if (tp->tpc_tp.host_type == SUN_CIPSO) {
25945916cd2Sjpk 		TPC_RELE(tp);
26045916cd2Sjpk 		return (getflabel_cipso(vfsp));
26145916cd2Sjpk 	}
26245916cd2Sjpk 
26345916cd2Sjpk 	if (tp->tpc_tp.host_type != UNLABELED)
26445916cd2Sjpk 		goto errout;
26545916cd2Sjpk 
26645916cd2Sjpk 	server_sl = &tp->tpc_tp.tp_def_label;
26745916cd2Sjpk 	srv_label = labelalloc(server_sl, default_doi, KM_SLEEP);
26845916cd2Sjpk 
26945916cd2Sjpk 	TPC_RELE(tp);
27045916cd2Sjpk 
27145916cd2Sjpk 	return (srv_label);
27245916cd2Sjpk 
27345916cd2Sjpk errout:
27445916cd2Sjpk 	return (NULL);
27545916cd2Sjpk }
27645916cd2Sjpk 
27745916cd2Sjpk /*
27845916cd2Sjpk  * getflabel -
27945916cd2Sjpk  *
28045916cd2Sjpk  * Return pointer to the ts_label associated with the specified file,
28145916cd2Sjpk  * or returns NULL if error occurs.  Caller is responsible for doing
28245916cd2Sjpk  * a label_rele of the ts_label.
28345916cd2Sjpk  */
28445916cd2Sjpk ts_label_t *
28545916cd2Sjpk getflabel(vnode_t *vp)
28645916cd2Sjpk {
2876fc927dcSgfaden 	vfs_t		*vfsp, *rvfsp;
28845916cd2Sjpk 	vnode_t		*rvp, *rvp2;
28945916cd2Sjpk 	zone_t		*zone;
29045916cd2Sjpk 	ts_label_t	*zl;
29145916cd2Sjpk 	boolean_t	vfs_is_held = B_FALSE;
29245916cd2Sjpk 	char		vpath[MAXPATHLEN];
29345916cd2Sjpk 
29445916cd2Sjpk 	ASSERT(vp);
2956fc927dcSgfaden 	vfsp = vp->v_vfsp;
29645916cd2Sjpk 	if (vfsp == NULL)
29745916cd2Sjpk 		return (NULL);
29845916cd2Sjpk 
2996fc927dcSgfaden 	rvp = vp;
30045916cd2Sjpk 
30145916cd2Sjpk 	/*
3026fc927dcSgfaden 	 * Traverse lofs mounts and fattach'es to get the real vnode
30345916cd2Sjpk 	 */
304da6c28aaSamw 	if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
30545916cd2Sjpk 		rvp = rvp2;
30645916cd2Sjpk 
3076fc927dcSgfaden 	rvfsp = rvp->v_vfsp;
30845916cd2Sjpk 
30945916cd2Sjpk 	/* rvp/rvfsp now represent the real vnode/vfs we will be using */
31045916cd2Sjpk 
31145916cd2Sjpk 	/* Go elsewhere to handle all nfs files. */
31245916cd2Sjpk 	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
31345916cd2Sjpk 		return (getflabel_nfs(rvfsp));
31445916cd2Sjpk 
31545916cd2Sjpk 	/*
31645916cd2Sjpk 	 * Fast path, for objects in a labeled zone: everything except
31745916cd2Sjpk 	 * for lofs/nfs will be just the label of that zone.
31845916cd2Sjpk 	 */
31945916cd2Sjpk 	if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
32045916cd2Sjpk 		if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
32145916cd2Sjpk 		    "lofs") != 0)) {
32245916cd2Sjpk 			zone = rvfsp->vfs_zone;
32345916cd2Sjpk 			zone_hold(zone);
32445916cd2Sjpk 			goto zone_out;		/* return this label */
32545916cd2Sjpk 		}
32645916cd2Sjpk 	}
32745916cd2Sjpk 
3286fc927dcSgfaden 	if (vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred) != 0) {
3296fc927dcSgfaden 		return (NULL);
33045916cd2Sjpk 	}
33145916cd2Sjpk 
33245916cd2Sjpk 	/*
3336fc927dcSgfaden 	 * Sanity check - vpath may be weird for some cases, like devices.
33445916cd2Sjpk 	 */
3356fc927dcSgfaden 	if (*vpath != '/') {
33645916cd2Sjpk 		zone = curproc->p_zone;
33745916cd2Sjpk 		zone_hold(zone);
33845916cd2Sjpk 		goto zone_out;
33945916cd2Sjpk 	}
34045916cd2Sjpk 
341afed4af4Srica 	/*
342afed4af4Srica 	 * If a mountpoint exists, hold the vfs while we reference it.
343afed4af4Srica 	 * Otherwise if mountpoint is NULL it should not be held (e.g.,
344afed4af4Srica 	 * a hold/release on spec_vfs would result in an attempted free
345afed4af4Srica 	 * and panic.)
346afed4af4Srica 	 */
347afed4af4Srica 	if (vfsp->vfs_mntpt != NULL) {
34845916cd2Sjpk 		VFS_HOLD(vfsp);
34945916cd2Sjpk 		vfs_is_held = B_TRUE;
350afed4af4Srica 	}
35145916cd2Sjpk 
3526fc927dcSgfaden 	zone = zone_find_by_any_path(vpath, B_FALSE);
35345916cd2Sjpk 
35445916cd2Sjpk 	/*
3556fc927dcSgfaden 	 * If the vnode source zone is properly set to a non-global zone, or
35645916cd2Sjpk 	 * any zone if the mount is R/W, then use the label of that zone.
35745916cd2Sjpk 	 */
35845916cd2Sjpk 	if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
35945916cd2Sjpk 		goto zone_out;		/* return this label */
36045916cd2Sjpk 
36145916cd2Sjpk 	/*
36245916cd2Sjpk 	 * Otherwise, if we're not in the global zone, use the label of
36345916cd2Sjpk 	 * our zone.
36445916cd2Sjpk 	 */
36545916cd2Sjpk 	if ((zone = curproc->p_zone) != global_zone) {
36645916cd2Sjpk 		zone_hold(zone);
36745916cd2Sjpk 		goto zone_out;		/* return this label */
36845916cd2Sjpk 	}
36945916cd2Sjpk 
37045916cd2Sjpk 	/*
37145916cd2Sjpk 	 * We're in the global zone and the mount is R/W ... so the file
37245916cd2Sjpk 	 * may actually be in the global zone -- or in the root of any zone.
37345916cd2Sjpk 	 * Always build our own path for the file, to be sure it's simplified
37445916cd2Sjpk 	 * (i.e., no ".", "..", "//", and so on).
37545916cd2Sjpk 	 */
37645916cd2Sjpk 
37745916cd2Sjpk 	zone_rele(zone);
37845916cd2Sjpk 	zone = zone_find_by_any_path(vpath, B_FALSE);
37945916cd2Sjpk 
38045916cd2Sjpk zone_out:
38145916cd2Sjpk 	if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
38245916cd2Sjpk 		vfs_t		*nvfs;
38345916cd2Sjpk 		boolean_t	exported = B_FALSE;
38445916cd2Sjpk 		refstr_t	*mntpt_ref;
38545916cd2Sjpk 		char		*mntpt;
38645916cd2Sjpk 
38745916cd2Sjpk 		/*
38845916cd2Sjpk 		 * File is in the global zone - check whether it's admin_high.
38945916cd2Sjpk 		 * If it's in a filesys that was exported from the global zone,
39045916cd2Sjpk 		 * it's admin_low by definition.  Otherwise, if it's in a
39145916cd2Sjpk 		 * filesys that's NOT exported to any zone, it's admin_high.
39245916cd2Sjpk 		 *
39345916cd2Sjpk 		 * And for these files if there wasn't a valid mount resource,
39445916cd2Sjpk 		 * the file must be admin_high (not exported, probably a global
39545916cd2Sjpk 		 * zone device).
39645916cd2Sjpk 		 */
39745916cd2Sjpk 		if (!vfs_is_held)
39845916cd2Sjpk 			goto out_high;
39945916cd2Sjpk 
40045916cd2Sjpk 		mntpt_ref = vfs_getmntpoint(vfsp);
40145916cd2Sjpk 		mntpt = (char *)refstr_value(mntpt_ref);
40245916cd2Sjpk 
40345916cd2Sjpk 		if ((mntpt != NULL) && (*mntpt == '/')) {
40445916cd2Sjpk 			zone_t	*to_zone;
40545916cd2Sjpk 
40645916cd2Sjpk 			to_zone = zone_find_by_any_path(mntpt, B_FALSE);
40745916cd2Sjpk 			zone_rele(to_zone);
40845916cd2Sjpk 			if (to_zone != global_zone) {
40945916cd2Sjpk 				/* force admin_low */
41045916cd2Sjpk 				exported = B_TRUE;
41145916cd2Sjpk 			}
41245916cd2Sjpk 		}
41345916cd2Sjpk 		if (mntpt_ref)
41445916cd2Sjpk 			refstr_rele(mntpt_ref);
41545916cd2Sjpk 
41645916cd2Sjpk 		if (!exported) {
41745916cd2Sjpk 			size_t	plen = strlen(vpath);
41845916cd2Sjpk 
41945916cd2Sjpk 			vfs_list_read_lock();
42045916cd2Sjpk 			nvfs = vfsp->vfs_next;
42145916cd2Sjpk 			while (nvfs != vfsp) {
42245916cd2Sjpk 				const char	*rstr;
42345916cd2Sjpk 				size_t		rlen = 0;
42445916cd2Sjpk 
42545916cd2Sjpk 				rstr = refstr_value(nvfs->vfs_resource);
42645916cd2Sjpk 				if (rstr != NULL)
42745916cd2Sjpk 					rlen = strlen(rstr);
42845916cd2Sjpk 
42945916cd2Sjpk 				/*
43045916cd2Sjpk 				 * Check for a match: does this vfs correspond
43145916cd2Sjpk 				 * to our global zone file path?  I.e., check
43245916cd2Sjpk 				 * if the resource string of this vfs is a
43345916cd2Sjpk 				 * prefix of our path.
43445916cd2Sjpk 				 */
43545916cd2Sjpk 				if ((rlen > 0) && (rlen <= plen) &&
43645916cd2Sjpk 				    (strncmp(rstr, vpath, rlen) == 0) &&
43745916cd2Sjpk 				    (vpath[rlen] == '/' ||
43845916cd2Sjpk 				    vpath[rlen] == '\0')) {
43945916cd2Sjpk 					/* force admin_low */
44045916cd2Sjpk 					exported = B_TRUE;
44145916cd2Sjpk 					break;
44245916cd2Sjpk 				}
44345916cd2Sjpk 				nvfs = nvfs->vfs_next;
44445916cd2Sjpk 			}
44545916cd2Sjpk 			vfs_list_unlock();
44645916cd2Sjpk 		}
44745916cd2Sjpk 
44845916cd2Sjpk 		if (!exported)
44945916cd2Sjpk 			goto out_high;
45045916cd2Sjpk 	}
45145916cd2Sjpk 
45245916cd2Sjpk 	if (vfs_is_held)
45345916cd2Sjpk 		VFS_RELE(vfsp);
45445916cd2Sjpk 
45545916cd2Sjpk 	/*
45645916cd2Sjpk 	 * Now that we have the "home" zone for the file, return the slabel
45745916cd2Sjpk 	 * of that zone.
45845916cd2Sjpk 	 */
45945916cd2Sjpk 	zl = zone->zone_slabel;
46045916cd2Sjpk 	label_hold(zl);
46145916cd2Sjpk 	zone_rele(zone);
46245916cd2Sjpk 	return (zl);
46345916cd2Sjpk 
46445916cd2Sjpk out_high:
46545916cd2Sjpk 	if (vfs_is_held)
46645916cd2Sjpk 		VFS_RELE(vfsp);
46745916cd2Sjpk 
46845916cd2Sjpk 	label_hold(l_admin_high);
46945916cd2Sjpk 	zone_rele(zone);
47045916cd2Sjpk 	return (l_admin_high);
47145916cd2Sjpk }
47245916cd2Sjpk 
47345916cd2Sjpk static int
47445916cd2Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp)
47545916cd2Sjpk {
47645916cd2Sjpk 	ts_label_t	*tsl;
47745916cd2Sjpk 	int		error = 0;
47845916cd2Sjpk 
47945916cd2Sjpk 	if ((tsl = getflabel(vp)) == NULL)
48045916cd2Sjpk 		return (EIO);
48145916cd2Sjpk 
48245916cd2Sjpk 	if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p,
48345916cd2Sjpk 	    sizeof (*(label_p))) != 0)
48445916cd2Sjpk 		error = EFAULT;
48545916cd2Sjpk 
48645916cd2Sjpk 	label_rele(tsl);
48745916cd2Sjpk 	return (error);
48845916cd2Sjpk }
48945916cd2Sjpk 
49045916cd2Sjpk /*
49145916cd2Sjpk  * fgetlabel(2TSOL) - get file label
49245916cd2Sjpk  * getlabel(2TSOL) - get file label
49345916cd2Sjpk  */
49445916cd2Sjpk int
49545916cd2Sjpk getlabel(const char *path, bslabel_t *label_p)
49645916cd2Sjpk {
49745916cd2Sjpk 	struct		vnode	*vp;
49845916cd2Sjpk 	char		*spath;
49945916cd2Sjpk 	int		error;
50045916cd2Sjpk 
50145916cd2Sjpk 	/* Sanity check arguments */
50245916cd2Sjpk 	if (path == NULL)
50345916cd2Sjpk 		return (set_errno(EINVAL));
50445916cd2Sjpk 
50545916cd2Sjpk 	spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
50645916cd2Sjpk 	if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) {
50745916cd2Sjpk 		kmem_free(spath, MAXPATHLEN);
50845916cd2Sjpk 		return (set_errno(error));
50945916cd2Sjpk 	}
51045916cd2Sjpk 
51145916cd2Sjpk 	if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) {
51245916cd2Sjpk 		kmem_free(spath, MAXPATHLEN);
51345916cd2Sjpk 		return (set_errno(error));
51445916cd2Sjpk 	}
51545916cd2Sjpk 	kmem_free(spath, MAXPATHLEN);
51645916cd2Sjpk 
51745916cd2Sjpk 	error = cgetlabel(label_p, vp);
51845916cd2Sjpk 
51945916cd2Sjpk 	VN_RELE(vp);
52045916cd2Sjpk 	if (error != 0)
52145916cd2Sjpk 		return (set_errno(error));
52245916cd2Sjpk 	else
52345916cd2Sjpk 		return (0);
52445916cd2Sjpk }
52545916cd2Sjpk 
52645916cd2Sjpk int
52745916cd2Sjpk fgetlabel(int fd, bslabel_t *label_p)
52845916cd2Sjpk {
52945916cd2Sjpk 	file_t		*fp;
53045916cd2Sjpk 	int		error;
53145916cd2Sjpk 
53245916cd2Sjpk 	if ((fp = getf(fd)) == NULL)
53345916cd2Sjpk 		return (set_errno(EBADF));
53445916cd2Sjpk 
53545916cd2Sjpk 	error = cgetlabel(label_p, fp->f_vnode);
53645916cd2Sjpk 	releasef(fd);
53745916cd2Sjpk 
53845916cd2Sjpk 	if (error != 0)
53945916cd2Sjpk 		return (set_errno(error));
54045916cd2Sjpk 	else
54145916cd2Sjpk 		return (0);
54245916cd2Sjpk }
54345916cd2Sjpk 
54445916cd2Sjpk /*
54503986916Sjarrett  * Used by NFSv3 and NFSv4 server to query label of
54603986916Sjarrett  * a pathname component during lookup/access ops.
54745916cd2Sjpk  */
54845916cd2Sjpk ts_label_t *
54903986916Sjarrett nfs_getflabel(vnode_t *vp)
55045916cd2Sjpk {
55145916cd2Sjpk 	zone_t *zone;
55245916cd2Sjpk 	ts_label_t *zone_label;
55345916cd2Sjpk 	char path[MAXNAMELEN];
55445916cd2Sjpk 	vnode_t *pvp, *tvp;
55545916cd2Sjpk 
55645916cd2Sjpk 	mutex_enter(&vp->v_lock);
55745916cd2Sjpk 	/*
55845916cd2Sjpk 	 * mount traverse has been done by caller
55945916cd2Sjpk 	 * before calling this routine.
56045916cd2Sjpk 	 */
56145916cd2Sjpk 	ASSERT(!vn_ismntpt(vp));
56245916cd2Sjpk 	if (vp->v_path != NULL) {
56345916cd2Sjpk 		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
56445916cd2Sjpk 		mutex_exit(&vp->v_lock);
56545916cd2Sjpk 	} else {
56645916cd2Sjpk 		/*
56745916cd2Sjpk 		 * v_path not cached. Since we rely on path
56845916cd2Sjpk 		 * of an obj to get its label, we need to get
56945916cd2Sjpk 		 * path corresponding to the parent vnode.
57045916cd2Sjpk 		 */
57145916cd2Sjpk 		tvp = vp;
57245916cd2Sjpk 		do {
57345916cd2Sjpk 			mutex_exit(&tvp->v_lock);
57445916cd2Sjpk 			if ((pvp = dnlc_reverse_lookup(tvp, path,
57545916cd2Sjpk 			    sizeof (path))) == NULL)
57645916cd2Sjpk 				return (NULL);
57745916cd2Sjpk 			mutex_enter(&pvp->v_lock);
57845916cd2Sjpk 			tvp = pvp;
57945916cd2Sjpk 		} while (pvp->v_path == NULL);
58045916cd2Sjpk 		zone = zone_find_by_any_path(pvp->v_path, B_FALSE);
58145916cd2Sjpk 		mutex_exit(&pvp->v_lock);
58245916cd2Sjpk 	}
58345916cd2Sjpk 	/*
58445916cd2Sjpk 	 * Caller has verified that the file is either
58545916cd2Sjpk 	 * exported or visible. So if the path falls in
58645916cd2Sjpk 	 * global zone, admin_low is returned; otherwise
58745916cd2Sjpk 	 * the zone's label is returned.
58845916cd2Sjpk 	 */
58945916cd2Sjpk 	zone_label = zone->zone_slabel;
59045916cd2Sjpk 	label_hold(zone_label);
59145916cd2Sjpk 	zone_rele(zone);
59245916cd2Sjpk 	return (zone_label);
59345916cd2Sjpk }
594