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