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 /* 221676Sjpk * Copyright 2006 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 521676Sjpk int sys_labeling = -1; /* initially unset */ 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 /* 721676Sjpk * Use the value of "label_services" within the edition module. 731676Sjpk * If for some reason label_services is not found, this will 741676Sjpk * result in the appropriate default -- "off." 751676Sjpk */ 761676Sjpk if (modgetsymvalue("label_services", B_FALSE) != 0) 771676Sjpk sys_labeling = 1; 781676Sjpk else 791676Sjpk sys_labeling = 0; 801676Sjpk 811676Sjpk tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t), 821676Sjpk 0, NULL, NULL, NULL, NULL, NULL, 0); 831676Sjpk bsllow(&label); 841676Sjpk l_admin_low = labelalloc(&label, default_doi, KM_SLEEP); 851676Sjpk bslhigh(&label); 861676Sjpk l_admin_high = labelalloc(&label, default_doi, KM_SLEEP); 871676Sjpk } 881676Sjpk 891676Sjpk /* 901676Sjpk * Allocate new ts_label_t. 911676Sjpk */ 921676Sjpk ts_label_t * 931676Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag) 941676Sjpk { 951676Sjpk ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 961676Sjpk 971676Sjpk if (lab != NULL) { 981676Sjpk lab->tsl_ref = 1; 991676Sjpk lab->tsl_doi = doi; 1001676Sjpk if (val == NULL) 1011676Sjpk bzero(&lab->tsl_label, sizeof (bslabel_t)); 1021676Sjpk else 1031676Sjpk bcopy(val, &lab->tsl_label, sizeof (bslabel_t)); 1041676Sjpk } 1051676Sjpk return (lab); 1061676Sjpk } 1071676Sjpk 1081676Sjpk /* 1091676Sjpk * Put a hold on a label structure. 1101676Sjpk */ 1111676Sjpk void 1121676Sjpk label_hold(ts_label_t *lab) 1131676Sjpk { 1141676Sjpk atomic_add_32(&lab->tsl_ref, 1); 1151676Sjpk } 1161676Sjpk 1171676Sjpk /* 1181676Sjpk * Release previous hold on a label structure. Free it if refcnt == 0. 1191676Sjpk */ 1201676Sjpk void 1211676Sjpk label_rele(ts_label_t *lab) 1221676Sjpk { 1231676Sjpk if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0) 1241676Sjpk kmem_cache_free(tslabel_cache, lab); 1251676Sjpk } 1261676Sjpk 1271676Sjpk bslabel_t * 1281676Sjpk label2bslabel(ts_label_t *lab) 1291676Sjpk { 1301676Sjpk return (&lab->tsl_label); 1311676Sjpk } 1321676Sjpk 1331676Sjpk 1341676Sjpk uint32_t 1351676Sjpk label2doi(ts_label_t *lab) 1361676Sjpk { 1371676Sjpk return (lab->tsl_doi); 1381676Sjpk } 1391676Sjpk 1401676Sjpk /* 1411676Sjpk * Compare labels. Return 1 if equal, 0 otherwise. 1421676Sjpk */ 1431676Sjpk boolean_t 1441676Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2) 1451676Sjpk { 1461676Sjpk return ((l1->tsl_doi == l2->tsl_doi) && 1471676Sjpk blequal(&l1->tsl_label, &l2->tsl_label)); 1481676Sjpk } 1491676Sjpk 1501676Sjpk /* 1511676Sjpk * There's no protocol today to obtain the label from the server. 1521676Sjpk * So we rely on conventions: zones, zone names, and zone paths 1531676Sjpk * must match across TX servers and their TX clients. Now use 1541676Sjpk * the exported name to find the equivalent local zone and its 1551676Sjpk * label. Caller is responsible for doing a label_rele of the 1561676Sjpk * returned ts_label. 1571676Sjpk */ 1581676Sjpk ts_label_t * 1591676Sjpk getflabel_cipso(vfs_t *vfsp) 1601676Sjpk { 1611676Sjpk zone_t *reszone; 1621676Sjpk zone_t *new_reszone; 1631676Sjpk char *nfspath, *respath; 1641676Sjpk refstr_t *resource_ref; 1651676Sjpk boolean_t treat_abs = B_FALSE; 1661676Sjpk 1671676Sjpk if (vfsp->vfs_resource == NULL) 1681676Sjpk return (NULL); /* error */ 1691676Sjpk resource_ref = vfs_getresource(vfsp); 1701676Sjpk 1711676Sjpk nfspath = (char *)refstr_value(resource_ref); 1721676Sjpk respath = strchr(nfspath, ':'); /* skip server name */ 1731676Sjpk if (respath) 1741676Sjpk respath++; /* skip over ":" */ 1751676Sjpk if (*respath != '/') { 1761676Sjpk /* treat path as absolute but it doesn't have leading '/' */ 1771676Sjpk treat_abs = B_TRUE; 1781676Sjpk } 1791676Sjpk 1801676Sjpk reszone = zone_find_by_any_path(respath, treat_abs); 1811676Sjpk if (reszone == global_zone) { 1821676Sjpk refstr_rele(resource_ref); 1831676Sjpk label_hold(l_admin_low); 1841676Sjpk zone_rele(reszone); 1851676Sjpk return (l_admin_low); 1861676Sjpk } 1871676Sjpk 1881676Sjpk /* 1891676Sjpk * Skip over zonepath (not including "root"), e.g. /zone/internal 1901676Sjpk */ 1911676Sjpk respath += reszone->zone_rootpathlen - 7; 1921676Sjpk if (treat_abs) 1931676Sjpk respath--; /* no leading '/' to skip */ 1941676Sjpk if (strncmp(respath, "/root/", 6) == 0) { 1951676Sjpk /* Check if we now have something like "/zone/public/" */ 1961676Sjpk 1971676Sjpk respath += 5; /* skip "/root" first */ 1981676Sjpk new_reszone = zone_find_by_any_path(respath, B_FALSE); 1991676Sjpk if (new_reszone != global_zone) { 2001676Sjpk zone_rele(reszone); 2011676Sjpk reszone = new_reszone; 2021676Sjpk } else { 2031676Sjpk zone_rele(new_reszone); 2041676Sjpk } 2051676Sjpk } 2061676Sjpk 2071676Sjpk refstr_rele(resource_ref); 2081676Sjpk label_hold(reszone->zone_slabel); 2091676Sjpk zone_rele(reszone); 2101676Sjpk 2111676Sjpk return (reszone->zone_slabel); 2121676Sjpk } 2131676Sjpk 2141676Sjpk static ts_label_t * 2151676Sjpk getflabel_nfs(vfs_t *vfsp) 2161676Sjpk { 2171676Sjpk bslabel_t *server_sl; 2181676Sjpk ts_label_t *srv_label; 2191676Sjpk tsol_tpc_t *tp; 2201676Sjpk int addr_type; 2211676Sjpk void *ipaddr; 2221676Sjpk struct servinfo *svp; 2231676Sjpk struct netbuf *addr; 2241676Sjpk struct knetconfig *knconf; 2251676Sjpk mntinfo_t *mi; 2261676Sjpk 2271676Sjpk mi = VFTOMI(vfsp); 2281676Sjpk svp = mi->mi_curr_serv; 2291676Sjpk addr = &svp->sv_addr; 2301676Sjpk knconf = svp->sv_knconf; 2311676Sjpk 2321676Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) { 2331676Sjpk addr_type = IPV4_VERSION; 2341676Sjpk /* LINTED: following cast to ipaddr is OK */ 2351676Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr; 2361676Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) { 2371676Sjpk addr_type = IPV6_VERSION; 2381676Sjpk /* LINTED: following cast to ipaddr is OK */ 2391676Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr; 2401676Sjpk } else { 2411676Sjpk goto errout; 2421676Sjpk } 2431676Sjpk 2441676Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 2451676Sjpk if (tp == NULL) 2461676Sjpk goto errout; 2471676Sjpk 2481676Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) { 2491676Sjpk TPC_RELE(tp); 2501676Sjpk return (getflabel_cipso(vfsp)); 2511676Sjpk } 2521676Sjpk 2531676Sjpk if (tp->tpc_tp.host_type != UNLABELED) 2541676Sjpk goto errout; 2551676Sjpk 2561676Sjpk server_sl = &tp->tpc_tp.tp_def_label; 2571676Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP); 2581676Sjpk 2591676Sjpk TPC_RELE(tp); 2601676Sjpk 2611676Sjpk return (srv_label); 2621676Sjpk 2631676Sjpk errout: 2641676Sjpk return (NULL); 2651676Sjpk } 2661676Sjpk 2671676Sjpk /* 2681676Sjpk * getflabel - 2691676Sjpk * 2701676Sjpk * Return pointer to the ts_label associated with the specified file, 2711676Sjpk * or returns NULL if error occurs. Caller is responsible for doing 2721676Sjpk * a label_rele of the ts_label. 2731676Sjpk */ 2741676Sjpk ts_label_t * 2751676Sjpk getflabel(vnode_t *vp) 2761676Sjpk { 277*1799Sgfaden vfs_t *vfsp, *rvfsp; 2781676Sjpk vnode_t *rvp, *rvp2; 2791676Sjpk zone_t *zone; 2801676Sjpk ts_label_t *zl; 2811676Sjpk boolean_t vfs_is_held = B_FALSE; 2821676Sjpk char vpath[MAXPATHLEN]; 2831676Sjpk 2841676Sjpk ASSERT(vp); 285*1799Sgfaden vfsp = vp->v_vfsp; 2861676Sjpk if (vfsp == NULL) 2871676Sjpk return (NULL); 2881676Sjpk 289*1799Sgfaden rvp = vp; 2901676Sjpk 2911676Sjpk /* 292*1799Sgfaden * Traverse lofs mounts and fattach'es to get the real vnode 2931676Sjpk */ 294*1799Sgfaden if (VOP_REALVP(rvp, &rvp2) == 0) 2951676Sjpk rvp = rvp2; 2961676Sjpk 297*1799Sgfaden rvfsp = rvp->v_vfsp; 2981676Sjpk 2991676Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */ 3001676Sjpk 3011676Sjpk /* Go elsewhere to handle all nfs files. */ 3021676Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0) 3031676Sjpk return (getflabel_nfs(rvfsp)); 3041676Sjpk 3051676Sjpk /* 3061676Sjpk * Fast path, for objects in a labeled zone: everything except 3071676Sjpk * for lofs/nfs will be just the label of that zone. 3081676Sjpk */ 3091676Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) { 3101676Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, 3111676Sjpk "lofs") != 0)) { 3121676Sjpk zone = rvfsp->vfs_zone; 3131676Sjpk zone_hold(zone); 3141676Sjpk goto zone_out; /* return this label */ 3151676Sjpk } 3161676Sjpk } 3171676Sjpk 318*1799Sgfaden if (vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred) != 0) { 319*1799Sgfaden return (NULL); 3201676Sjpk } 3211676Sjpk 3221676Sjpk /* 323*1799Sgfaden * Sanity check - vpath may be weird for some cases, like devices. 3241676Sjpk */ 325*1799Sgfaden if (*vpath != '/') { 326*1799Sgfaden zone = curproc->p_zone; 327*1799Sgfaden zone_hold(zone); 328*1799Sgfaden goto zone_out; 3291676Sjpk } 3301676Sjpk 3311676Sjpk VFS_HOLD(vfsp); 3321676Sjpk vfs_is_held = B_TRUE; 3331676Sjpk 334*1799Sgfaden zone = zone_find_by_any_path(vpath, B_FALSE); 3351676Sjpk 3361676Sjpk /* 337*1799Sgfaden * If the vnode source zone is properly set to a non-global zone, or 3381676Sjpk * any zone if the mount is R/W, then use the label of that zone. 3391676Sjpk */ 3401676Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0)) 3411676Sjpk goto zone_out; /* return this label */ 3421676Sjpk 3431676Sjpk /* 3441676Sjpk * Otherwise, if we're not in the global zone, use the label of 3451676Sjpk * our zone. 3461676Sjpk */ 3471676Sjpk if ((zone = curproc->p_zone) != global_zone) { 3481676Sjpk zone_hold(zone); 3491676Sjpk goto zone_out; /* return this label */ 3501676Sjpk } 3511676Sjpk 3521676Sjpk /* 3531676Sjpk * We're in the global zone and the mount is R/W ... so the file 3541676Sjpk * may actually be in the global zone -- or in the root of any zone. 3551676Sjpk * Always build our own path for the file, to be sure it's simplified 3561676Sjpk * (i.e., no ".", "..", "//", and so on). 3571676Sjpk */ 3581676Sjpk 3591676Sjpk zone_rele(zone); 3601676Sjpk zone = zone_find_by_any_path(vpath, B_FALSE); 3611676Sjpk 3621676Sjpk zone_out: 3631676Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) { 3641676Sjpk vfs_t *nvfs; 3651676Sjpk boolean_t exported = B_FALSE; 3661676Sjpk refstr_t *mntpt_ref; 3671676Sjpk char *mntpt; 3681676Sjpk 3691676Sjpk /* 3701676Sjpk * File is in the global zone - check whether it's admin_high. 3711676Sjpk * If it's in a filesys that was exported from the global zone, 3721676Sjpk * it's admin_low by definition. Otherwise, if it's in a 3731676Sjpk * filesys that's NOT exported to any zone, it's admin_high. 3741676Sjpk * 3751676Sjpk * And for these files if there wasn't a valid mount resource, 3761676Sjpk * the file must be admin_high (not exported, probably a global 3771676Sjpk * zone device). 3781676Sjpk */ 3791676Sjpk if (!vfs_is_held) 3801676Sjpk goto out_high; 3811676Sjpk 3821676Sjpk mntpt_ref = vfs_getmntpoint(vfsp); 3831676Sjpk mntpt = (char *)refstr_value(mntpt_ref); 3841676Sjpk 3851676Sjpk if ((mntpt != NULL) && (*mntpt == '/')) { 3861676Sjpk zone_t *to_zone; 3871676Sjpk 3881676Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE); 3891676Sjpk zone_rele(to_zone); 3901676Sjpk if (to_zone != global_zone) { 3911676Sjpk /* force admin_low */ 3921676Sjpk exported = B_TRUE; 3931676Sjpk } 3941676Sjpk } 3951676Sjpk if (mntpt_ref) 3961676Sjpk refstr_rele(mntpt_ref); 3971676Sjpk 3981676Sjpk if (!exported) { 3991676Sjpk size_t plen = strlen(vpath); 4001676Sjpk 4011676Sjpk vfs_list_read_lock(); 4021676Sjpk nvfs = vfsp->vfs_next; 4031676Sjpk while (nvfs != vfsp) { 4041676Sjpk const char *rstr; 4051676Sjpk size_t rlen = 0; 4061676Sjpk 4071676Sjpk rstr = refstr_value(nvfs->vfs_resource); 4081676Sjpk if (rstr != NULL) 4091676Sjpk rlen = strlen(rstr); 4101676Sjpk 4111676Sjpk /* 4121676Sjpk * Check for a match: does this vfs correspond 4131676Sjpk * to our global zone file path? I.e., check 4141676Sjpk * if the resource string of this vfs is a 4151676Sjpk * prefix of our path. 4161676Sjpk */ 4171676Sjpk if ((rlen > 0) && (rlen <= plen) && 4181676Sjpk (strncmp(rstr, vpath, rlen) == 0) && 4191676Sjpk (vpath[rlen] == '/' || 4201676Sjpk vpath[rlen] == '\0')) { 4211676Sjpk /* force admin_low */ 4221676Sjpk exported = B_TRUE; 4231676Sjpk break; 4241676Sjpk } 4251676Sjpk nvfs = nvfs->vfs_next; 4261676Sjpk } 4271676Sjpk vfs_list_unlock(); 4281676Sjpk } 4291676Sjpk 4301676Sjpk if (!exported) 4311676Sjpk goto out_high; 4321676Sjpk } 4331676Sjpk 4341676Sjpk if (vfs_is_held) 4351676Sjpk VFS_RELE(vfsp); 4361676Sjpk 4371676Sjpk /* 4381676Sjpk * Now that we have the "home" zone for the file, return the slabel 4391676Sjpk * of that zone. 4401676Sjpk */ 4411676Sjpk zl = zone->zone_slabel; 4421676Sjpk label_hold(zl); 4431676Sjpk zone_rele(zone); 4441676Sjpk return (zl); 4451676Sjpk 4461676Sjpk out_high: 4471676Sjpk if (vfs_is_held) 4481676Sjpk VFS_RELE(vfsp); 4491676Sjpk 4501676Sjpk label_hold(l_admin_high); 4511676Sjpk zone_rele(zone); 4521676Sjpk return (l_admin_high); 4531676Sjpk } 4541676Sjpk 4551676Sjpk static int 4561676Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp) 4571676Sjpk { 4581676Sjpk ts_label_t *tsl; 4591676Sjpk int error = 0; 4601676Sjpk 4611676Sjpk if ((tsl = getflabel(vp)) == NULL) 4621676Sjpk return (EIO); 4631676Sjpk 4641676Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p, 4651676Sjpk sizeof (*(label_p))) != 0) 4661676Sjpk error = EFAULT; 4671676Sjpk 4681676Sjpk label_rele(tsl); 4691676Sjpk return (error); 4701676Sjpk } 4711676Sjpk 4721676Sjpk /* 4731676Sjpk * fgetlabel(2TSOL) - get file label 4741676Sjpk * getlabel(2TSOL) - get file label 4751676Sjpk */ 4761676Sjpk int 4771676Sjpk getlabel(const char *path, bslabel_t *label_p) 4781676Sjpk { 4791676Sjpk struct vnode *vp; 4801676Sjpk char *spath; 4811676Sjpk int error; 4821676Sjpk 4831676Sjpk /* Sanity check arguments */ 4841676Sjpk if (path == NULL) 4851676Sjpk return (set_errno(EINVAL)); 4861676Sjpk 4871676Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4881676Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) { 4891676Sjpk kmem_free(spath, MAXPATHLEN); 4901676Sjpk return (set_errno(error)); 4911676Sjpk } 4921676Sjpk 4931676Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) { 4941676Sjpk kmem_free(spath, MAXPATHLEN); 4951676Sjpk return (set_errno(error)); 4961676Sjpk } 4971676Sjpk kmem_free(spath, MAXPATHLEN); 4981676Sjpk 4991676Sjpk error = cgetlabel(label_p, vp); 5001676Sjpk 5011676Sjpk VN_RELE(vp); 5021676Sjpk if (error != 0) 5031676Sjpk return (set_errno(error)); 5041676Sjpk else 5051676Sjpk return (0); 5061676Sjpk } 5071676Sjpk 5081676Sjpk int 5091676Sjpk fgetlabel(int fd, bslabel_t *label_p) 5101676Sjpk { 5111676Sjpk file_t *fp; 5121676Sjpk int error; 5131676Sjpk 5141676Sjpk if ((fp = getf(fd)) == NULL) 5151676Sjpk return (set_errno(EBADF)); 5161676Sjpk 5171676Sjpk error = cgetlabel(label_p, fp->f_vnode); 5181676Sjpk releasef(fd); 5191676Sjpk 5201676Sjpk if (error != 0) 5211676Sjpk return (set_errno(error)); 5221676Sjpk else 5231676Sjpk return (0); 5241676Sjpk } 5251676Sjpk 5261676Sjpk /* 5271676Sjpk * Used by NFSv4 to query label of a pathname 5281676Sjpk * component during lookup/access ops. 5291676Sjpk */ 5301676Sjpk ts_label_t * 5311676Sjpk nfs4_getflabel(vnode_t *vp) 5321676Sjpk { 5331676Sjpk zone_t *zone; 5341676Sjpk ts_label_t *zone_label; 5351676Sjpk char path[MAXNAMELEN]; 5361676Sjpk vnode_t *pvp, *tvp; 5371676Sjpk 5381676Sjpk mutex_enter(&vp->v_lock); 5391676Sjpk /* 5401676Sjpk * mount traverse has been done by caller 5411676Sjpk * before calling this routine. 5421676Sjpk */ 5431676Sjpk ASSERT(!vn_ismntpt(vp)); 5441676Sjpk if (vp->v_path != NULL) { 5451676Sjpk zone = zone_find_by_any_path(vp->v_path, B_FALSE); 5461676Sjpk mutex_exit(&vp->v_lock); 5471676Sjpk } else { 5481676Sjpk /* 5491676Sjpk * v_path not cached. Since we rely on path 5501676Sjpk * of an obj to get its label, we need to get 5511676Sjpk * path corresponding to the parent vnode. 5521676Sjpk */ 5531676Sjpk tvp = vp; 5541676Sjpk do { 5551676Sjpk mutex_exit(&tvp->v_lock); 5561676Sjpk if ((pvp = dnlc_reverse_lookup(tvp, path, 5571676Sjpk sizeof (path))) == NULL) 5581676Sjpk return (NULL); 5591676Sjpk mutex_enter(&pvp->v_lock); 5601676Sjpk tvp = pvp; 5611676Sjpk } while (pvp->v_path == NULL); 5621676Sjpk zone = zone_find_by_any_path(pvp->v_path, B_FALSE); 5631676Sjpk mutex_exit(&pvp->v_lock); 5641676Sjpk } 5651676Sjpk /* 5661676Sjpk * Caller has verified that the file is either 5671676Sjpk * exported or visible. So if the path falls in 5681676Sjpk * global zone, admin_low is returned; otherwise 5691676Sjpk * the zone's label is returned. 5701676Sjpk */ 5711676Sjpk zone_label = zone->zone_slabel; 5721676Sjpk label_hold(zone_label); 5731676Sjpk zone_rele(zone); 5741676Sjpk return (zone_label); 5751676Sjpk } 576