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 /*
228034149bSRic Aleshire * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2345916cd2Sjpk */
2445916cd2Sjpk
2545916cd2Sjpk #include <sys/types.h>
2645916cd2Sjpk #include <sys/param.h>
2745916cd2Sjpk #include <sys/cmn_err.h>
2845916cd2Sjpk #include <sys/systm.h>
2945916cd2Sjpk #include <sys/cred.h>
3045916cd2Sjpk #include <sys/modctl.h>
3145916cd2Sjpk #include <sys/vfs.h>
3245916cd2Sjpk #include <sys/vnode.h>
3345916cd2Sjpk #include <sys/tiuser.h>
3445916cd2Sjpk #include <sys/kmem.h>
3545916cd2Sjpk #include <sys/pathname.h>
3645916cd2Sjpk #include <sys/zone.h>
3745916cd2Sjpk #include <sys/tsol/label.h>
3845916cd2Sjpk #include <sys/tsol/tnet.h>
3945916cd2Sjpk #include <sys/fs/lofs_node.h>
408034149bSRic Aleshire #include <sys/fs/zfs.h>
418034149bSRic Aleshire #include <sys/dsl_prop.h>
4245916cd2Sjpk #include <inet/ip6.h>
4345916cd2Sjpk #include <rpc/auth.h>
4445916cd2Sjpk #include <rpc/clnt.h>
4545916cd2Sjpk #include <nfs/nfs.h>
4645916cd2Sjpk #include <nfs/nfs4.h>
4745916cd2Sjpk #include <nfs/nfs_clnt.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
label_init(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 *
labelalloc(const bslabel_t * val,uint32_t doi,int flag)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 /*
1035f9878b0Sken Powell - Sun Microsystem * Duplicate an existing ts_label_t to a new one, with only
1045f9878b0Sken Powell - Sun Microsystem * the current reference.
1055f9878b0Sken Powell - Sun Microsystem */
1065f9878b0Sken Powell - Sun Microsystem ts_label_t *
labeldup(const ts_label_t * val,int flag)1075f9878b0Sken Powell - Sun Microsystem labeldup(const ts_label_t *val, int flag)
1085f9878b0Sken Powell - Sun Microsystem {
1095f9878b0Sken Powell - Sun Microsystem ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
1105f9878b0Sken Powell - Sun Microsystem
1115f9878b0Sken Powell - Sun Microsystem if (lab != NULL) {
1125f9878b0Sken Powell - Sun Microsystem bcopy(val, lab, sizeof (ts_label_t));
1135f9878b0Sken Powell - Sun Microsystem lab->tsl_ref = 1;
1145f9878b0Sken Powell - Sun Microsystem }
1155f9878b0Sken Powell - Sun Microsystem return (lab);
1165f9878b0Sken Powell - Sun Microsystem }
1175f9878b0Sken Powell - Sun Microsystem
1185f9878b0Sken Powell - Sun Microsystem /*
11945916cd2Sjpk * Put a hold on a label structure.
12045916cd2Sjpk */
12145916cd2Sjpk void
label_hold(ts_label_t * lab)12245916cd2Sjpk label_hold(ts_label_t *lab)
12345916cd2Sjpk {
124*0d6bb4c6SJosef 'Jeff' Sipek atomic_inc_32(&lab->tsl_ref);
12545916cd2Sjpk }
12645916cd2Sjpk
12745916cd2Sjpk /*
12845916cd2Sjpk * Release previous hold on a label structure. Free it if refcnt == 0.
12945916cd2Sjpk */
13045916cd2Sjpk void
label_rele(ts_label_t * lab)13145916cd2Sjpk label_rele(ts_label_t *lab)
13245916cd2Sjpk {
133*0d6bb4c6SJosef 'Jeff' Sipek if (atomic_dec_32_nv(&lab->tsl_ref) == 0)
13445916cd2Sjpk kmem_cache_free(tslabel_cache, lab);
13545916cd2Sjpk }
13645916cd2Sjpk
13745916cd2Sjpk bslabel_t *
label2bslabel(ts_label_t * lab)13845916cd2Sjpk label2bslabel(ts_label_t *lab)
13945916cd2Sjpk {
14045916cd2Sjpk return (&lab->tsl_label);
14145916cd2Sjpk }
14245916cd2Sjpk
14345916cd2Sjpk
14445916cd2Sjpk uint32_t
label2doi(ts_label_t * lab)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
label_equal(const ts_label_t * l1,const ts_label_t * l2)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 *
getflabel_cipso(vfs_t * vfsp)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
2248034149bSRic Aleshire /*
2258034149bSRic Aleshire * Get the label if any of a zfs filesystem. Get the dataset, then
2268034149bSRic Aleshire * get its mlslabel property, convert as needed, and return it. If
2278034149bSRic Aleshire * there's no mlslabel or it is the default one, return NULL.
2288034149bSRic Aleshire */
2298034149bSRic Aleshire static ts_label_t *
getflabel_zfs(vfs_t * vfsp)2308034149bSRic Aleshire getflabel_zfs(vfs_t *vfsp)
2318034149bSRic Aleshire {
2328034149bSRic Aleshire int error;
2338034149bSRic Aleshire ts_label_t *tsl = NULL;
2348034149bSRic Aleshire refstr_t *resource_ref;
2358034149bSRic Aleshire bslabel_t ds_sl;
2368034149bSRic Aleshire char ds_hexsl[MAXNAMELEN];
2378034149bSRic Aleshire const char *osname;
2388034149bSRic Aleshire
2398034149bSRic Aleshire resource_ref = vfs_getresource(vfsp);
2408034149bSRic Aleshire osname = refstr_value(resource_ref);
2418034149bSRic Aleshire
2428034149bSRic Aleshire error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
2438034149bSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL);
2448034149bSRic Aleshire refstr_rele(resource_ref);
2458034149bSRic Aleshire
2468034149bSRic Aleshire if ((error) || (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0))
2478034149bSRic Aleshire return (NULL);
2488034149bSRic Aleshire if (hexstr_to_label(ds_hexsl, &ds_sl) != 0)
2498034149bSRic Aleshire return (NULL);
2508034149bSRic Aleshire
2518034149bSRic Aleshire tsl = labelalloc(&ds_sl, default_doi, KM_SLEEP);
2528034149bSRic Aleshire return (tsl);
2538034149bSRic Aleshire }
2548034149bSRic Aleshire
25545916cd2Sjpk static ts_label_t *
getflabel_nfs(vfs_t * vfsp)25645916cd2Sjpk getflabel_nfs(vfs_t *vfsp)
25745916cd2Sjpk {
25845916cd2Sjpk bslabel_t *server_sl;
25945916cd2Sjpk ts_label_t *srv_label;
26045916cd2Sjpk tsol_tpc_t *tp;
26145916cd2Sjpk int addr_type;
26245916cd2Sjpk void *ipaddr;
26345916cd2Sjpk struct servinfo *svp;
26445916cd2Sjpk struct netbuf *addr;
26545916cd2Sjpk struct knetconfig *knconf;
26645916cd2Sjpk mntinfo_t *mi;
26745916cd2Sjpk
26845916cd2Sjpk mi = VFTOMI(vfsp);
26945916cd2Sjpk svp = mi->mi_curr_serv;
27045916cd2Sjpk addr = &svp->sv_addr;
27145916cd2Sjpk knconf = svp->sv_knconf;
27245916cd2Sjpk
27345916cd2Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) {
27445916cd2Sjpk addr_type = IPV4_VERSION;
27545916cd2Sjpk /* LINTED: following cast to ipaddr is OK */
27645916cd2Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr;
27745916cd2Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) {
27845916cd2Sjpk addr_type = IPV6_VERSION;
27945916cd2Sjpk /* LINTED: following cast to ipaddr is OK */
28045916cd2Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr;
28145916cd2Sjpk } else {
28245916cd2Sjpk goto errout;
28345916cd2Sjpk }
28445916cd2Sjpk
28545916cd2Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE);
28645916cd2Sjpk if (tp == NULL)
28745916cd2Sjpk goto errout;
28845916cd2Sjpk
28945916cd2Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) {
29045916cd2Sjpk TPC_RELE(tp);
29145916cd2Sjpk return (getflabel_cipso(vfsp));
29245916cd2Sjpk }
29345916cd2Sjpk
29445916cd2Sjpk if (tp->tpc_tp.host_type != UNLABELED)
29545916cd2Sjpk goto errout;
29645916cd2Sjpk
29745916cd2Sjpk server_sl = &tp->tpc_tp.tp_def_label;
29845916cd2Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP);
29945916cd2Sjpk
30045916cd2Sjpk TPC_RELE(tp);
30145916cd2Sjpk
30245916cd2Sjpk return (srv_label);
30345916cd2Sjpk
30445916cd2Sjpk errout:
30545916cd2Sjpk return (NULL);
30645916cd2Sjpk }
30745916cd2Sjpk
30845916cd2Sjpk /*
30945916cd2Sjpk * getflabel -
31045916cd2Sjpk *
31145916cd2Sjpk * Return pointer to the ts_label associated with the specified file,
31245916cd2Sjpk * or returns NULL if error occurs. Caller is responsible for doing
31345916cd2Sjpk * a label_rele of the ts_label.
31445916cd2Sjpk */
31545916cd2Sjpk ts_label_t *
getflabel(vnode_t * vp)31645916cd2Sjpk getflabel(vnode_t *vp)
31745916cd2Sjpk {
3186fc927dcSgfaden vfs_t *vfsp, *rvfsp;
31945916cd2Sjpk vnode_t *rvp, *rvp2;
32045916cd2Sjpk zone_t *zone;
32145916cd2Sjpk ts_label_t *zl;
322770915ebSRic Aleshire int err;
32345916cd2Sjpk boolean_t vfs_is_held = B_FALSE;
32445916cd2Sjpk char vpath[MAXPATHLEN];
32545916cd2Sjpk
32645916cd2Sjpk ASSERT(vp);
3276fc927dcSgfaden vfsp = vp->v_vfsp;
32845916cd2Sjpk if (vfsp == NULL)
32945916cd2Sjpk return (NULL);
33045916cd2Sjpk
3316fc927dcSgfaden rvp = vp;
33245916cd2Sjpk
33345916cd2Sjpk /*
3346fc927dcSgfaden * Traverse lofs mounts and fattach'es to get the real vnode
33545916cd2Sjpk */
336da6c28aaSamw if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
33745916cd2Sjpk rvp = rvp2;
33845916cd2Sjpk
3396fc927dcSgfaden rvfsp = rvp->v_vfsp;
34045916cd2Sjpk
34145916cd2Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */
34245916cd2Sjpk
34345916cd2Sjpk /* Go elsewhere to handle all nfs files. */
34445916cd2Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
34545916cd2Sjpk return (getflabel_nfs(rvfsp));
34645916cd2Sjpk
34745916cd2Sjpk /*
34845916cd2Sjpk * Fast path, for objects in a labeled zone: everything except
34945916cd2Sjpk * for lofs/nfs will be just the label of that zone.
35045916cd2Sjpk */
35145916cd2Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
35245916cd2Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
35345916cd2Sjpk "lofs") != 0)) {
35445916cd2Sjpk zone = rvfsp->vfs_zone;
35545916cd2Sjpk zone_hold(zone);
35645916cd2Sjpk goto zone_out; /* return this label */
35745916cd2Sjpk }
35845916cd2Sjpk }
35945916cd2Sjpk
36045916cd2Sjpk /*
361770915ebSRic Aleshire * Get the vnode path -- it may be missing or weird for some
362770915ebSRic Aleshire * cases, like devices. In those cases use the label of the
363770915ebSRic Aleshire * current zone.
36445916cd2Sjpk */
365770915ebSRic Aleshire err = vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred);
366770915ebSRic Aleshire if ((err != 0) || (*vpath != '/')) {
36745916cd2Sjpk zone = curproc->p_zone;
36845916cd2Sjpk zone_hold(zone);
36945916cd2Sjpk goto zone_out;
37045916cd2Sjpk }
37145916cd2Sjpk
372afed4af4Srica /*
3738034149bSRic Aleshire * For zfs filesystem, return the explicit label property if a
3748034149bSRic Aleshire * meaningful one exists.
3758034149bSRic Aleshire */
3768034149bSRic Aleshire if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "zfs", 3) == 0) {
3778034149bSRic Aleshire ts_label_t *tsl;
3788034149bSRic Aleshire
3798034149bSRic Aleshire tsl = getflabel_zfs(rvfsp);
3808034149bSRic Aleshire
3818034149bSRic Aleshire /* if label found, return it, otherwise continue... */
3828034149bSRic Aleshire if (tsl != NULL)
3838034149bSRic Aleshire return (tsl);
3848034149bSRic Aleshire }
3858034149bSRic Aleshire
3868034149bSRic Aleshire /*
387afed4af4Srica * If a mountpoint exists, hold the vfs while we reference it.
388afed4af4Srica * Otherwise if mountpoint is NULL it should not be held (e.g.,
389afed4af4Srica * a hold/release on spec_vfs would result in an attempted free
390afed4af4Srica * and panic.)
391afed4af4Srica */
392afed4af4Srica if (vfsp->vfs_mntpt != NULL) {
39345916cd2Sjpk VFS_HOLD(vfsp);
39445916cd2Sjpk vfs_is_held = B_TRUE;
395afed4af4Srica }
39645916cd2Sjpk
3976fc927dcSgfaden zone = zone_find_by_any_path(vpath, B_FALSE);
39845916cd2Sjpk
39945916cd2Sjpk /*
4006fc927dcSgfaden * If the vnode source zone is properly set to a non-global zone, or
40145916cd2Sjpk * any zone if the mount is R/W, then use the label of that zone.
40245916cd2Sjpk */
40345916cd2Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
40445916cd2Sjpk goto zone_out; /* return this label */
40545916cd2Sjpk
40645916cd2Sjpk /*
40745916cd2Sjpk * Otherwise, if we're not in the global zone, use the label of
40845916cd2Sjpk * our zone.
40945916cd2Sjpk */
41045916cd2Sjpk if ((zone = curproc->p_zone) != global_zone) {
41145916cd2Sjpk zone_hold(zone);
41245916cd2Sjpk goto zone_out; /* return this label */
41345916cd2Sjpk }
41445916cd2Sjpk
41545916cd2Sjpk /*
41645916cd2Sjpk * We're in the global zone and the mount is R/W ... so the file
41745916cd2Sjpk * may actually be in the global zone -- or in the root of any zone.
41845916cd2Sjpk * Always build our own path for the file, to be sure it's simplified
41945916cd2Sjpk * (i.e., no ".", "..", "//", and so on).
42045916cd2Sjpk */
42145916cd2Sjpk
42245916cd2Sjpk zone_rele(zone);
42345916cd2Sjpk zone = zone_find_by_any_path(vpath, B_FALSE);
42445916cd2Sjpk
42545916cd2Sjpk zone_out:
42645916cd2Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
42745916cd2Sjpk vfs_t *nvfs;
42845916cd2Sjpk boolean_t exported = B_FALSE;
42945916cd2Sjpk refstr_t *mntpt_ref;
43045916cd2Sjpk char *mntpt;
43145916cd2Sjpk
43245916cd2Sjpk /*
43345916cd2Sjpk * File is in the global zone - check whether it's admin_high.
43445916cd2Sjpk * If it's in a filesys that was exported from the global zone,
43545916cd2Sjpk * it's admin_low by definition. Otherwise, if it's in a
43645916cd2Sjpk * filesys that's NOT exported to any zone, it's admin_high.
43745916cd2Sjpk *
43845916cd2Sjpk * And for these files if there wasn't a valid mount resource,
43945916cd2Sjpk * the file must be admin_high (not exported, probably a global
44045916cd2Sjpk * zone device).
44145916cd2Sjpk */
44245916cd2Sjpk if (!vfs_is_held)
44345916cd2Sjpk goto out_high;
44445916cd2Sjpk
44545916cd2Sjpk mntpt_ref = vfs_getmntpoint(vfsp);
44645916cd2Sjpk mntpt = (char *)refstr_value(mntpt_ref);
44745916cd2Sjpk
44845916cd2Sjpk if ((mntpt != NULL) && (*mntpt == '/')) {
44945916cd2Sjpk zone_t *to_zone;
45045916cd2Sjpk
45145916cd2Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE);
45245916cd2Sjpk zone_rele(to_zone);
45345916cd2Sjpk if (to_zone != global_zone) {
45445916cd2Sjpk /* force admin_low */
45545916cd2Sjpk exported = B_TRUE;
45645916cd2Sjpk }
45745916cd2Sjpk }
45845916cd2Sjpk if (mntpt_ref)
45945916cd2Sjpk refstr_rele(mntpt_ref);
46045916cd2Sjpk
46145916cd2Sjpk if (!exported) {
46245916cd2Sjpk size_t plen = strlen(vpath);
46345916cd2Sjpk
46445916cd2Sjpk vfs_list_read_lock();
46545916cd2Sjpk nvfs = vfsp->vfs_next;
46645916cd2Sjpk while (nvfs != vfsp) {
46745916cd2Sjpk const char *rstr;
46845916cd2Sjpk size_t rlen = 0;
46945916cd2Sjpk
4708034149bSRic Aleshire /*
4718034149bSRic Aleshire * Skip checking this vfs if it's not lofs
4728034149bSRic Aleshire * (the only way to export from the global
4738034149bSRic Aleshire * zone to a zone).
4748034149bSRic Aleshire */
4758034149bSRic Aleshire if (strncmp(vfssw[nvfs->vfs_fstype].vsw_name,
4768034149bSRic Aleshire "lofs", 4) != 0) {
4778034149bSRic Aleshire nvfs = nvfs->vfs_next;
4788034149bSRic Aleshire continue;
4798034149bSRic Aleshire }
4808034149bSRic Aleshire
48145916cd2Sjpk rstr = refstr_value(nvfs->vfs_resource);
48245916cd2Sjpk if (rstr != NULL)
48345916cd2Sjpk rlen = strlen(rstr);
48445916cd2Sjpk
48545916cd2Sjpk /*
48645916cd2Sjpk * Check for a match: does this vfs correspond
48745916cd2Sjpk * to our global zone file path? I.e., check
48845916cd2Sjpk * if the resource string of this vfs is a
48945916cd2Sjpk * prefix of our path.
49045916cd2Sjpk */
49145916cd2Sjpk if ((rlen > 0) && (rlen <= plen) &&
49245916cd2Sjpk (strncmp(rstr, vpath, rlen) == 0) &&
49345916cd2Sjpk (vpath[rlen] == '/' ||
49445916cd2Sjpk vpath[rlen] == '\0')) {
49545916cd2Sjpk /* force admin_low */
49645916cd2Sjpk exported = B_TRUE;
49745916cd2Sjpk break;
49845916cd2Sjpk }
49945916cd2Sjpk nvfs = nvfs->vfs_next;
50045916cd2Sjpk }
50145916cd2Sjpk vfs_list_unlock();
50245916cd2Sjpk }
50345916cd2Sjpk
50445916cd2Sjpk if (!exported)
50545916cd2Sjpk goto out_high;
50645916cd2Sjpk }
50745916cd2Sjpk
50845916cd2Sjpk if (vfs_is_held)
50945916cd2Sjpk VFS_RELE(vfsp);
51045916cd2Sjpk
51145916cd2Sjpk /*
51245916cd2Sjpk * Now that we have the "home" zone for the file, return the slabel
51345916cd2Sjpk * of that zone.
51445916cd2Sjpk */
51545916cd2Sjpk zl = zone->zone_slabel;
51645916cd2Sjpk label_hold(zl);
51745916cd2Sjpk zone_rele(zone);
51845916cd2Sjpk return (zl);
51945916cd2Sjpk
52045916cd2Sjpk out_high:
52145916cd2Sjpk if (vfs_is_held)
52245916cd2Sjpk VFS_RELE(vfsp);
52345916cd2Sjpk
52445916cd2Sjpk label_hold(l_admin_high);
52545916cd2Sjpk zone_rele(zone);
52645916cd2Sjpk return (l_admin_high);
52745916cd2Sjpk }
52845916cd2Sjpk
52945916cd2Sjpk static int
cgetlabel(bslabel_t * label_p,vnode_t * vp)53045916cd2Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp)
53145916cd2Sjpk {
53245916cd2Sjpk ts_label_t *tsl;
53345916cd2Sjpk int error = 0;
53445916cd2Sjpk
53545916cd2Sjpk if ((tsl = getflabel(vp)) == NULL)
53645916cd2Sjpk return (EIO);
53745916cd2Sjpk
53845916cd2Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p,
53945916cd2Sjpk sizeof (*(label_p))) != 0)
54045916cd2Sjpk error = EFAULT;
54145916cd2Sjpk
54245916cd2Sjpk label_rele(tsl);
54345916cd2Sjpk return (error);
54445916cd2Sjpk }
54545916cd2Sjpk
54645916cd2Sjpk /*
54745916cd2Sjpk * fgetlabel(2TSOL) - get file label
54845916cd2Sjpk * getlabel(2TSOL) - get file label
54945916cd2Sjpk */
55045916cd2Sjpk int
getlabel(const char * path,bslabel_t * label_p)55145916cd2Sjpk getlabel(const char *path, bslabel_t *label_p)
55245916cd2Sjpk {
55345916cd2Sjpk struct vnode *vp;
55445916cd2Sjpk char *spath;
55545916cd2Sjpk int error;
55645916cd2Sjpk
55745916cd2Sjpk /* Sanity check arguments */
55845916cd2Sjpk if (path == NULL)
55945916cd2Sjpk return (set_errno(EINVAL));
56045916cd2Sjpk
56145916cd2Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
56245916cd2Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) {
56345916cd2Sjpk kmem_free(spath, MAXPATHLEN);
56445916cd2Sjpk return (set_errno(error));
56545916cd2Sjpk }
56645916cd2Sjpk
56745916cd2Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) {
56845916cd2Sjpk kmem_free(spath, MAXPATHLEN);
56945916cd2Sjpk return (set_errno(error));
57045916cd2Sjpk }
57145916cd2Sjpk kmem_free(spath, MAXPATHLEN);
57245916cd2Sjpk
57345916cd2Sjpk error = cgetlabel(label_p, vp);
57445916cd2Sjpk
57545916cd2Sjpk VN_RELE(vp);
57645916cd2Sjpk if (error != 0)
57745916cd2Sjpk return (set_errno(error));
57845916cd2Sjpk else
57945916cd2Sjpk return (0);
58045916cd2Sjpk }
58145916cd2Sjpk
58245916cd2Sjpk int
fgetlabel(int fd,bslabel_t * label_p)58345916cd2Sjpk fgetlabel(int fd, bslabel_t *label_p)
58445916cd2Sjpk {
58545916cd2Sjpk file_t *fp;
58645916cd2Sjpk int error;
58745916cd2Sjpk
58845916cd2Sjpk if ((fp = getf(fd)) == NULL)
58945916cd2Sjpk return (set_errno(EBADF));
59045916cd2Sjpk
59145916cd2Sjpk error = cgetlabel(label_p, fp->f_vnode);
59245916cd2Sjpk releasef(fd);
59345916cd2Sjpk
59445916cd2Sjpk if (error != 0)
59545916cd2Sjpk return (set_errno(error));
59645916cd2Sjpk else
59745916cd2Sjpk return (0);
59845916cd2Sjpk }
599