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 /* 22*9710SKen.Powell@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231676Sjpk * Use is subject to license terms. 241676Sjpk */ 251676Sjpk 261676Sjpk #include <sys/types.h> 271676Sjpk #include <sys/param.h> 281676Sjpk #include <sys/cmn_err.h> 291676Sjpk #include <sys/systm.h> 301676Sjpk #include <sys/cred.h> 311676Sjpk #include <sys/modctl.h> 321676Sjpk #include <sys/vfs.h> 331676Sjpk #include <sys/vnode.h> 341676Sjpk #include <sys/tiuser.h> 351676Sjpk #include <sys/kmem.h> 361676Sjpk #include <sys/pathname.h> 371676Sjpk #include <sys/zone.h> 381676Sjpk #include <sys/tsol/label.h> 391676Sjpk #include <sys/tsol/tnet.h> 401676Sjpk #include <sys/fs/lofs_node.h> 411676Sjpk #include <inet/ip6.h> 421676Sjpk #include <rpc/auth.h> 431676Sjpk #include <rpc/clnt.h> 441676Sjpk #include <nfs/nfs.h> 451676Sjpk #include <nfs/nfs4.h> 461676Sjpk #include <nfs/nfs_clnt.h> 471676Sjpk #include <sys/dnlc.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 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 * 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 /* 103*9710SKen.Powell@Sun.COM * Duplicate an existing ts_label_t to a new one, with only 104*9710SKen.Powell@Sun.COM * the current reference. 105*9710SKen.Powell@Sun.COM */ 106*9710SKen.Powell@Sun.COM ts_label_t * 107*9710SKen.Powell@Sun.COM labeldup(const ts_label_t *val, int flag) 108*9710SKen.Powell@Sun.COM { 109*9710SKen.Powell@Sun.COM ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 110*9710SKen.Powell@Sun.COM 111*9710SKen.Powell@Sun.COM if (lab != NULL) { 112*9710SKen.Powell@Sun.COM bcopy(val, lab, sizeof (ts_label_t)); 113*9710SKen.Powell@Sun.COM lab->tsl_ref = 1; 114*9710SKen.Powell@Sun.COM } 115*9710SKen.Powell@Sun.COM return (lab); 116*9710SKen.Powell@Sun.COM } 117*9710SKen.Powell@Sun.COM 118*9710SKen.Powell@Sun.COM /* 1191676Sjpk * Put a hold on a label structure. 1201676Sjpk */ 1211676Sjpk void 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 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 * 1381676Sjpk label2bslabel(ts_label_t *lab) 1391676Sjpk { 1401676Sjpk return (&lab->tsl_label); 1411676Sjpk } 1421676Sjpk 1431676Sjpk 1441676Sjpk uint32_t 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 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 * 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 2241676Sjpk static ts_label_t * 2251676Sjpk getflabel_nfs(vfs_t *vfsp) 2261676Sjpk { 2271676Sjpk bslabel_t *server_sl; 2281676Sjpk ts_label_t *srv_label; 2291676Sjpk tsol_tpc_t *tp; 2301676Sjpk int addr_type; 2311676Sjpk void *ipaddr; 2321676Sjpk struct servinfo *svp; 2331676Sjpk struct netbuf *addr; 2341676Sjpk struct knetconfig *knconf; 2351676Sjpk mntinfo_t *mi; 2361676Sjpk 2371676Sjpk mi = VFTOMI(vfsp); 2381676Sjpk svp = mi->mi_curr_serv; 2391676Sjpk addr = &svp->sv_addr; 2401676Sjpk knconf = svp->sv_knconf; 2411676Sjpk 2421676Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) { 2431676Sjpk addr_type = IPV4_VERSION; 2441676Sjpk /* LINTED: following cast to ipaddr is OK */ 2451676Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr; 2461676Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) { 2471676Sjpk addr_type = IPV6_VERSION; 2481676Sjpk /* LINTED: following cast to ipaddr is OK */ 2491676Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr; 2501676Sjpk } else { 2511676Sjpk goto errout; 2521676Sjpk } 2531676Sjpk 2541676Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 2551676Sjpk if (tp == NULL) 2561676Sjpk goto errout; 2571676Sjpk 2581676Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) { 2591676Sjpk TPC_RELE(tp); 2601676Sjpk return (getflabel_cipso(vfsp)); 2611676Sjpk } 2621676Sjpk 2631676Sjpk if (tp->tpc_tp.host_type != UNLABELED) 2641676Sjpk goto errout; 2651676Sjpk 2661676Sjpk server_sl = &tp->tpc_tp.tp_def_label; 2671676Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP); 2681676Sjpk 2691676Sjpk TPC_RELE(tp); 2701676Sjpk 2711676Sjpk return (srv_label); 2721676Sjpk 2731676Sjpk errout: 2741676Sjpk return (NULL); 2751676Sjpk } 2761676Sjpk 2771676Sjpk /* 2781676Sjpk * getflabel - 2791676Sjpk * 2801676Sjpk * Return pointer to the ts_label associated with the specified file, 2811676Sjpk * or returns NULL if error occurs. Caller is responsible for doing 2821676Sjpk * a label_rele of the ts_label. 2831676Sjpk */ 2841676Sjpk ts_label_t * 2851676Sjpk getflabel(vnode_t *vp) 2861676Sjpk { 2871799Sgfaden vfs_t *vfsp, *rvfsp; 2881676Sjpk vnode_t *rvp, *rvp2; 2891676Sjpk zone_t *zone; 2901676Sjpk ts_label_t *zl; 2911676Sjpk boolean_t vfs_is_held = B_FALSE; 2921676Sjpk char vpath[MAXPATHLEN]; 2931676Sjpk 2941676Sjpk ASSERT(vp); 2951799Sgfaden vfsp = vp->v_vfsp; 2961676Sjpk if (vfsp == NULL) 2971676Sjpk return (NULL); 2981676Sjpk 2991799Sgfaden rvp = vp; 3001676Sjpk 3011676Sjpk /* 3021799Sgfaden * Traverse lofs mounts and fattach'es to get the real vnode 3031676Sjpk */ 3045331Samw if (VOP_REALVP(rvp, &rvp2, NULL) == 0) 3051676Sjpk rvp = rvp2; 3061676Sjpk 3071799Sgfaden rvfsp = rvp->v_vfsp; 3081676Sjpk 3091676Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */ 3101676Sjpk 3111676Sjpk /* Go elsewhere to handle all nfs files. */ 3121676Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0) 3131676Sjpk return (getflabel_nfs(rvfsp)); 3141676Sjpk 3151676Sjpk /* 3161676Sjpk * Fast path, for objects in a labeled zone: everything except 3171676Sjpk * for lofs/nfs will be just the label of that zone. 3181676Sjpk */ 3191676Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) { 3201676Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, 3211676Sjpk "lofs") != 0)) { 3221676Sjpk zone = rvfsp->vfs_zone; 3231676Sjpk zone_hold(zone); 3241676Sjpk goto zone_out; /* return this label */ 3251676Sjpk } 3261676Sjpk } 3271676Sjpk 3281799Sgfaden if (vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred) != 0) { 3291799Sgfaden return (NULL); 3301676Sjpk } 3311676Sjpk 3321676Sjpk /* 3331799Sgfaden * Sanity check - vpath may be weird for some cases, like devices. 3341676Sjpk */ 3351799Sgfaden if (*vpath != '/') { 3361799Sgfaden zone = curproc->p_zone; 3371799Sgfaden zone_hold(zone); 3381799Sgfaden goto zone_out; 3391676Sjpk } 3401676Sjpk 3412194Srica /* 3422194Srica * If a mountpoint exists, hold the vfs while we reference it. 3432194Srica * Otherwise if mountpoint is NULL it should not be held (e.g., 3442194Srica * a hold/release on spec_vfs would result in an attempted free 3452194Srica * and panic.) 3462194Srica */ 3472194Srica if (vfsp->vfs_mntpt != NULL) { 3482194Srica VFS_HOLD(vfsp); 3492194Srica vfs_is_held = B_TRUE; 3502194Srica } 3511676Sjpk 3521799Sgfaden zone = zone_find_by_any_path(vpath, B_FALSE); 3531676Sjpk 3541676Sjpk /* 3551799Sgfaden * If the vnode source zone is properly set to a non-global zone, or 3561676Sjpk * any zone if the mount is R/W, then use the label of that zone. 3571676Sjpk */ 3581676Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0)) 3591676Sjpk goto zone_out; /* return this label */ 3601676Sjpk 3611676Sjpk /* 3621676Sjpk * Otherwise, if we're not in the global zone, use the label of 3631676Sjpk * our zone. 3641676Sjpk */ 3651676Sjpk if ((zone = curproc->p_zone) != global_zone) { 3661676Sjpk zone_hold(zone); 3671676Sjpk goto zone_out; /* return this label */ 3681676Sjpk } 3691676Sjpk 3701676Sjpk /* 3711676Sjpk * We're in the global zone and the mount is R/W ... so the file 3721676Sjpk * may actually be in the global zone -- or in the root of any zone. 3731676Sjpk * Always build our own path for the file, to be sure it's simplified 3741676Sjpk * (i.e., no ".", "..", "//", and so on). 3751676Sjpk */ 3761676Sjpk 3771676Sjpk zone_rele(zone); 3781676Sjpk zone = zone_find_by_any_path(vpath, B_FALSE); 3791676Sjpk 3801676Sjpk zone_out: 3811676Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) { 3821676Sjpk vfs_t *nvfs; 3831676Sjpk boolean_t exported = B_FALSE; 3841676Sjpk refstr_t *mntpt_ref; 3851676Sjpk char *mntpt; 3861676Sjpk 3871676Sjpk /* 3881676Sjpk * File is in the global zone - check whether it's admin_high. 3891676Sjpk * If it's in a filesys that was exported from the global zone, 3901676Sjpk * it's admin_low by definition. Otherwise, if it's in a 3911676Sjpk * filesys that's NOT exported to any zone, it's admin_high. 3921676Sjpk * 3931676Sjpk * And for these files if there wasn't a valid mount resource, 3941676Sjpk * the file must be admin_high (not exported, probably a global 3951676Sjpk * zone device). 3961676Sjpk */ 3971676Sjpk if (!vfs_is_held) 3981676Sjpk goto out_high; 3991676Sjpk 4001676Sjpk mntpt_ref = vfs_getmntpoint(vfsp); 4011676Sjpk mntpt = (char *)refstr_value(mntpt_ref); 4021676Sjpk 4031676Sjpk if ((mntpt != NULL) && (*mntpt == '/')) { 4041676Sjpk zone_t *to_zone; 4051676Sjpk 4061676Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE); 4071676Sjpk zone_rele(to_zone); 4081676Sjpk if (to_zone != global_zone) { 4091676Sjpk /* force admin_low */ 4101676Sjpk exported = B_TRUE; 4111676Sjpk } 4121676Sjpk } 4131676Sjpk if (mntpt_ref) 4141676Sjpk refstr_rele(mntpt_ref); 4151676Sjpk 4161676Sjpk if (!exported) { 4171676Sjpk size_t plen = strlen(vpath); 4181676Sjpk 4191676Sjpk vfs_list_read_lock(); 4201676Sjpk nvfs = vfsp->vfs_next; 4211676Sjpk while (nvfs != vfsp) { 4221676Sjpk const char *rstr; 4231676Sjpk size_t rlen = 0; 4241676Sjpk 4251676Sjpk rstr = refstr_value(nvfs->vfs_resource); 4261676Sjpk if (rstr != NULL) 4271676Sjpk rlen = strlen(rstr); 4281676Sjpk 4291676Sjpk /* 4301676Sjpk * Check for a match: does this vfs correspond 4311676Sjpk * to our global zone file path? I.e., check 4321676Sjpk * if the resource string of this vfs is a 4331676Sjpk * prefix of our path. 4341676Sjpk */ 4351676Sjpk if ((rlen > 0) && (rlen <= plen) && 4361676Sjpk (strncmp(rstr, vpath, rlen) == 0) && 4371676Sjpk (vpath[rlen] == '/' || 4381676Sjpk vpath[rlen] == '\0')) { 4391676Sjpk /* force admin_low */ 4401676Sjpk exported = B_TRUE; 4411676Sjpk break; 4421676Sjpk } 4431676Sjpk nvfs = nvfs->vfs_next; 4441676Sjpk } 4451676Sjpk vfs_list_unlock(); 4461676Sjpk } 4471676Sjpk 4481676Sjpk if (!exported) 4491676Sjpk goto out_high; 4501676Sjpk } 4511676Sjpk 4521676Sjpk if (vfs_is_held) 4531676Sjpk VFS_RELE(vfsp); 4541676Sjpk 4551676Sjpk /* 4561676Sjpk * Now that we have the "home" zone for the file, return the slabel 4571676Sjpk * of that zone. 4581676Sjpk */ 4591676Sjpk zl = zone->zone_slabel; 4601676Sjpk label_hold(zl); 4611676Sjpk zone_rele(zone); 4621676Sjpk return (zl); 4631676Sjpk 4641676Sjpk out_high: 4651676Sjpk if (vfs_is_held) 4661676Sjpk VFS_RELE(vfsp); 4671676Sjpk 4681676Sjpk label_hold(l_admin_high); 4691676Sjpk zone_rele(zone); 4701676Sjpk return (l_admin_high); 4711676Sjpk } 4721676Sjpk 4731676Sjpk static int 4741676Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp) 4751676Sjpk { 4761676Sjpk ts_label_t *tsl; 4771676Sjpk int error = 0; 4781676Sjpk 4791676Sjpk if ((tsl = getflabel(vp)) == NULL) 4801676Sjpk return (EIO); 4811676Sjpk 4821676Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p, 4831676Sjpk sizeof (*(label_p))) != 0) 4841676Sjpk error = EFAULT; 4851676Sjpk 4861676Sjpk label_rele(tsl); 4871676Sjpk return (error); 4881676Sjpk } 4891676Sjpk 4901676Sjpk /* 4911676Sjpk * fgetlabel(2TSOL) - get file label 4921676Sjpk * getlabel(2TSOL) - get file label 4931676Sjpk */ 4941676Sjpk int 4951676Sjpk getlabel(const char *path, bslabel_t *label_p) 4961676Sjpk { 4971676Sjpk struct vnode *vp; 4981676Sjpk char *spath; 4991676Sjpk int error; 5001676Sjpk 5011676Sjpk /* Sanity check arguments */ 5021676Sjpk if (path == NULL) 5031676Sjpk return (set_errno(EINVAL)); 5041676Sjpk 5051676Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5061676Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) { 5071676Sjpk kmem_free(spath, MAXPATHLEN); 5081676Sjpk return (set_errno(error)); 5091676Sjpk } 5101676Sjpk 5111676Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) { 5121676Sjpk kmem_free(spath, MAXPATHLEN); 5131676Sjpk return (set_errno(error)); 5141676Sjpk } 5151676Sjpk kmem_free(spath, MAXPATHLEN); 5161676Sjpk 5171676Sjpk error = cgetlabel(label_p, vp); 5181676Sjpk 5191676Sjpk VN_RELE(vp); 5201676Sjpk if (error != 0) 5211676Sjpk return (set_errno(error)); 5221676Sjpk else 5231676Sjpk return (0); 5241676Sjpk } 5251676Sjpk 5261676Sjpk int 5271676Sjpk fgetlabel(int fd, bslabel_t *label_p) 5281676Sjpk { 5291676Sjpk file_t *fp; 5301676Sjpk int error; 5311676Sjpk 5321676Sjpk if ((fp = getf(fd)) == NULL) 5331676Sjpk return (set_errno(EBADF)); 5341676Sjpk 5351676Sjpk error = cgetlabel(label_p, fp->f_vnode); 5361676Sjpk releasef(fd); 5371676Sjpk 5381676Sjpk if (error != 0) 5391676Sjpk return (set_errno(error)); 5401676Sjpk else 5411676Sjpk return (0); 5421676Sjpk } 5431676Sjpk 5441676Sjpk /* 5454971Sjarrett * Used by NFSv3 and NFSv4 server to query label of 5464971Sjarrett * a pathname component during lookup/access ops. 5471676Sjpk */ 5481676Sjpk ts_label_t * 5494971Sjarrett nfs_getflabel(vnode_t *vp) 5501676Sjpk { 5511676Sjpk zone_t *zone; 5521676Sjpk ts_label_t *zone_label; 5531676Sjpk char path[MAXNAMELEN]; 5541676Sjpk vnode_t *pvp, *tvp; 5551676Sjpk 5561676Sjpk mutex_enter(&vp->v_lock); 5571676Sjpk /* 5581676Sjpk * mount traverse has been done by caller 5591676Sjpk * before calling this routine. 5601676Sjpk */ 5611676Sjpk ASSERT(!vn_ismntpt(vp)); 5621676Sjpk if (vp->v_path != NULL) { 5631676Sjpk zone = zone_find_by_any_path(vp->v_path, B_FALSE); 5641676Sjpk mutex_exit(&vp->v_lock); 5651676Sjpk } else { 5661676Sjpk /* 5671676Sjpk * v_path not cached. Since we rely on path 5681676Sjpk * of an obj to get its label, we need to get 5691676Sjpk * path corresponding to the parent vnode. 5701676Sjpk */ 5711676Sjpk tvp = vp; 5721676Sjpk do { 5731676Sjpk mutex_exit(&tvp->v_lock); 5741676Sjpk if ((pvp = dnlc_reverse_lookup(tvp, path, 5751676Sjpk sizeof (path))) == NULL) 5761676Sjpk return (NULL); 5771676Sjpk mutex_enter(&pvp->v_lock); 5781676Sjpk tvp = pvp; 5791676Sjpk } while (pvp->v_path == NULL); 5801676Sjpk zone = zone_find_by_any_path(pvp->v_path, B_FALSE); 5811676Sjpk mutex_exit(&pvp->v_lock); 5821676Sjpk } 5831676Sjpk /* 5841676Sjpk * Caller has verified that the file is either 5851676Sjpk * exported or visible. So if the path falls in 5861676Sjpk * global zone, admin_low is returned; otherwise 5871676Sjpk * the zone's label is returned. 5881676Sjpk */ 5891676Sjpk zone_label = zone->zone_slabel; 5901676Sjpk label_hold(zone_label); 5911676Sjpk zone_rele(zone); 5921676Sjpk return (zone_label); 5931676Sjpk } 594