xref: /onnv-gate/usr/src/uts/common/os/tlabel.c (revision 12338:35935eb9ada9)
11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
211676Sjpk /*
2212236SRic.Aleshire@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
231676Sjpk  */
241676Sjpk 
251676Sjpk #include <sys/types.h>
261676Sjpk #include <sys/param.h>
271676Sjpk #include <sys/cmn_err.h>
281676Sjpk #include <sys/systm.h>
291676Sjpk #include <sys/cred.h>
301676Sjpk #include <sys/modctl.h>
311676Sjpk #include <sys/vfs.h>
321676Sjpk #include <sys/vnode.h>
331676Sjpk #include <sys/tiuser.h>
341676Sjpk #include <sys/kmem.h>
351676Sjpk #include <sys/pathname.h>
361676Sjpk #include <sys/zone.h>
371676Sjpk #include <sys/tsol/label.h>
381676Sjpk #include <sys/tsol/tnet.h>
391676Sjpk #include <sys/fs/lofs_node.h>
4012236SRic.Aleshire@Sun.COM #include <sys/fs/zfs.h>
4112236SRic.Aleshire@Sun.COM #include <sys/dsl_prop.h>
421676Sjpk #include <inet/ip6.h>
431676Sjpk #include <rpc/auth.h>
441676Sjpk #include <rpc/clnt.h>
451676Sjpk #include <nfs/nfs.h>
461676Sjpk #include <nfs/nfs4.h>
471676Sjpk #include <nfs/nfs_clnt.h>
481676Sjpk 
491676Sjpk 
504746Srica int sys_labeling = 0;			/* the default is "off" */
511676Sjpk 
521676Sjpk static kmem_cache_t *tslabel_cache;
531676Sjpk ts_label_t *l_admin_low;
541676Sjpk ts_label_t *l_admin_high;
551676Sjpk 
561676Sjpk uint32_t default_doi = DEFAULT_DOI;
571676Sjpk 
581676Sjpk /*
591676Sjpk  * Initialize labels infrastructure.
601676Sjpk  * This is called during startup() time (before vfs_mntroot) by thread_init().
611676Sjpk  * It has to be called early so that the is_system_labeled() function returns
621676Sjpk  * the right value when called by the networking code on a diskless boot.
631676Sjpk  */
641676Sjpk void
label_init(void)651676Sjpk label_init(void)
661676Sjpk {
671676Sjpk 	bslabel_t label;
681676Sjpk 
691676Sjpk 	/*
704746Srica 	 * sys_labeling will default to "off" unless it is overridden
714746Srica 	 * in /etc/system.
721676Sjpk 	 */
731676Sjpk 
741676Sjpk 	tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t),
751676Sjpk 	    0, NULL, NULL, NULL, NULL, NULL, 0);
761676Sjpk 	bsllow(&label);
771676Sjpk 	l_admin_low = labelalloc(&label, default_doi, KM_SLEEP);
781676Sjpk 	bslhigh(&label);
791676Sjpk 	l_admin_high = labelalloc(&label, default_doi, KM_SLEEP);
801676Sjpk }
811676Sjpk 
821676Sjpk /*
831676Sjpk  * Allocate new ts_label_t.
841676Sjpk  */
851676Sjpk ts_label_t *
labelalloc(const bslabel_t * val,uint32_t doi,int flag)861676Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag)
871676Sjpk {
881676Sjpk 	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
891676Sjpk 
901676Sjpk 	if (lab != NULL) {
911676Sjpk 		lab->tsl_ref = 1;
921676Sjpk 		lab->tsl_doi = doi;
934448Skp158701 		lab->tsl_flags = 0;
941676Sjpk 		if (val == NULL)
951676Sjpk 			bzero(&lab->tsl_label, sizeof (bslabel_t));
961676Sjpk 		else
971676Sjpk 			bcopy(val, &lab->tsl_label,  sizeof (bslabel_t));
981676Sjpk 	}
991676Sjpk 	return (lab);
1001676Sjpk }
1011676Sjpk 
1021676Sjpk /*
1039710SKen.Powell@Sun.COM  * Duplicate an existing ts_label_t to a new one, with only
1049710SKen.Powell@Sun.COM  * the current reference.
1059710SKen.Powell@Sun.COM  */
1069710SKen.Powell@Sun.COM ts_label_t *
labeldup(const ts_label_t * val,int flag)1079710SKen.Powell@Sun.COM labeldup(const ts_label_t *val, int flag)
1089710SKen.Powell@Sun.COM {
1099710SKen.Powell@Sun.COM 	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
1109710SKen.Powell@Sun.COM 
1119710SKen.Powell@Sun.COM 	if (lab != NULL) {
1129710SKen.Powell@Sun.COM 		bcopy(val, lab, sizeof (ts_label_t));
1139710SKen.Powell@Sun.COM 		lab->tsl_ref = 1;
1149710SKen.Powell@Sun.COM 	}
1159710SKen.Powell@Sun.COM 	return (lab);
1169710SKen.Powell@Sun.COM }
1179710SKen.Powell@Sun.COM 
1189710SKen.Powell@Sun.COM /*
1191676Sjpk  * Put a hold on a label structure.
1201676Sjpk  */
1211676Sjpk void
label_hold(ts_label_t * lab)1221676Sjpk label_hold(ts_label_t *lab)
1231676Sjpk {
1241676Sjpk 	atomic_add_32(&lab->tsl_ref, 1);
1251676Sjpk }
1261676Sjpk 
1271676Sjpk /*
1281676Sjpk  * Release previous hold on a label structure.  Free it if refcnt == 0.
1291676Sjpk  */
1301676Sjpk void
label_rele(ts_label_t * lab)1311676Sjpk label_rele(ts_label_t *lab)
1321676Sjpk {
1331676Sjpk 	if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0)
1341676Sjpk 		kmem_cache_free(tslabel_cache, lab);
1351676Sjpk }
1361676Sjpk 
1371676Sjpk bslabel_t *
label2bslabel(ts_label_t * lab)1381676Sjpk label2bslabel(ts_label_t *lab)
1391676Sjpk {
1401676Sjpk 	return (&lab->tsl_label);
1411676Sjpk }
1421676Sjpk 
1431676Sjpk 
1441676Sjpk uint32_t
label2doi(ts_label_t * lab)1451676Sjpk label2doi(ts_label_t *lab)
1461676Sjpk {
1471676Sjpk 	return (lab->tsl_doi);
1481676Sjpk }
1491676Sjpk 
1501676Sjpk /*
1511676Sjpk  * Compare labels. Return 1 if equal, 0 otherwise.
1521676Sjpk  */
1531676Sjpk boolean_t
label_equal(const ts_label_t * l1,const ts_label_t * l2)1541676Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2)
1551676Sjpk {
1561676Sjpk 	return ((l1->tsl_doi == l2->tsl_doi) &&
1571676Sjpk 	    blequal(&l1->tsl_label, &l2->tsl_label));
1581676Sjpk }
1591676Sjpk 
1601676Sjpk /*
1611676Sjpk  * There's no protocol today to obtain the label from the server.
1621676Sjpk  * So we rely on conventions: zones, zone names, and zone paths
1631676Sjpk  * must match across TX servers and their TX clients.  Now use
1641676Sjpk  * the exported name to find the equivalent local zone and its
1651676Sjpk  * label.  Caller is responsible for doing a label_rele of the
1661676Sjpk  * returned ts_label.
1671676Sjpk  */
1681676Sjpk ts_label_t *
getflabel_cipso(vfs_t * vfsp)1691676Sjpk getflabel_cipso(vfs_t *vfsp)
1701676Sjpk {
1711676Sjpk 	zone_t	*reszone;
1721676Sjpk 	zone_t	*new_reszone;
1731676Sjpk 	char	*nfspath, *respath;
1741676Sjpk 	refstr_t	*resource_ref;
1751676Sjpk 	boolean_t	treat_abs = B_FALSE;
1761676Sjpk 
1771676Sjpk 	if (vfsp->vfs_resource == NULL)
1781676Sjpk 		return (NULL);			/* error */
1791676Sjpk 	resource_ref = vfs_getresource(vfsp);
1801676Sjpk 
1811676Sjpk 	nfspath = (char *)refstr_value(resource_ref);
1821676Sjpk 	respath = strchr(nfspath, ':');		/* skip server name */
1831676Sjpk 	if (respath)
1841676Sjpk 		respath++;			/* skip over ":" */
1851676Sjpk 	if (*respath != '/') {
1861676Sjpk 		/* treat path as absolute but it doesn't have leading '/' */
1871676Sjpk 		treat_abs = B_TRUE;
1881676Sjpk 	}
1891676Sjpk 
1901676Sjpk 	reszone = zone_find_by_any_path(respath, treat_abs);
1911676Sjpk 	if (reszone == global_zone) {
1921676Sjpk 		refstr_rele(resource_ref);
1931676Sjpk 		label_hold(l_admin_low);
1941676Sjpk 		zone_rele(reszone);
1951676Sjpk 		return (l_admin_low);
1961676Sjpk 	}
1971676Sjpk 
1981676Sjpk 	/*
1991676Sjpk 	 * Skip over zonepath (not including "root"), e.g. /zone/internal
2001676Sjpk 	 */
2011676Sjpk 	respath += reszone->zone_rootpathlen - 7;
2021676Sjpk 	if (treat_abs)
2031676Sjpk 		respath--;			/* no leading '/' to skip */
2041676Sjpk 	if (strncmp(respath, "/root/", 6) == 0) {
2051676Sjpk 		/* Check if we now have something like "/zone/public/" */
2061676Sjpk 
2071676Sjpk 		respath += 5;			/* skip "/root" first */
2081676Sjpk 		new_reszone = zone_find_by_any_path(respath, B_FALSE);
2091676Sjpk 		if (new_reszone != global_zone) {
2101676Sjpk 			zone_rele(reszone);
2111676Sjpk 			reszone = new_reszone;
2121676Sjpk 		} else {
2131676Sjpk 			zone_rele(new_reszone);
2141676Sjpk 		}
2151676Sjpk 	}
2161676Sjpk 
2171676Sjpk 	refstr_rele(resource_ref);
2181676Sjpk 	label_hold(reszone->zone_slabel);
2191676Sjpk 	zone_rele(reszone);
2201676Sjpk 
2211676Sjpk 	return (reszone->zone_slabel);
2221676Sjpk }
2231676Sjpk 
22412236SRic.Aleshire@Sun.COM /*
22512236SRic.Aleshire@Sun.COM  * Get the label if any of a zfs filesystem.  Get the dataset, then
22612236SRic.Aleshire@Sun.COM  * get its mlslabel property, convert as needed, and return it.  If
22712236SRic.Aleshire@Sun.COM  * there's no mlslabel or it is the default one, return NULL.
22812236SRic.Aleshire@Sun.COM  */
22912236SRic.Aleshire@Sun.COM static ts_label_t *
getflabel_zfs(vfs_t * vfsp)23012236SRic.Aleshire@Sun.COM getflabel_zfs(vfs_t *vfsp)
23112236SRic.Aleshire@Sun.COM {
23212236SRic.Aleshire@Sun.COM 	int		error;
23312236SRic.Aleshire@Sun.COM 	ts_label_t	*tsl = NULL;
23412236SRic.Aleshire@Sun.COM 	refstr_t	*resource_ref;
23512236SRic.Aleshire@Sun.COM 	bslabel_t	ds_sl;
23612236SRic.Aleshire@Sun.COM 	char		ds_hexsl[MAXNAMELEN];
23712236SRic.Aleshire@Sun.COM 	const char	*osname;
23812236SRic.Aleshire@Sun.COM 
23912236SRic.Aleshire@Sun.COM 	resource_ref = vfs_getresource(vfsp);
24012236SRic.Aleshire@Sun.COM 	osname = refstr_value(resource_ref);
24112236SRic.Aleshire@Sun.COM 
24212236SRic.Aleshire@Sun.COM 	error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
24312236SRic.Aleshire@Sun.COM 	    1, sizeof (ds_hexsl), &ds_hexsl, NULL);
24412236SRic.Aleshire@Sun.COM 	refstr_rele(resource_ref);
24512236SRic.Aleshire@Sun.COM 
24612236SRic.Aleshire@Sun.COM 	if ((error) || (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0))
24712236SRic.Aleshire@Sun.COM 		return (NULL);
24812236SRic.Aleshire@Sun.COM 	if (hexstr_to_label(ds_hexsl, &ds_sl) != 0)
24912236SRic.Aleshire@Sun.COM 		return (NULL);
25012236SRic.Aleshire@Sun.COM 
25112236SRic.Aleshire@Sun.COM 	tsl = labelalloc(&ds_sl, default_doi, KM_SLEEP);
25212236SRic.Aleshire@Sun.COM 	return (tsl);
25312236SRic.Aleshire@Sun.COM }
25412236SRic.Aleshire@Sun.COM 
2551676Sjpk static ts_label_t *
getflabel_nfs(vfs_t * vfsp)2561676Sjpk getflabel_nfs(vfs_t *vfsp)
2571676Sjpk {
2581676Sjpk 	bslabel_t	*server_sl;
2591676Sjpk 	ts_label_t	*srv_label;
2601676Sjpk 	tsol_tpc_t	*tp;
2611676Sjpk 	int		addr_type;
2621676Sjpk 	void		*ipaddr;
2631676Sjpk 	struct servinfo *svp;
2641676Sjpk 	struct netbuf	*addr;
2651676Sjpk 	struct knetconfig *knconf;
2661676Sjpk 	mntinfo_t	*mi;
2671676Sjpk 
2681676Sjpk 	mi = VFTOMI(vfsp);
2691676Sjpk 	svp = mi->mi_curr_serv;
2701676Sjpk 	addr = &svp->sv_addr;
2711676Sjpk 	knconf = svp->sv_knconf;
2721676Sjpk 
2731676Sjpk 	if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
2741676Sjpk 		addr_type = IPV4_VERSION;
2751676Sjpk 		/* LINTED: following cast to ipaddr is OK */
2761676Sjpk 		ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
2771676Sjpk 	} else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
2781676Sjpk 		addr_type = IPV6_VERSION;
2791676Sjpk 		/* LINTED: following cast to ipaddr is OK */
2801676Sjpk 		ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
2811676Sjpk 	} else {
2821676Sjpk 		goto errout;
2831676Sjpk 	}
2841676Sjpk 
2851676Sjpk 	tp = find_tpc(ipaddr, addr_type, B_FALSE);
2861676Sjpk 	if (tp == NULL)
2871676Sjpk 		goto errout;
2881676Sjpk 
2891676Sjpk 	if (tp->tpc_tp.host_type == SUN_CIPSO) {
2901676Sjpk 		TPC_RELE(tp);
2911676Sjpk 		return (getflabel_cipso(vfsp));
2921676Sjpk 	}
2931676Sjpk 
2941676Sjpk 	if (tp->tpc_tp.host_type != UNLABELED)
2951676Sjpk 		goto errout;
2961676Sjpk 
2971676Sjpk 	server_sl = &tp->tpc_tp.tp_def_label;
2981676Sjpk 	srv_label = labelalloc(server_sl, default_doi, KM_SLEEP);
2991676Sjpk 
3001676Sjpk 	TPC_RELE(tp);
3011676Sjpk 
3021676Sjpk 	return (srv_label);
3031676Sjpk 
3041676Sjpk errout:
3051676Sjpk 	return (NULL);
3061676Sjpk }
3071676Sjpk 
3081676Sjpk /*
3091676Sjpk  * getflabel -
3101676Sjpk  *
3111676Sjpk  * Return pointer to the ts_label associated with the specified file,
3121676Sjpk  * or returns NULL if error occurs.  Caller is responsible for doing
3131676Sjpk  * a label_rele of the ts_label.
3141676Sjpk  */
3151676Sjpk ts_label_t *
getflabel(vnode_t * vp)3161676Sjpk getflabel(vnode_t *vp)
3171676Sjpk {
3181799Sgfaden 	vfs_t		*vfsp, *rvfsp;
3191676Sjpk 	vnode_t		*rvp, *rvp2;
3201676Sjpk 	zone_t		*zone;
3211676Sjpk 	ts_label_t	*zl;
322*12338SRic.Aleshire@Sun.COM 	int		err;
3231676Sjpk 	boolean_t	vfs_is_held = B_FALSE;
3241676Sjpk 	char		vpath[MAXPATHLEN];
3251676Sjpk 
3261676Sjpk 	ASSERT(vp);
3271799Sgfaden 	vfsp = vp->v_vfsp;
3281676Sjpk 	if (vfsp == NULL)
3291676Sjpk 		return (NULL);
3301676Sjpk 
3311799Sgfaden 	rvp = vp;
3321676Sjpk 
3331676Sjpk 	/*
3341799Sgfaden 	 * Traverse lofs mounts and fattach'es to get the real vnode
3351676Sjpk 	 */
3365331Samw 	if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
3371676Sjpk 		rvp = rvp2;
3381676Sjpk 
3391799Sgfaden 	rvfsp = rvp->v_vfsp;
3401676Sjpk 
3411676Sjpk 	/* rvp/rvfsp now represent the real vnode/vfs we will be using */
3421676Sjpk 
3431676Sjpk 	/* Go elsewhere to handle all nfs files. */
3441676Sjpk 	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
3451676Sjpk 		return (getflabel_nfs(rvfsp));
3461676Sjpk 
3471676Sjpk 	/*
3481676Sjpk 	 * Fast path, for objects in a labeled zone: everything except
3491676Sjpk 	 * for lofs/nfs will be just the label of that zone.
3501676Sjpk 	 */
3511676Sjpk 	if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
3521676Sjpk 		if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
3531676Sjpk 		    "lofs") != 0)) {
3541676Sjpk 			zone = rvfsp->vfs_zone;
3551676Sjpk 			zone_hold(zone);
3561676Sjpk 			goto zone_out;		/* return this label */
3571676Sjpk 		}
3581676Sjpk 	}
3591676Sjpk 
3601676Sjpk 	/*
361*12338SRic.Aleshire@Sun.COM 	 * Get the vnode path -- it may be missing or weird for some
362*12338SRic.Aleshire@Sun.COM 	 * cases, like devices.  In those cases use the label of the
363*12338SRic.Aleshire@Sun.COM 	 * current zone.
3641676Sjpk 	 */
365*12338SRic.Aleshire@Sun.COM 	err = vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred);
366*12338SRic.Aleshire@Sun.COM 	if ((err != 0) || (*vpath != '/')) {
3671799Sgfaden 		zone = curproc->p_zone;
3681799Sgfaden 		zone_hold(zone);
3691799Sgfaden 		goto zone_out;
3701676Sjpk 	}
3711676Sjpk 
3722194Srica 	/*
37312236SRic.Aleshire@Sun.COM 	 * For zfs filesystem, return the explicit label property if a
37412236SRic.Aleshire@Sun.COM 	 * meaningful one exists.
37512236SRic.Aleshire@Sun.COM 	 */
37612236SRic.Aleshire@Sun.COM 	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "zfs", 3) == 0) {
37712236SRic.Aleshire@Sun.COM 		ts_label_t *tsl;
37812236SRic.Aleshire@Sun.COM 
37912236SRic.Aleshire@Sun.COM 		tsl = getflabel_zfs(rvfsp);
38012236SRic.Aleshire@Sun.COM 
38112236SRic.Aleshire@Sun.COM 		/* if label found, return it, otherwise continue... */
38212236SRic.Aleshire@Sun.COM 		if (tsl != NULL)
38312236SRic.Aleshire@Sun.COM 			return (tsl);
38412236SRic.Aleshire@Sun.COM 	}
38512236SRic.Aleshire@Sun.COM 
38612236SRic.Aleshire@Sun.COM 	/*
3872194Srica 	 * If a mountpoint exists, hold the vfs while we reference it.
3882194Srica 	 * Otherwise if mountpoint is NULL it should not be held (e.g.,
3892194Srica 	 * a hold/release on spec_vfs would result in an attempted free
3902194Srica 	 * and panic.)
3912194Srica 	 */
3922194Srica 	if (vfsp->vfs_mntpt != NULL) {
3932194Srica 		VFS_HOLD(vfsp);
3942194Srica 		vfs_is_held = B_TRUE;
3952194Srica 	}
3961676Sjpk 
3971799Sgfaden 	zone = zone_find_by_any_path(vpath, B_FALSE);
3981676Sjpk 
3991676Sjpk 	/*
4001799Sgfaden 	 * If the vnode source zone is properly set to a non-global zone, or
4011676Sjpk 	 * any zone if the mount is R/W, then use the label of that zone.
4021676Sjpk 	 */
4031676Sjpk 	if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
4041676Sjpk 		goto zone_out;		/* return this label */
4051676Sjpk 
4061676Sjpk 	/*
4071676Sjpk 	 * Otherwise, if we're not in the global zone, use the label of
4081676Sjpk 	 * our zone.
4091676Sjpk 	 */
4101676Sjpk 	if ((zone = curproc->p_zone) != global_zone) {
4111676Sjpk 		zone_hold(zone);
4121676Sjpk 		goto zone_out;		/* return this label */
4131676Sjpk 	}
4141676Sjpk 
4151676Sjpk 	/*
4161676Sjpk 	 * We're in the global zone and the mount is R/W ... so the file
4171676Sjpk 	 * may actually be in the global zone -- or in the root of any zone.
4181676Sjpk 	 * Always build our own path for the file, to be sure it's simplified
4191676Sjpk 	 * (i.e., no ".", "..", "//", and so on).
4201676Sjpk 	 */
4211676Sjpk 
4221676Sjpk 	zone_rele(zone);
4231676Sjpk 	zone = zone_find_by_any_path(vpath, B_FALSE);
4241676Sjpk 
4251676Sjpk zone_out:
4261676Sjpk 	if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
4271676Sjpk 		vfs_t		*nvfs;
4281676Sjpk 		boolean_t	exported = B_FALSE;
4291676Sjpk 		refstr_t	*mntpt_ref;
4301676Sjpk 		char		*mntpt;
4311676Sjpk 
4321676Sjpk 		/*
4331676Sjpk 		 * File is in the global zone - check whether it's admin_high.
4341676Sjpk 		 * If it's in a filesys that was exported from the global zone,
4351676Sjpk 		 * it's admin_low by definition.  Otherwise, if it's in a
4361676Sjpk 		 * filesys that's NOT exported to any zone, it's admin_high.
4371676Sjpk 		 *
4381676Sjpk 		 * And for these files if there wasn't a valid mount resource,
4391676Sjpk 		 * the file must be admin_high (not exported, probably a global
4401676Sjpk 		 * zone device).
4411676Sjpk 		 */
4421676Sjpk 		if (!vfs_is_held)
4431676Sjpk 			goto out_high;
4441676Sjpk 
4451676Sjpk 		mntpt_ref = vfs_getmntpoint(vfsp);
4461676Sjpk 		mntpt = (char *)refstr_value(mntpt_ref);
4471676Sjpk 
4481676Sjpk 		if ((mntpt != NULL) && (*mntpt == '/')) {
4491676Sjpk 			zone_t	*to_zone;
4501676Sjpk 
4511676Sjpk 			to_zone = zone_find_by_any_path(mntpt, B_FALSE);
4521676Sjpk 			zone_rele(to_zone);
4531676Sjpk 			if (to_zone != global_zone) {
4541676Sjpk 				/* force admin_low */
4551676Sjpk 				exported = B_TRUE;
4561676Sjpk 			}
4571676Sjpk 		}
4581676Sjpk 		if (mntpt_ref)
4591676Sjpk 			refstr_rele(mntpt_ref);
4601676Sjpk 
4611676Sjpk 		if (!exported) {
4621676Sjpk 			size_t	plen = strlen(vpath);
4631676Sjpk 
4641676Sjpk 			vfs_list_read_lock();
4651676Sjpk 			nvfs = vfsp->vfs_next;
4661676Sjpk 			while (nvfs != vfsp) {
4671676Sjpk 				const char	*rstr;
4681676Sjpk 				size_t		rlen = 0;
4691676Sjpk 
47012236SRic.Aleshire@Sun.COM 				/*
47112236SRic.Aleshire@Sun.COM 				 * Skip checking this vfs if it's not lofs
47212236SRic.Aleshire@Sun.COM 				 * (the only way to export from the global
47312236SRic.Aleshire@Sun.COM 				 * zone to a zone).
47412236SRic.Aleshire@Sun.COM 				 */
47512236SRic.Aleshire@Sun.COM 				if (strncmp(vfssw[nvfs->vfs_fstype].vsw_name,
47612236SRic.Aleshire@Sun.COM 				    "lofs", 4) != 0) {
47712236SRic.Aleshire@Sun.COM 					nvfs = nvfs->vfs_next;
47812236SRic.Aleshire@Sun.COM 					continue;
47912236SRic.Aleshire@Sun.COM 				}
48012236SRic.Aleshire@Sun.COM 
4811676Sjpk 				rstr = refstr_value(nvfs->vfs_resource);
4821676Sjpk 				if (rstr != NULL)
4831676Sjpk 					rlen = strlen(rstr);
4841676Sjpk 
4851676Sjpk 				/*
4861676Sjpk 				 * Check for a match: does this vfs correspond
4871676Sjpk 				 * to our global zone file path?  I.e., check
4881676Sjpk 				 * if the resource string of this vfs is a
4891676Sjpk 				 * prefix of our path.
4901676Sjpk 				 */
4911676Sjpk 				if ((rlen > 0) && (rlen <= plen) &&
4921676Sjpk 				    (strncmp(rstr, vpath, rlen) == 0) &&
4931676Sjpk 				    (vpath[rlen] == '/' ||
4941676Sjpk 				    vpath[rlen] == '\0')) {
4951676Sjpk 					/* force admin_low */
4961676Sjpk 					exported = B_TRUE;
4971676Sjpk 					break;
4981676Sjpk 				}
4991676Sjpk 				nvfs = nvfs->vfs_next;
5001676Sjpk 			}
5011676Sjpk 			vfs_list_unlock();
5021676Sjpk 		}
5031676Sjpk 
5041676Sjpk 		if (!exported)
5051676Sjpk 			goto out_high;
5061676Sjpk 	}
5071676Sjpk 
5081676Sjpk 	if (vfs_is_held)
5091676Sjpk 		VFS_RELE(vfsp);
5101676Sjpk 
5111676Sjpk 	/*
5121676Sjpk 	 * Now that we have the "home" zone for the file, return the slabel
5131676Sjpk 	 * of that zone.
5141676Sjpk 	 */
5151676Sjpk 	zl = zone->zone_slabel;
5161676Sjpk 	label_hold(zl);
5171676Sjpk 	zone_rele(zone);
5181676Sjpk 	return (zl);
5191676Sjpk 
5201676Sjpk out_high:
5211676Sjpk 	if (vfs_is_held)
5221676Sjpk 		VFS_RELE(vfsp);
5231676Sjpk 
5241676Sjpk 	label_hold(l_admin_high);
5251676Sjpk 	zone_rele(zone);
5261676Sjpk 	return (l_admin_high);
5271676Sjpk }
5281676Sjpk 
5291676Sjpk static int
cgetlabel(bslabel_t * label_p,vnode_t * vp)5301676Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp)
5311676Sjpk {
5321676Sjpk 	ts_label_t	*tsl;
5331676Sjpk 	int		error = 0;
5341676Sjpk 
5351676Sjpk 	if ((tsl = getflabel(vp)) == NULL)
5361676Sjpk 		return (EIO);
5371676Sjpk 
5381676Sjpk 	if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p,
5391676Sjpk 	    sizeof (*(label_p))) != 0)
5401676Sjpk 		error = EFAULT;
5411676Sjpk 
5421676Sjpk 	label_rele(tsl);
5431676Sjpk 	return (error);
5441676Sjpk }
5451676Sjpk 
5461676Sjpk /*
5471676Sjpk  * fgetlabel(2TSOL) - get file label
5481676Sjpk  * getlabel(2TSOL) - get file label
5491676Sjpk  */
5501676Sjpk int
getlabel(const char * path,bslabel_t * label_p)5511676Sjpk getlabel(const char *path, bslabel_t *label_p)
5521676Sjpk {
5531676Sjpk 	struct		vnode	*vp;
5541676Sjpk 	char		*spath;
5551676Sjpk 	int		error;
5561676Sjpk 
5571676Sjpk 	/* Sanity check arguments */
5581676Sjpk 	if (path == NULL)
5591676Sjpk 		return (set_errno(EINVAL));
5601676Sjpk 
5611676Sjpk 	spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
5621676Sjpk 	if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) {
5631676Sjpk 		kmem_free(spath, MAXPATHLEN);
5641676Sjpk 		return (set_errno(error));
5651676Sjpk 	}
5661676Sjpk 
5671676Sjpk 	if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) {
5681676Sjpk 		kmem_free(spath, MAXPATHLEN);
5691676Sjpk 		return (set_errno(error));
5701676Sjpk 	}
5711676Sjpk 	kmem_free(spath, MAXPATHLEN);
5721676Sjpk 
5731676Sjpk 	error = cgetlabel(label_p, vp);
5741676Sjpk 
5751676Sjpk 	VN_RELE(vp);
5761676Sjpk 	if (error != 0)
5771676Sjpk 		return (set_errno(error));
5781676Sjpk 	else
5791676Sjpk 		return (0);
5801676Sjpk }
5811676Sjpk 
5821676Sjpk int
fgetlabel(int fd,bslabel_t * label_p)5831676Sjpk fgetlabel(int fd, bslabel_t *label_p)
5841676Sjpk {
5851676Sjpk 	file_t		*fp;
5861676Sjpk 	int		error;
5871676Sjpk 
5881676Sjpk 	if ((fp = getf(fd)) == NULL)
5891676Sjpk 		return (set_errno(EBADF));
5901676Sjpk 
5911676Sjpk 	error = cgetlabel(label_p, fp->f_vnode);
5921676Sjpk 	releasef(fd);
5931676Sjpk 
5941676Sjpk 	if (error != 0)
5951676Sjpk 		return (set_errno(error));
5961676Sjpk 	else
5971676Sjpk 		return (0);
5981676Sjpk }
599