xref: /titanic_53/usr/src/uts/common/os/tlabel.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
1*45916cd2Sjpk /*
2*45916cd2Sjpk  * CDDL HEADER START
3*45916cd2Sjpk  *
4*45916cd2Sjpk  * The contents of this file are subject to the terms of the
5*45916cd2Sjpk  * Common Development and Distribution License (the "License").
6*45916cd2Sjpk  * You may not use this file except in compliance with the License.
7*45916cd2Sjpk  *
8*45916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*45916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
10*45916cd2Sjpk  * See the License for the specific language governing permissions
11*45916cd2Sjpk  * and limitations under the License.
12*45916cd2Sjpk  *
13*45916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
14*45916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*45916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
16*45916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
17*45916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
18*45916cd2Sjpk  *
19*45916cd2Sjpk  * CDDL HEADER END
20*45916cd2Sjpk  */
21*45916cd2Sjpk /*
22*45916cd2Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*45916cd2Sjpk  * Use is subject to license terms.
24*45916cd2Sjpk  */
25*45916cd2Sjpk 
26*45916cd2Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*45916cd2Sjpk 
28*45916cd2Sjpk #include <sys/types.h>
29*45916cd2Sjpk #include <sys/param.h>
30*45916cd2Sjpk #include <sys/cmn_err.h>
31*45916cd2Sjpk #include <sys/systm.h>
32*45916cd2Sjpk #include <sys/cred.h>
33*45916cd2Sjpk #include <sys/modctl.h>
34*45916cd2Sjpk #include <sys/vfs.h>
35*45916cd2Sjpk #include <sys/vnode.h>
36*45916cd2Sjpk #include <sys/tiuser.h>
37*45916cd2Sjpk #include <sys/kmem.h>
38*45916cd2Sjpk #include <sys/pathname.h>
39*45916cd2Sjpk #include <sys/zone.h>
40*45916cd2Sjpk #include <sys/tsol/label.h>
41*45916cd2Sjpk #include <sys/tsol/tnet.h>
42*45916cd2Sjpk #include <sys/fs/lofs_node.h>
43*45916cd2Sjpk #include <inet/ip6.h>
44*45916cd2Sjpk #include <rpc/auth.h>
45*45916cd2Sjpk #include <rpc/clnt.h>
46*45916cd2Sjpk #include <nfs/nfs.h>
47*45916cd2Sjpk #include <nfs/nfs4.h>
48*45916cd2Sjpk #include <nfs/nfs_clnt.h>
49*45916cd2Sjpk #include <sys/dnlc.h>
50*45916cd2Sjpk 
51*45916cd2Sjpk 
52*45916cd2Sjpk int sys_labeling = -1;			/* initially unset */
53*45916cd2Sjpk 
54*45916cd2Sjpk static kmem_cache_t *tslabel_cache;
55*45916cd2Sjpk ts_label_t *l_admin_low;
56*45916cd2Sjpk ts_label_t *l_admin_high;
57*45916cd2Sjpk 
58*45916cd2Sjpk uint32_t default_doi = DEFAULT_DOI;
59*45916cd2Sjpk 
60*45916cd2Sjpk /*
61*45916cd2Sjpk  * Initialize labels infrastructure.
62*45916cd2Sjpk  * This is called during startup() time (before vfs_mntroot) by thread_init().
63*45916cd2Sjpk  * It has to be called early so that the is_system_labeled() function returns
64*45916cd2Sjpk  * the right value when called by the networking code on a diskless boot.
65*45916cd2Sjpk  */
66*45916cd2Sjpk void
67*45916cd2Sjpk label_init(void)
68*45916cd2Sjpk {
69*45916cd2Sjpk 	bslabel_t label;
70*45916cd2Sjpk 
71*45916cd2Sjpk 	/*
72*45916cd2Sjpk 	 * Use the value of "label_services" within the edition module.
73*45916cd2Sjpk 	 * If for some reason label_services is not found, this will
74*45916cd2Sjpk 	 * result in the appropriate default -- "off."
75*45916cd2Sjpk 	 */
76*45916cd2Sjpk 	if (modgetsymvalue("label_services", B_FALSE) != 0)
77*45916cd2Sjpk 		sys_labeling = 1;
78*45916cd2Sjpk 	else
79*45916cd2Sjpk 		sys_labeling = 0;
80*45916cd2Sjpk 
81*45916cd2Sjpk 	tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t),
82*45916cd2Sjpk 	    0, NULL, NULL, NULL, NULL, NULL, 0);
83*45916cd2Sjpk 	bsllow(&label);
84*45916cd2Sjpk 	l_admin_low = labelalloc(&label, default_doi, KM_SLEEP);
85*45916cd2Sjpk 	bslhigh(&label);
86*45916cd2Sjpk 	l_admin_high = labelalloc(&label, default_doi, KM_SLEEP);
87*45916cd2Sjpk }
88*45916cd2Sjpk 
89*45916cd2Sjpk /*
90*45916cd2Sjpk  * Allocate new ts_label_t.
91*45916cd2Sjpk  */
92*45916cd2Sjpk ts_label_t *
93*45916cd2Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag)
94*45916cd2Sjpk {
95*45916cd2Sjpk 	ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
96*45916cd2Sjpk 
97*45916cd2Sjpk 	if (lab != NULL) {
98*45916cd2Sjpk 		lab->tsl_ref = 1;
99*45916cd2Sjpk 		lab->tsl_doi = doi;
100*45916cd2Sjpk 		if (val == NULL)
101*45916cd2Sjpk 			bzero(&lab->tsl_label, sizeof (bslabel_t));
102*45916cd2Sjpk 		else
103*45916cd2Sjpk 			bcopy(val, &lab->tsl_label,  sizeof (bslabel_t));
104*45916cd2Sjpk 	}
105*45916cd2Sjpk 	return (lab);
106*45916cd2Sjpk }
107*45916cd2Sjpk 
108*45916cd2Sjpk /*
109*45916cd2Sjpk  * Put a hold on a label structure.
110*45916cd2Sjpk  */
111*45916cd2Sjpk void
112*45916cd2Sjpk label_hold(ts_label_t *lab)
113*45916cd2Sjpk {
114*45916cd2Sjpk 	atomic_add_32(&lab->tsl_ref, 1);
115*45916cd2Sjpk }
116*45916cd2Sjpk 
117*45916cd2Sjpk /*
118*45916cd2Sjpk  * Release previous hold on a label structure.  Free it if refcnt == 0.
119*45916cd2Sjpk  */
120*45916cd2Sjpk void
121*45916cd2Sjpk label_rele(ts_label_t *lab)
122*45916cd2Sjpk {
123*45916cd2Sjpk 	if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0)
124*45916cd2Sjpk 		kmem_cache_free(tslabel_cache, lab);
125*45916cd2Sjpk }
126*45916cd2Sjpk 
127*45916cd2Sjpk bslabel_t *
128*45916cd2Sjpk label2bslabel(ts_label_t *lab)
129*45916cd2Sjpk {
130*45916cd2Sjpk 	return (&lab->tsl_label);
131*45916cd2Sjpk }
132*45916cd2Sjpk 
133*45916cd2Sjpk 
134*45916cd2Sjpk uint32_t
135*45916cd2Sjpk label2doi(ts_label_t *lab)
136*45916cd2Sjpk {
137*45916cd2Sjpk 	return (lab->tsl_doi);
138*45916cd2Sjpk }
139*45916cd2Sjpk 
140*45916cd2Sjpk /*
141*45916cd2Sjpk  * Compare labels. Return 1 if equal, 0 otherwise.
142*45916cd2Sjpk  */
143*45916cd2Sjpk boolean_t
144*45916cd2Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2)
145*45916cd2Sjpk {
146*45916cd2Sjpk 	return ((l1->tsl_doi == l2->tsl_doi) &&
147*45916cd2Sjpk 	    blequal(&l1->tsl_label, &l2->tsl_label));
148*45916cd2Sjpk }
149*45916cd2Sjpk 
150*45916cd2Sjpk /*
151*45916cd2Sjpk  * There's no protocol today to obtain the label from the server.
152*45916cd2Sjpk  * So we rely on conventions: zones, zone names, and zone paths
153*45916cd2Sjpk  * must match across TX servers and their TX clients.  Now use
154*45916cd2Sjpk  * the exported name to find the equivalent local zone and its
155*45916cd2Sjpk  * label.  Caller is responsible for doing a label_rele of the
156*45916cd2Sjpk  * returned ts_label.
157*45916cd2Sjpk  */
158*45916cd2Sjpk ts_label_t *
159*45916cd2Sjpk getflabel_cipso(vfs_t *vfsp)
160*45916cd2Sjpk {
161*45916cd2Sjpk 	zone_t	*reszone;
162*45916cd2Sjpk 	zone_t	*new_reszone;
163*45916cd2Sjpk 	char	*nfspath, *respath;
164*45916cd2Sjpk 	refstr_t	*resource_ref;
165*45916cd2Sjpk 	boolean_t	treat_abs = B_FALSE;
166*45916cd2Sjpk 
167*45916cd2Sjpk 	if (vfsp->vfs_resource == NULL)
168*45916cd2Sjpk 		return (NULL);			/* error */
169*45916cd2Sjpk 	resource_ref = vfs_getresource(vfsp);
170*45916cd2Sjpk 
171*45916cd2Sjpk 	nfspath = (char *)refstr_value(resource_ref);
172*45916cd2Sjpk 	respath = strchr(nfspath, ':');		/* skip server name */
173*45916cd2Sjpk 	if (respath)
174*45916cd2Sjpk 		respath++;			/* skip over ":" */
175*45916cd2Sjpk 	if (*respath != '/') {
176*45916cd2Sjpk 		/* treat path as absolute but it doesn't have leading '/' */
177*45916cd2Sjpk 		treat_abs = B_TRUE;
178*45916cd2Sjpk 	}
179*45916cd2Sjpk 
180*45916cd2Sjpk 	reszone = zone_find_by_any_path(respath, treat_abs);
181*45916cd2Sjpk 	if (reszone == global_zone) {
182*45916cd2Sjpk 		refstr_rele(resource_ref);
183*45916cd2Sjpk 		label_hold(l_admin_low);
184*45916cd2Sjpk 		zone_rele(reszone);
185*45916cd2Sjpk 		return (l_admin_low);
186*45916cd2Sjpk 	}
187*45916cd2Sjpk 
188*45916cd2Sjpk 	/*
189*45916cd2Sjpk 	 * Skip over zonepath (not including "root"), e.g. /zone/internal
190*45916cd2Sjpk 	 */
191*45916cd2Sjpk 	respath += reszone->zone_rootpathlen - 7;
192*45916cd2Sjpk 	if (treat_abs)
193*45916cd2Sjpk 		respath--;			/* no leading '/' to skip */
194*45916cd2Sjpk 	if (strncmp(respath, "/root/", 6) == 0) {
195*45916cd2Sjpk 		/* Check if we now have something like "/zone/public/" */
196*45916cd2Sjpk 
197*45916cd2Sjpk 		respath += 5;			/* skip "/root" first */
198*45916cd2Sjpk 		new_reszone = zone_find_by_any_path(respath, B_FALSE);
199*45916cd2Sjpk 		if (new_reszone != global_zone) {
200*45916cd2Sjpk 			zone_rele(reszone);
201*45916cd2Sjpk 			reszone = new_reszone;
202*45916cd2Sjpk 		} else {
203*45916cd2Sjpk 			zone_rele(new_reszone);
204*45916cd2Sjpk 		}
205*45916cd2Sjpk 	}
206*45916cd2Sjpk 
207*45916cd2Sjpk 	refstr_rele(resource_ref);
208*45916cd2Sjpk 	label_hold(reszone->zone_slabel);
209*45916cd2Sjpk 	zone_rele(reszone);
210*45916cd2Sjpk 
211*45916cd2Sjpk 	return (reszone->zone_slabel);
212*45916cd2Sjpk }
213*45916cd2Sjpk 
214*45916cd2Sjpk static ts_label_t *
215*45916cd2Sjpk getflabel_nfs(vfs_t *vfsp)
216*45916cd2Sjpk {
217*45916cd2Sjpk 	bslabel_t	*server_sl;
218*45916cd2Sjpk 	ts_label_t	*srv_label;
219*45916cd2Sjpk 	tsol_tpc_t	*tp;
220*45916cd2Sjpk 	int		addr_type;
221*45916cd2Sjpk 	void		*ipaddr;
222*45916cd2Sjpk 	struct servinfo *svp;
223*45916cd2Sjpk 	struct netbuf	*addr;
224*45916cd2Sjpk 	struct knetconfig *knconf;
225*45916cd2Sjpk 	mntinfo_t	*mi;
226*45916cd2Sjpk 
227*45916cd2Sjpk 	mi = VFTOMI(vfsp);
228*45916cd2Sjpk 	svp = mi->mi_curr_serv;
229*45916cd2Sjpk 	addr = &svp->sv_addr;
230*45916cd2Sjpk 	knconf = svp->sv_knconf;
231*45916cd2Sjpk 
232*45916cd2Sjpk 	if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
233*45916cd2Sjpk 		addr_type = IPV4_VERSION;
234*45916cd2Sjpk 		/* LINTED: following cast to ipaddr is OK */
235*45916cd2Sjpk 		ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
236*45916cd2Sjpk 	} else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
237*45916cd2Sjpk 		addr_type = IPV6_VERSION;
238*45916cd2Sjpk 		/* LINTED: following cast to ipaddr is OK */
239*45916cd2Sjpk 		ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
240*45916cd2Sjpk 	} else {
241*45916cd2Sjpk 		goto errout;
242*45916cd2Sjpk 	}
243*45916cd2Sjpk 
244*45916cd2Sjpk 	tp = find_tpc(ipaddr, addr_type, B_FALSE);
245*45916cd2Sjpk 	if (tp == NULL)
246*45916cd2Sjpk 		goto errout;
247*45916cd2Sjpk 
248*45916cd2Sjpk 	if (tp->tpc_tp.host_type == SUN_CIPSO) {
249*45916cd2Sjpk 		TPC_RELE(tp);
250*45916cd2Sjpk 		return (getflabel_cipso(vfsp));
251*45916cd2Sjpk 	}
252*45916cd2Sjpk 
253*45916cd2Sjpk 	if (tp->tpc_tp.host_type != UNLABELED)
254*45916cd2Sjpk 		goto errout;
255*45916cd2Sjpk 
256*45916cd2Sjpk 	server_sl = &tp->tpc_tp.tp_def_label;
257*45916cd2Sjpk 	srv_label = labelalloc(server_sl, default_doi, KM_SLEEP);
258*45916cd2Sjpk 
259*45916cd2Sjpk 	TPC_RELE(tp);
260*45916cd2Sjpk 
261*45916cd2Sjpk 	return (srv_label);
262*45916cd2Sjpk 
263*45916cd2Sjpk errout:
264*45916cd2Sjpk 	return (NULL);
265*45916cd2Sjpk }
266*45916cd2Sjpk 
267*45916cd2Sjpk /*
268*45916cd2Sjpk  * getflabel -
269*45916cd2Sjpk  *
270*45916cd2Sjpk  * Return pointer to the ts_label associated with the specified file,
271*45916cd2Sjpk  * or returns NULL if error occurs.  Caller is responsible for doing
272*45916cd2Sjpk  * a label_rele of the ts_label.
273*45916cd2Sjpk  */
274*45916cd2Sjpk ts_label_t *
275*45916cd2Sjpk getflabel(vnode_t *vp)
276*45916cd2Sjpk {
277*45916cd2Sjpk 	vfs_t		*vfsp, *rvfsp, *nvfs;
278*45916cd2Sjpk 	vnode_t		*rvp, *rvp2;
279*45916cd2Sjpk 	zone_t		*zone;
280*45916cd2Sjpk 	ts_label_t	*zl;
281*45916cd2Sjpk 	boolean_t	vfs_is_held = B_FALSE;
282*45916cd2Sjpk 	refstr_t	*resource_ref = NULL;
283*45916cd2Sjpk 	char		*resource = NULL;
284*45916cd2Sjpk 	char		vpath[MAXPATHLEN];
285*45916cd2Sjpk 
286*45916cd2Sjpk 	ASSERT(vp);
287*45916cd2Sjpk 	vfsp = rvfsp = nvfs = vp->v_vfsp;
288*45916cd2Sjpk 	if (vfsp == NULL)
289*45916cd2Sjpk 		return (NULL);
290*45916cd2Sjpk 
291*45916cd2Sjpk 	rvp = rvp2 = vp;
292*45916cd2Sjpk 
293*45916cd2Sjpk 	/*
294*45916cd2Sjpk 	 * Get rid of all but the last loopback vfs, since the last such mount
295*45916cd2Sjpk 	 * has the correct resource to use (except for nfs case, handled later).
296*45916cd2Sjpk 	 */
297*45916cd2Sjpk 	while (strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "lofs") == 0) {
298*45916cd2Sjpk 		rvp = rvp2;
299*45916cd2Sjpk 		rvfsp = nvfs;
300*45916cd2Sjpk 		if ((rvp2 = realvp(rvp)) == NULL)
301*45916cd2Sjpk 			break;
302*45916cd2Sjpk 		if (((nvfs = rvp2->v_vfsp) == NULL) || (nvfs == rvfsp))
303*45916cd2Sjpk 			break;
304*45916cd2Sjpk 	}
305*45916cd2Sjpk 
306*45916cd2Sjpk 	/*
307*45916cd2Sjpk 	 * rvp/rvfsp now represent the preliminary vnode/vfs we may use.  Now
308*45916cd2Sjpk 	 * check if the next vfs is nfs; if so, then it has the correct info
309*45916cd2Sjpk 	 * to use.  And finally, for some cases on loop-back mounts there will
310*45916cd2Sjpk 	 * be no resource; for these, use the underlying vfs also.
311*45916cd2Sjpk 	 */
312*45916cd2Sjpk 	if (strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, "lofs") == 0) {
313*45916cd2Sjpk 		if (((rvp2 = realvp(rvp)) != NULL) &&
314*45916cd2Sjpk 		    ((nvfs = rvp2->v_vfsp) != NULL) &&
315*45916cd2Sjpk 		    ((strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "nfs") == 0)) ||
316*45916cd2Sjpk 		    (rvfsp->vfs_resource == NULL)) {
317*45916cd2Sjpk 			rvp = rvp2;
318*45916cd2Sjpk 			rvfsp = nvfs;
319*45916cd2Sjpk 		}
320*45916cd2Sjpk 	}
321*45916cd2Sjpk 
322*45916cd2Sjpk 	/* rvp/rvfsp now represent the real vnode/vfs we will be using */
323*45916cd2Sjpk 
324*45916cd2Sjpk 	/* Go elsewhere to handle all nfs files. */
325*45916cd2Sjpk 	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
326*45916cd2Sjpk 		return (getflabel_nfs(rvfsp));
327*45916cd2Sjpk 
328*45916cd2Sjpk 	/*
329*45916cd2Sjpk 	 * Fast path, for objects in a labeled zone: everything except
330*45916cd2Sjpk 	 * for lofs/nfs will be just the label of that zone.
331*45916cd2Sjpk 	 */
332*45916cd2Sjpk 	if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
333*45916cd2Sjpk 		if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
334*45916cd2Sjpk 		    "lofs") != 0)) {
335*45916cd2Sjpk 			zone = rvfsp->vfs_zone;
336*45916cd2Sjpk 			zone_hold(zone);
337*45916cd2Sjpk 			goto zone_out;		/* return this label */
338*45916cd2Sjpk 		}
339*45916cd2Sjpk 	}
340*45916cd2Sjpk 
341*45916cd2Sjpk 	if (rvfsp->vfs_resource) {
342*45916cd2Sjpk 		resource_ref = vfs_getresource(rvfsp);
343*45916cd2Sjpk 		resource = (char *)refstr_value(resource_ref);
344*45916cd2Sjpk 	}
345*45916cd2Sjpk 
346*45916cd2Sjpk 	/*
347*45916cd2Sjpk 	 * Sanity check - resource may be weird for some cases, like devices.
348*45916cd2Sjpk 	 * In this case, the label must be "local", so just use the mount point.
349*45916cd2Sjpk 	 */
350*45916cd2Sjpk 	if ((resource == NULL) || (*resource != '/')) {
351*45916cd2Sjpk 		if (resource_ref)
352*45916cd2Sjpk 			refstr_rele(resource_ref);
353*45916cd2Sjpk 		if (rvfsp->vfs_mntpt) {
354*45916cd2Sjpk 			resource_ref = vfs_getmntpoint(rvfsp);
355*45916cd2Sjpk 			resource = (char *)refstr_value(resource_ref);
356*45916cd2Sjpk 		}
357*45916cd2Sjpk 		if ((resource == NULL) || (*resource != '/')) {
358*45916cd2Sjpk 			zone = curproc->p_zone;
359*45916cd2Sjpk 			zone_hold(zone);
360*45916cd2Sjpk 			goto zone_out;
361*45916cd2Sjpk 		}
362*45916cd2Sjpk 	}
363*45916cd2Sjpk 
364*45916cd2Sjpk 	VFS_HOLD(vfsp);
365*45916cd2Sjpk 	vfs_is_held = B_TRUE;
366*45916cd2Sjpk 
367*45916cd2Sjpk 	zone = zone_find_by_any_path(resource, B_FALSE);
368*45916cd2Sjpk 
369*45916cd2Sjpk 	/*
370*45916cd2Sjpk 	 * If the vfs source zone is properly set to a non-global zone, or
371*45916cd2Sjpk 	 * any zone if the mount is R/W, then use the label of that zone.
372*45916cd2Sjpk 	 */
373*45916cd2Sjpk 	if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
374*45916cd2Sjpk 		goto zone_out;		/* return this label */
375*45916cd2Sjpk 
376*45916cd2Sjpk 	/*
377*45916cd2Sjpk 	 * Otherwise, if we're not in the global zone, use the label of
378*45916cd2Sjpk 	 * our zone.
379*45916cd2Sjpk 	 */
380*45916cd2Sjpk 	if ((zone = curproc->p_zone) != global_zone) {
381*45916cd2Sjpk 		zone_hold(zone);
382*45916cd2Sjpk 		goto zone_out;		/* return this label */
383*45916cd2Sjpk 	}
384*45916cd2Sjpk 
385*45916cd2Sjpk 	/*
386*45916cd2Sjpk 	 * We're in the global zone and the mount is R/W ... so the file
387*45916cd2Sjpk 	 * may actually be in the global zone -- or in the root of any zone.
388*45916cd2Sjpk 	 * Always build our own path for the file, to be sure it's simplified
389*45916cd2Sjpk 	 * (i.e., no ".", "..", "//", and so on).
390*45916cd2Sjpk 	 */
391*45916cd2Sjpk 	if (vnodetopath(NULL, vp, vpath, sizeof (vpath), CRED()) != 0) {
392*45916cd2Sjpk 		if (vfs_is_held)
393*45916cd2Sjpk 			VFS_RELE(vfsp);
394*45916cd2Sjpk 		if (resource_ref)
395*45916cd2Sjpk 			refstr_rele(resource_ref);
396*45916cd2Sjpk 		zone_rele(zone);
397*45916cd2Sjpk 		return (NULL);
398*45916cd2Sjpk 	}
399*45916cd2Sjpk 
400*45916cd2Sjpk 	zone_rele(zone);
401*45916cd2Sjpk 	zone = zone_find_by_any_path(vpath, B_FALSE);
402*45916cd2Sjpk 
403*45916cd2Sjpk zone_out:
404*45916cd2Sjpk 	if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
405*45916cd2Sjpk 		vfs_t		*nvfs;
406*45916cd2Sjpk 		boolean_t	exported = B_FALSE;
407*45916cd2Sjpk 		refstr_t	*mntpt_ref;
408*45916cd2Sjpk 		char		*mntpt;
409*45916cd2Sjpk 
410*45916cd2Sjpk 		/*
411*45916cd2Sjpk 		 * File is in the global zone - check whether it's admin_high.
412*45916cd2Sjpk 		 * If it's in a filesys that was exported from the global zone,
413*45916cd2Sjpk 		 * it's admin_low by definition.  Otherwise, if it's in a
414*45916cd2Sjpk 		 * filesys that's NOT exported to any zone, it's admin_high.
415*45916cd2Sjpk 		 *
416*45916cd2Sjpk 		 * And for these files if there wasn't a valid mount resource,
417*45916cd2Sjpk 		 * the file must be admin_high (not exported, probably a global
418*45916cd2Sjpk 		 * zone device).
419*45916cd2Sjpk 		 */
420*45916cd2Sjpk 		if (!vfs_is_held)
421*45916cd2Sjpk 			goto out_high;
422*45916cd2Sjpk 
423*45916cd2Sjpk 		mntpt_ref = vfs_getmntpoint(vfsp);
424*45916cd2Sjpk 		mntpt = (char *)refstr_value(mntpt_ref);
425*45916cd2Sjpk 
426*45916cd2Sjpk 		if ((mntpt != NULL) && (*mntpt == '/')) {
427*45916cd2Sjpk 			zone_t	*to_zone;
428*45916cd2Sjpk 
429*45916cd2Sjpk 			to_zone = zone_find_by_any_path(mntpt, B_FALSE);
430*45916cd2Sjpk 			zone_rele(to_zone);
431*45916cd2Sjpk 			if (to_zone != global_zone) {
432*45916cd2Sjpk 				/* force admin_low */
433*45916cd2Sjpk 				exported = B_TRUE;
434*45916cd2Sjpk 			}
435*45916cd2Sjpk 		}
436*45916cd2Sjpk 		if (mntpt_ref)
437*45916cd2Sjpk 			refstr_rele(mntpt_ref);
438*45916cd2Sjpk 
439*45916cd2Sjpk 		if (!exported) {
440*45916cd2Sjpk 			size_t	plen = strlen(vpath);
441*45916cd2Sjpk 
442*45916cd2Sjpk 			vfs_list_read_lock();
443*45916cd2Sjpk 			nvfs = vfsp->vfs_next;
444*45916cd2Sjpk 			while (nvfs != vfsp) {
445*45916cd2Sjpk 				const char	*rstr;
446*45916cd2Sjpk 				size_t		rlen = 0;
447*45916cd2Sjpk 
448*45916cd2Sjpk 				rstr = refstr_value(nvfs->vfs_resource);
449*45916cd2Sjpk 				if (rstr != NULL)
450*45916cd2Sjpk 					rlen = strlen(rstr);
451*45916cd2Sjpk 
452*45916cd2Sjpk 				/*
453*45916cd2Sjpk 				 * Check for a match: does this vfs correspond
454*45916cd2Sjpk 				 * to our global zone file path?  I.e., check
455*45916cd2Sjpk 				 * if the resource string of this vfs is a
456*45916cd2Sjpk 				 * prefix of our path.
457*45916cd2Sjpk 				 */
458*45916cd2Sjpk 				if ((rlen > 0) && (rlen <= plen) &&
459*45916cd2Sjpk 				    (strncmp(rstr, vpath, rlen) == 0) &&
460*45916cd2Sjpk 				    (vpath[rlen] == '/' ||
461*45916cd2Sjpk 				    vpath[rlen] == '\0')) {
462*45916cd2Sjpk 					/* force admin_low */
463*45916cd2Sjpk 					exported = B_TRUE;
464*45916cd2Sjpk 					break;
465*45916cd2Sjpk 				}
466*45916cd2Sjpk 				nvfs = nvfs->vfs_next;
467*45916cd2Sjpk 			}
468*45916cd2Sjpk 			vfs_list_unlock();
469*45916cd2Sjpk 		}
470*45916cd2Sjpk 
471*45916cd2Sjpk 		if (!exported)
472*45916cd2Sjpk 			goto out_high;
473*45916cd2Sjpk 	}
474*45916cd2Sjpk 
475*45916cd2Sjpk 	if (vfs_is_held)
476*45916cd2Sjpk 		VFS_RELE(vfsp);
477*45916cd2Sjpk 
478*45916cd2Sjpk 	if (resource_ref)
479*45916cd2Sjpk 		refstr_rele(resource_ref);
480*45916cd2Sjpk 
481*45916cd2Sjpk 	/*
482*45916cd2Sjpk 	 * Now that we have the "home" zone for the file, return the slabel
483*45916cd2Sjpk 	 * of that zone.
484*45916cd2Sjpk 	 */
485*45916cd2Sjpk 	zl = zone->zone_slabel;
486*45916cd2Sjpk 	label_hold(zl);
487*45916cd2Sjpk 	zone_rele(zone);
488*45916cd2Sjpk 	return (zl);
489*45916cd2Sjpk 
490*45916cd2Sjpk out_high:
491*45916cd2Sjpk 	if (vfs_is_held)
492*45916cd2Sjpk 		VFS_RELE(vfsp);
493*45916cd2Sjpk 	if (resource_ref)
494*45916cd2Sjpk 		refstr_rele(resource_ref);
495*45916cd2Sjpk 
496*45916cd2Sjpk 	label_hold(l_admin_high);
497*45916cd2Sjpk 	zone_rele(zone);
498*45916cd2Sjpk 	return (l_admin_high);
499*45916cd2Sjpk }
500*45916cd2Sjpk 
501*45916cd2Sjpk static int
502*45916cd2Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp)
503*45916cd2Sjpk {
504*45916cd2Sjpk 	ts_label_t	*tsl;
505*45916cd2Sjpk 	int		error = 0;
506*45916cd2Sjpk 
507*45916cd2Sjpk 	if ((tsl = getflabel(vp)) == NULL)
508*45916cd2Sjpk 		return (EIO);
509*45916cd2Sjpk 
510*45916cd2Sjpk 	if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p,
511*45916cd2Sjpk 	    sizeof (*(label_p))) != 0)
512*45916cd2Sjpk 		error = EFAULT;
513*45916cd2Sjpk 
514*45916cd2Sjpk 	label_rele(tsl);
515*45916cd2Sjpk 	return (error);
516*45916cd2Sjpk }
517*45916cd2Sjpk 
518*45916cd2Sjpk /*
519*45916cd2Sjpk  * fgetlabel(2TSOL) - get file label
520*45916cd2Sjpk  * getlabel(2TSOL) - get file label
521*45916cd2Sjpk  */
522*45916cd2Sjpk int
523*45916cd2Sjpk getlabel(const char *path, bslabel_t *label_p)
524*45916cd2Sjpk {
525*45916cd2Sjpk 	struct		vnode	*vp;
526*45916cd2Sjpk 	char		*spath;
527*45916cd2Sjpk 	int		error;
528*45916cd2Sjpk 
529*45916cd2Sjpk 	/* Sanity check arguments */
530*45916cd2Sjpk 	if (path == NULL)
531*45916cd2Sjpk 		return (set_errno(EINVAL));
532*45916cd2Sjpk 
533*45916cd2Sjpk 	spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
534*45916cd2Sjpk 	if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) {
535*45916cd2Sjpk 		kmem_free(spath, MAXPATHLEN);
536*45916cd2Sjpk 		return (set_errno(error));
537*45916cd2Sjpk 	}
538*45916cd2Sjpk 
539*45916cd2Sjpk 	if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) {
540*45916cd2Sjpk 		kmem_free(spath, MAXPATHLEN);
541*45916cd2Sjpk 		return (set_errno(error));
542*45916cd2Sjpk 	}
543*45916cd2Sjpk 	kmem_free(spath, MAXPATHLEN);
544*45916cd2Sjpk 
545*45916cd2Sjpk 	error = cgetlabel(label_p, vp);
546*45916cd2Sjpk 
547*45916cd2Sjpk 	VN_RELE(vp);
548*45916cd2Sjpk 	if (error != 0)
549*45916cd2Sjpk 		return (set_errno(error));
550*45916cd2Sjpk 	else
551*45916cd2Sjpk 		return (0);
552*45916cd2Sjpk }
553*45916cd2Sjpk 
554*45916cd2Sjpk int
555*45916cd2Sjpk fgetlabel(int fd, bslabel_t *label_p)
556*45916cd2Sjpk {
557*45916cd2Sjpk 	file_t		*fp;
558*45916cd2Sjpk 	int		error;
559*45916cd2Sjpk 
560*45916cd2Sjpk 	if ((fp = getf(fd)) == NULL)
561*45916cd2Sjpk 		return (set_errno(EBADF));
562*45916cd2Sjpk 
563*45916cd2Sjpk 	error = cgetlabel(label_p, fp->f_vnode);
564*45916cd2Sjpk 	releasef(fd);
565*45916cd2Sjpk 
566*45916cd2Sjpk 	if (error != 0)
567*45916cd2Sjpk 		return (set_errno(error));
568*45916cd2Sjpk 	else
569*45916cd2Sjpk 		return (0);
570*45916cd2Sjpk }
571*45916cd2Sjpk 
572*45916cd2Sjpk /*
573*45916cd2Sjpk  * Used by NFSv4 to query label of a pathname
574*45916cd2Sjpk  * component during lookup/access ops.
575*45916cd2Sjpk  */
576*45916cd2Sjpk ts_label_t *
577*45916cd2Sjpk nfs4_getflabel(vnode_t *vp)
578*45916cd2Sjpk {
579*45916cd2Sjpk 	zone_t *zone;
580*45916cd2Sjpk 	ts_label_t *zone_label;
581*45916cd2Sjpk 	char path[MAXNAMELEN];
582*45916cd2Sjpk 	vnode_t *pvp, *tvp;
583*45916cd2Sjpk 
584*45916cd2Sjpk 	mutex_enter(&vp->v_lock);
585*45916cd2Sjpk 	/*
586*45916cd2Sjpk 	 * mount traverse has been done by caller
587*45916cd2Sjpk 	 * before calling this routine.
588*45916cd2Sjpk 	 */
589*45916cd2Sjpk 	ASSERT(!vn_ismntpt(vp));
590*45916cd2Sjpk 	if (vp->v_path != NULL) {
591*45916cd2Sjpk 		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
592*45916cd2Sjpk 		mutex_exit(&vp->v_lock);
593*45916cd2Sjpk 	} else {
594*45916cd2Sjpk 		/*
595*45916cd2Sjpk 		 * v_path not cached. Since we rely on path
596*45916cd2Sjpk 		 * of an obj to get its label, we need to get
597*45916cd2Sjpk 		 * path corresponding to the parent vnode.
598*45916cd2Sjpk 		 */
599*45916cd2Sjpk 		tvp = vp;
600*45916cd2Sjpk 		do {
601*45916cd2Sjpk 			mutex_exit(&tvp->v_lock);
602*45916cd2Sjpk 			if ((pvp = dnlc_reverse_lookup(tvp, path,
603*45916cd2Sjpk 			    sizeof (path))) == NULL)
604*45916cd2Sjpk 				return (NULL);
605*45916cd2Sjpk 			mutex_enter(&pvp->v_lock);
606*45916cd2Sjpk 			tvp = pvp;
607*45916cd2Sjpk 		} while (pvp->v_path == NULL);
608*45916cd2Sjpk 		zone = zone_find_by_any_path(pvp->v_path, B_FALSE);
609*45916cd2Sjpk 		mutex_exit(&pvp->v_lock);
610*45916cd2Sjpk 	}
611*45916cd2Sjpk 	/*
612*45916cd2Sjpk 	 * Caller has verified that the file is either
613*45916cd2Sjpk 	 * exported or visible. So if the path falls in
614*45916cd2Sjpk 	 * global zone, admin_low is returned; otherwise
615*45916cd2Sjpk 	 * the zone's label is returned.
616*45916cd2Sjpk 	 */
617*45916cd2Sjpk 	zone_label = zone->zone_slabel;
618*45916cd2Sjpk 	label_hold(zone_label);
619*45916cd2Sjpk 	zone_rele(zone);
620*45916cd2Sjpk 	return (zone_label);
621*45916cd2Sjpk }
622