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 /* 224448Skp158701 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 231676Sjpk * Use is subject to license terms. 241676Sjpk */ 251676Sjpk 261676Sjpk #pragma ident "%Z%%M% %I% %E% SMI" 271676Sjpk 281676Sjpk #include <sys/types.h> 291676Sjpk #include <sys/param.h> 301676Sjpk #include <sys/cmn_err.h> 311676Sjpk #include <sys/systm.h> 321676Sjpk #include <sys/cred.h> 331676Sjpk #include <sys/modctl.h> 341676Sjpk #include <sys/vfs.h> 351676Sjpk #include <sys/vnode.h> 361676Sjpk #include <sys/tiuser.h> 371676Sjpk #include <sys/kmem.h> 381676Sjpk #include <sys/pathname.h> 391676Sjpk #include <sys/zone.h> 401676Sjpk #include <sys/tsol/label.h> 411676Sjpk #include <sys/tsol/tnet.h> 421676Sjpk #include <sys/fs/lofs_node.h> 431676Sjpk #include <inet/ip6.h> 441676Sjpk #include <rpc/auth.h> 451676Sjpk #include <rpc/clnt.h> 461676Sjpk #include <nfs/nfs.h> 471676Sjpk #include <nfs/nfs4.h> 481676Sjpk #include <nfs/nfs_clnt.h> 491676Sjpk #include <sys/dnlc.h> 501676Sjpk 511676Sjpk 524746Srica int sys_labeling = 0; /* the default is "off" */ 531676Sjpk 541676Sjpk static kmem_cache_t *tslabel_cache; 551676Sjpk ts_label_t *l_admin_low; 561676Sjpk ts_label_t *l_admin_high; 571676Sjpk 581676Sjpk uint32_t default_doi = DEFAULT_DOI; 591676Sjpk 601676Sjpk /* 611676Sjpk * Initialize labels infrastructure. 621676Sjpk * This is called during startup() time (before vfs_mntroot) by thread_init(). 631676Sjpk * It has to be called early so that the is_system_labeled() function returns 641676Sjpk * the right value when called by the networking code on a diskless boot. 651676Sjpk */ 661676Sjpk void 671676Sjpk label_init(void) 681676Sjpk { 691676Sjpk bslabel_t label; 701676Sjpk 711676Sjpk /* 724746Srica * sys_labeling will default to "off" unless it is overridden 734746Srica * in /etc/system. 741676Sjpk */ 751676Sjpk 761676Sjpk tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t), 771676Sjpk 0, NULL, NULL, NULL, NULL, NULL, 0); 781676Sjpk bsllow(&label); 791676Sjpk l_admin_low = labelalloc(&label, default_doi, KM_SLEEP); 801676Sjpk bslhigh(&label); 811676Sjpk l_admin_high = labelalloc(&label, default_doi, KM_SLEEP); 821676Sjpk } 831676Sjpk 841676Sjpk /* 851676Sjpk * Allocate new ts_label_t. 861676Sjpk */ 871676Sjpk ts_label_t * 881676Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag) 891676Sjpk { 901676Sjpk ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 911676Sjpk 921676Sjpk if (lab != NULL) { 931676Sjpk lab->tsl_ref = 1; 941676Sjpk lab->tsl_doi = doi; 954448Skp158701 lab->tsl_flags = 0; 961676Sjpk if (val == NULL) 971676Sjpk bzero(&lab->tsl_label, sizeof (bslabel_t)); 981676Sjpk else 991676Sjpk bcopy(val, &lab->tsl_label, sizeof (bslabel_t)); 1001676Sjpk } 1011676Sjpk return (lab); 1021676Sjpk } 1031676Sjpk 1041676Sjpk /* 1051676Sjpk * Put a hold on a label structure. 1061676Sjpk */ 1071676Sjpk void 1081676Sjpk label_hold(ts_label_t *lab) 1091676Sjpk { 1101676Sjpk atomic_add_32(&lab->tsl_ref, 1); 1111676Sjpk } 1121676Sjpk 1131676Sjpk /* 1141676Sjpk * Release previous hold on a label structure. Free it if refcnt == 0. 1151676Sjpk */ 1161676Sjpk void 1171676Sjpk label_rele(ts_label_t *lab) 1181676Sjpk { 1191676Sjpk if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0) 1201676Sjpk kmem_cache_free(tslabel_cache, lab); 1211676Sjpk } 1221676Sjpk 1231676Sjpk bslabel_t * 1241676Sjpk label2bslabel(ts_label_t *lab) 1251676Sjpk { 1261676Sjpk return (&lab->tsl_label); 1271676Sjpk } 1281676Sjpk 1291676Sjpk 1301676Sjpk uint32_t 1311676Sjpk label2doi(ts_label_t *lab) 1321676Sjpk { 1331676Sjpk return (lab->tsl_doi); 1341676Sjpk } 1351676Sjpk 1361676Sjpk /* 1371676Sjpk * Compare labels. Return 1 if equal, 0 otherwise. 1381676Sjpk */ 1391676Sjpk boolean_t 1401676Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2) 1411676Sjpk { 1421676Sjpk return ((l1->tsl_doi == l2->tsl_doi) && 1431676Sjpk blequal(&l1->tsl_label, &l2->tsl_label)); 1441676Sjpk } 1451676Sjpk 1461676Sjpk /* 1471676Sjpk * There's no protocol today to obtain the label from the server. 1481676Sjpk * So we rely on conventions: zones, zone names, and zone paths 1491676Sjpk * must match across TX servers and their TX clients. Now use 1501676Sjpk * the exported name to find the equivalent local zone and its 1511676Sjpk * label. Caller is responsible for doing a label_rele of the 1521676Sjpk * returned ts_label. 1531676Sjpk */ 1541676Sjpk ts_label_t * 1551676Sjpk getflabel_cipso(vfs_t *vfsp) 1561676Sjpk { 1571676Sjpk zone_t *reszone; 1581676Sjpk zone_t *new_reszone; 1591676Sjpk char *nfspath, *respath; 1601676Sjpk refstr_t *resource_ref; 1611676Sjpk boolean_t treat_abs = B_FALSE; 1621676Sjpk 1631676Sjpk if (vfsp->vfs_resource == NULL) 1641676Sjpk return (NULL); /* error */ 1651676Sjpk resource_ref = vfs_getresource(vfsp); 1661676Sjpk 1671676Sjpk nfspath = (char *)refstr_value(resource_ref); 1681676Sjpk respath = strchr(nfspath, ':'); /* skip server name */ 1691676Sjpk if (respath) 1701676Sjpk respath++; /* skip over ":" */ 1711676Sjpk if (*respath != '/') { 1721676Sjpk /* treat path as absolute but it doesn't have leading '/' */ 1731676Sjpk treat_abs = B_TRUE; 1741676Sjpk } 1751676Sjpk 1761676Sjpk reszone = zone_find_by_any_path(respath, treat_abs); 1771676Sjpk if (reszone == global_zone) { 1781676Sjpk refstr_rele(resource_ref); 1791676Sjpk label_hold(l_admin_low); 1801676Sjpk zone_rele(reszone); 1811676Sjpk return (l_admin_low); 1821676Sjpk } 1831676Sjpk 1841676Sjpk /* 1851676Sjpk * Skip over zonepath (not including "root"), e.g. /zone/internal 1861676Sjpk */ 1871676Sjpk respath += reszone->zone_rootpathlen - 7; 1881676Sjpk if (treat_abs) 1891676Sjpk respath--; /* no leading '/' to skip */ 1901676Sjpk if (strncmp(respath, "/root/", 6) == 0) { 1911676Sjpk /* Check if we now have something like "/zone/public/" */ 1921676Sjpk 1931676Sjpk respath += 5; /* skip "/root" first */ 1941676Sjpk new_reszone = zone_find_by_any_path(respath, B_FALSE); 1951676Sjpk if (new_reszone != global_zone) { 1961676Sjpk zone_rele(reszone); 1971676Sjpk reszone = new_reszone; 1981676Sjpk } else { 1991676Sjpk zone_rele(new_reszone); 2001676Sjpk } 2011676Sjpk } 2021676Sjpk 2031676Sjpk refstr_rele(resource_ref); 2041676Sjpk label_hold(reszone->zone_slabel); 2051676Sjpk zone_rele(reszone); 2061676Sjpk 2071676Sjpk return (reszone->zone_slabel); 2081676Sjpk } 2091676Sjpk 2101676Sjpk static ts_label_t * 2111676Sjpk getflabel_nfs(vfs_t *vfsp) 2121676Sjpk { 2131676Sjpk bslabel_t *server_sl; 2141676Sjpk ts_label_t *srv_label; 2151676Sjpk tsol_tpc_t *tp; 2161676Sjpk int addr_type; 2171676Sjpk void *ipaddr; 2181676Sjpk struct servinfo *svp; 2191676Sjpk struct netbuf *addr; 2201676Sjpk struct knetconfig *knconf; 2211676Sjpk mntinfo_t *mi; 2221676Sjpk 2231676Sjpk mi = VFTOMI(vfsp); 2241676Sjpk svp = mi->mi_curr_serv; 2251676Sjpk addr = &svp->sv_addr; 2261676Sjpk knconf = svp->sv_knconf; 2271676Sjpk 2281676Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) { 2291676Sjpk addr_type = IPV4_VERSION; 2301676Sjpk /* LINTED: following cast to ipaddr is OK */ 2311676Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr; 2321676Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) { 2331676Sjpk addr_type = IPV6_VERSION; 2341676Sjpk /* LINTED: following cast to ipaddr is OK */ 2351676Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr; 2361676Sjpk } else { 2371676Sjpk goto errout; 2381676Sjpk } 2391676Sjpk 2401676Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 2411676Sjpk if (tp == NULL) 2421676Sjpk goto errout; 2431676Sjpk 2441676Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) { 2451676Sjpk TPC_RELE(tp); 2461676Sjpk return (getflabel_cipso(vfsp)); 2471676Sjpk } 2481676Sjpk 2491676Sjpk if (tp->tpc_tp.host_type != UNLABELED) 2501676Sjpk goto errout; 2511676Sjpk 2521676Sjpk server_sl = &tp->tpc_tp.tp_def_label; 2531676Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP); 2541676Sjpk 2551676Sjpk TPC_RELE(tp); 2561676Sjpk 2571676Sjpk return (srv_label); 2581676Sjpk 2591676Sjpk errout: 2601676Sjpk return (NULL); 2611676Sjpk } 2621676Sjpk 2631676Sjpk /* 2641676Sjpk * getflabel - 2651676Sjpk * 2661676Sjpk * Return pointer to the ts_label associated with the specified file, 2671676Sjpk * or returns NULL if error occurs. Caller is responsible for doing 2681676Sjpk * a label_rele of the ts_label. 2691676Sjpk */ 2701676Sjpk ts_label_t * 2711676Sjpk getflabel(vnode_t *vp) 2721676Sjpk { 2731799Sgfaden vfs_t *vfsp, *rvfsp; 2741676Sjpk vnode_t *rvp, *rvp2; 2751676Sjpk zone_t *zone; 2761676Sjpk ts_label_t *zl; 2771676Sjpk boolean_t vfs_is_held = B_FALSE; 2781676Sjpk char vpath[MAXPATHLEN]; 2791676Sjpk 2801676Sjpk ASSERT(vp); 2811799Sgfaden vfsp = vp->v_vfsp; 2821676Sjpk if (vfsp == NULL) 2831676Sjpk return (NULL); 2841676Sjpk 2851799Sgfaden rvp = vp; 2861676Sjpk 2871676Sjpk /* 2881799Sgfaden * Traverse lofs mounts and fattach'es to get the real vnode 2891676Sjpk */ 290*5331Samw if (VOP_REALVP(rvp, &rvp2, NULL) == 0) 2911676Sjpk rvp = rvp2; 2921676Sjpk 2931799Sgfaden rvfsp = rvp->v_vfsp; 2941676Sjpk 2951676Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */ 2961676Sjpk 2971676Sjpk /* Go elsewhere to handle all nfs files. */ 2981676Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0) 2991676Sjpk return (getflabel_nfs(rvfsp)); 3001676Sjpk 3011676Sjpk /* 3021676Sjpk * Fast path, for objects in a labeled zone: everything except 3031676Sjpk * for lofs/nfs will be just the label of that zone. 3041676Sjpk */ 3051676Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) { 3061676Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, 3071676Sjpk "lofs") != 0)) { 3081676Sjpk zone = rvfsp->vfs_zone; 3091676Sjpk zone_hold(zone); 3101676Sjpk goto zone_out; /* return this label */ 3111676Sjpk } 3121676Sjpk } 3131676Sjpk 3141799Sgfaden if (vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred) != 0) { 3151799Sgfaden return (NULL); 3161676Sjpk } 3171676Sjpk 3181676Sjpk /* 3191799Sgfaden * Sanity check - vpath may be weird for some cases, like devices. 3201676Sjpk */ 3211799Sgfaden if (*vpath != '/') { 3221799Sgfaden zone = curproc->p_zone; 3231799Sgfaden zone_hold(zone); 3241799Sgfaden goto zone_out; 3251676Sjpk } 3261676Sjpk 3272194Srica /* 3282194Srica * If a mountpoint exists, hold the vfs while we reference it. 3292194Srica * Otherwise if mountpoint is NULL it should not be held (e.g., 3302194Srica * a hold/release on spec_vfs would result in an attempted free 3312194Srica * and panic.) 3322194Srica */ 3332194Srica if (vfsp->vfs_mntpt != NULL) { 3342194Srica VFS_HOLD(vfsp); 3352194Srica vfs_is_held = B_TRUE; 3362194Srica } 3371676Sjpk 3381799Sgfaden zone = zone_find_by_any_path(vpath, B_FALSE); 3391676Sjpk 3401676Sjpk /* 3411799Sgfaden * If the vnode source zone is properly set to a non-global zone, or 3421676Sjpk * any zone if the mount is R/W, then use the label of that zone. 3431676Sjpk */ 3441676Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0)) 3451676Sjpk goto zone_out; /* return this label */ 3461676Sjpk 3471676Sjpk /* 3481676Sjpk * Otherwise, if we're not in the global zone, use the label of 3491676Sjpk * our zone. 3501676Sjpk */ 3511676Sjpk if ((zone = curproc->p_zone) != global_zone) { 3521676Sjpk zone_hold(zone); 3531676Sjpk goto zone_out; /* return this label */ 3541676Sjpk } 3551676Sjpk 3561676Sjpk /* 3571676Sjpk * We're in the global zone and the mount is R/W ... so the file 3581676Sjpk * may actually be in the global zone -- or in the root of any zone. 3591676Sjpk * Always build our own path for the file, to be sure it's simplified 3601676Sjpk * (i.e., no ".", "..", "//", and so on). 3611676Sjpk */ 3621676Sjpk 3631676Sjpk zone_rele(zone); 3641676Sjpk zone = zone_find_by_any_path(vpath, B_FALSE); 3651676Sjpk 3661676Sjpk zone_out: 3671676Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) { 3681676Sjpk vfs_t *nvfs; 3691676Sjpk boolean_t exported = B_FALSE; 3701676Sjpk refstr_t *mntpt_ref; 3711676Sjpk char *mntpt; 3721676Sjpk 3731676Sjpk /* 3741676Sjpk * File is in the global zone - check whether it's admin_high. 3751676Sjpk * If it's in a filesys that was exported from the global zone, 3761676Sjpk * it's admin_low by definition. Otherwise, if it's in a 3771676Sjpk * filesys that's NOT exported to any zone, it's admin_high. 3781676Sjpk * 3791676Sjpk * And for these files if there wasn't a valid mount resource, 3801676Sjpk * the file must be admin_high (not exported, probably a global 3811676Sjpk * zone device). 3821676Sjpk */ 3831676Sjpk if (!vfs_is_held) 3841676Sjpk goto out_high; 3851676Sjpk 3861676Sjpk mntpt_ref = vfs_getmntpoint(vfsp); 3871676Sjpk mntpt = (char *)refstr_value(mntpt_ref); 3881676Sjpk 3891676Sjpk if ((mntpt != NULL) && (*mntpt == '/')) { 3901676Sjpk zone_t *to_zone; 3911676Sjpk 3921676Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE); 3931676Sjpk zone_rele(to_zone); 3941676Sjpk if (to_zone != global_zone) { 3951676Sjpk /* force admin_low */ 3961676Sjpk exported = B_TRUE; 3971676Sjpk } 3981676Sjpk } 3991676Sjpk if (mntpt_ref) 4001676Sjpk refstr_rele(mntpt_ref); 4011676Sjpk 4021676Sjpk if (!exported) { 4031676Sjpk size_t plen = strlen(vpath); 4041676Sjpk 4051676Sjpk vfs_list_read_lock(); 4061676Sjpk nvfs = vfsp->vfs_next; 4071676Sjpk while (nvfs != vfsp) { 4081676Sjpk const char *rstr; 4091676Sjpk size_t rlen = 0; 4101676Sjpk 4111676Sjpk rstr = refstr_value(nvfs->vfs_resource); 4121676Sjpk if (rstr != NULL) 4131676Sjpk rlen = strlen(rstr); 4141676Sjpk 4151676Sjpk /* 4161676Sjpk * Check for a match: does this vfs correspond 4171676Sjpk * to our global zone file path? I.e., check 4181676Sjpk * if the resource string of this vfs is a 4191676Sjpk * prefix of our path. 4201676Sjpk */ 4211676Sjpk if ((rlen > 0) && (rlen <= plen) && 4221676Sjpk (strncmp(rstr, vpath, rlen) == 0) && 4231676Sjpk (vpath[rlen] == '/' || 4241676Sjpk vpath[rlen] == '\0')) { 4251676Sjpk /* force admin_low */ 4261676Sjpk exported = B_TRUE; 4271676Sjpk break; 4281676Sjpk } 4291676Sjpk nvfs = nvfs->vfs_next; 4301676Sjpk } 4311676Sjpk vfs_list_unlock(); 4321676Sjpk } 4331676Sjpk 4341676Sjpk if (!exported) 4351676Sjpk goto out_high; 4361676Sjpk } 4371676Sjpk 4381676Sjpk if (vfs_is_held) 4391676Sjpk VFS_RELE(vfsp); 4401676Sjpk 4411676Sjpk /* 4421676Sjpk * Now that we have the "home" zone for the file, return the slabel 4431676Sjpk * of that zone. 4441676Sjpk */ 4451676Sjpk zl = zone->zone_slabel; 4461676Sjpk label_hold(zl); 4471676Sjpk zone_rele(zone); 4481676Sjpk return (zl); 4491676Sjpk 4501676Sjpk out_high: 4511676Sjpk if (vfs_is_held) 4521676Sjpk VFS_RELE(vfsp); 4531676Sjpk 4541676Sjpk label_hold(l_admin_high); 4551676Sjpk zone_rele(zone); 4561676Sjpk return (l_admin_high); 4571676Sjpk } 4581676Sjpk 4591676Sjpk static int 4601676Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp) 4611676Sjpk { 4621676Sjpk ts_label_t *tsl; 4631676Sjpk int error = 0; 4641676Sjpk 4651676Sjpk if ((tsl = getflabel(vp)) == NULL) 4661676Sjpk return (EIO); 4671676Sjpk 4681676Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p, 4691676Sjpk sizeof (*(label_p))) != 0) 4701676Sjpk error = EFAULT; 4711676Sjpk 4721676Sjpk label_rele(tsl); 4731676Sjpk return (error); 4741676Sjpk } 4751676Sjpk 4761676Sjpk /* 4771676Sjpk * fgetlabel(2TSOL) - get file label 4781676Sjpk * getlabel(2TSOL) - get file label 4791676Sjpk */ 4801676Sjpk int 4811676Sjpk getlabel(const char *path, bslabel_t *label_p) 4821676Sjpk { 4831676Sjpk struct vnode *vp; 4841676Sjpk char *spath; 4851676Sjpk int error; 4861676Sjpk 4871676Sjpk /* Sanity check arguments */ 4881676Sjpk if (path == NULL) 4891676Sjpk return (set_errno(EINVAL)); 4901676Sjpk 4911676Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4921676Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) { 4931676Sjpk kmem_free(spath, MAXPATHLEN); 4941676Sjpk return (set_errno(error)); 4951676Sjpk } 4961676Sjpk 4971676Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) { 4981676Sjpk kmem_free(spath, MAXPATHLEN); 4991676Sjpk return (set_errno(error)); 5001676Sjpk } 5011676Sjpk kmem_free(spath, MAXPATHLEN); 5021676Sjpk 5031676Sjpk error = cgetlabel(label_p, vp); 5041676Sjpk 5051676Sjpk VN_RELE(vp); 5061676Sjpk if (error != 0) 5071676Sjpk return (set_errno(error)); 5081676Sjpk else 5091676Sjpk return (0); 5101676Sjpk } 5111676Sjpk 5121676Sjpk int 5131676Sjpk fgetlabel(int fd, bslabel_t *label_p) 5141676Sjpk { 5151676Sjpk file_t *fp; 5161676Sjpk int error; 5171676Sjpk 5181676Sjpk if ((fp = getf(fd)) == NULL) 5191676Sjpk return (set_errno(EBADF)); 5201676Sjpk 5211676Sjpk error = cgetlabel(label_p, fp->f_vnode); 5221676Sjpk releasef(fd); 5231676Sjpk 5241676Sjpk if (error != 0) 5251676Sjpk return (set_errno(error)); 5261676Sjpk else 5271676Sjpk return (0); 5281676Sjpk } 5291676Sjpk 5301676Sjpk /* 5314971Sjarrett * Used by NFSv3 and NFSv4 server to query label of 5324971Sjarrett * a pathname component during lookup/access ops. 5331676Sjpk */ 5341676Sjpk ts_label_t * 5354971Sjarrett nfs_getflabel(vnode_t *vp) 5361676Sjpk { 5371676Sjpk zone_t *zone; 5381676Sjpk ts_label_t *zone_label; 5391676Sjpk char path[MAXNAMELEN]; 5401676Sjpk vnode_t *pvp, *tvp; 5411676Sjpk 5421676Sjpk mutex_enter(&vp->v_lock); 5431676Sjpk /* 5441676Sjpk * mount traverse has been done by caller 5451676Sjpk * before calling this routine. 5461676Sjpk */ 5471676Sjpk ASSERT(!vn_ismntpt(vp)); 5481676Sjpk if (vp->v_path != NULL) { 5491676Sjpk zone = zone_find_by_any_path(vp->v_path, B_FALSE); 5501676Sjpk mutex_exit(&vp->v_lock); 5511676Sjpk } else { 5521676Sjpk /* 5531676Sjpk * v_path not cached. Since we rely on path 5541676Sjpk * of an obj to get its label, we need to get 5551676Sjpk * path corresponding to the parent vnode. 5561676Sjpk */ 5571676Sjpk tvp = vp; 5581676Sjpk do { 5591676Sjpk mutex_exit(&tvp->v_lock); 5601676Sjpk if ((pvp = dnlc_reverse_lookup(tvp, path, 5611676Sjpk sizeof (path))) == NULL) 5621676Sjpk return (NULL); 5631676Sjpk mutex_enter(&pvp->v_lock); 5641676Sjpk tvp = pvp; 5651676Sjpk } while (pvp->v_path == NULL); 5661676Sjpk zone = zone_find_by_any_path(pvp->v_path, B_FALSE); 5671676Sjpk mutex_exit(&pvp->v_lock); 5681676Sjpk } 5691676Sjpk /* 5701676Sjpk * Caller has verified that the file is either 5711676Sjpk * exported or visible. So if the path falls in 5721676Sjpk * global zone, admin_low is returned; otherwise 5731676Sjpk * the zone's label is returned. 5741676Sjpk */ 5751676Sjpk zone_label = zone->zone_slabel; 5761676Sjpk label_hold(zone_label); 5771676Sjpk zone_rele(zone); 5781676Sjpk return (zone_label); 5791676Sjpk } 580