1*45916cd2Sjpk /* 2*45916cd2Sjpk * CDDL HEADER START 3*45916cd2Sjpk * 4*45916cd2Sjpk * The contents of this file are subject to the terms of the 5*45916cd2Sjpk * Common Development and Distribution License (the "License"). 6*45916cd2Sjpk * You may not use this file except in compliance with the License. 7*45916cd2Sjpk * 8*45916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*45916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 10*45916cd2Sjpk * See the License for the specific language governing permissions 11*45916cd2Sjpk * and limitations under the License. 12*45916cd2Sjpk * 13*45916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 14*45916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*45916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 16*45916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 17*45916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 18*45916cd2Sjpk * 19*45916cd2Sjpk * CDDL HEADER END 20*45916cd2Sjpk */ 21*45916cd2Sjpk /* 22*45916cd2Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*45916cd2Sjpk * Use is subject to license terms. 24*45916cd2Sjpk */ 25*45916cd2Sjpk 26*45916cd2Sjpk #pragma ident "%Z%%M% %I% %E% SMI" 27*45916cd2Sjpk 28*45916cd2Sjpk #include <sys/types.h> 29*45916cd2Sjpk #include <sys/param.h> 30*45916cd2Sjpk #include <sys/cmn_err.h> 31*45916cd2Sjpk #include <sys/systm.h> 32*45916cd2Sjpk #include <sys/cred.h> 33*45916cd2Sjpk #include <sys/modctl.h> 34*45916cd2Sjpk #include <sys/vfs.h> 35*45916cd2Sjpk #include <sys/vnode.h> 36*45916cd2Sjpk #include <sys/tiuser.h> 37*45916cd2Sjpk #include <sys/kmem.h> 38*45916cd2Sjpk #include <sys/pathname.h> 39*45916cd2Sjpk #include <sys/zone.h> 40*45916cd2Sjpk #include <sys/tsol/label.h> 41*45916cd2Sjpk #include <sys/tsol/tnet.h> 42*45916cd2Sjpk #include <sys/fs/lofs_node.h> 43*45916cd2Sjpk #include <inet/ip6.h> 44*45916cd2Sjpk #include <rpc/auth.h> 45*45916cd2Sjpk #include <rpc/clnt.h> 46*45916cd2Sjpk #include <nfs/nfs.h> 47*45916cd2Sjpk #include <nfs/nfs4.h> 48*45916cd2Sjpk #include <nfs/nfs_clnt.h> 49*45916cd2Sjpk #include <sys/dnlc.h> 50*45916cd2Sjpk 51*45916cd2Sjpk 52*45916cd2Sjpk int sys_labeling = -1; /* initially unset */ 53*45916cd2Sjpk 54*45916cd2Sjpk static kmem_cache_t *tslabel_cache; 55*45916cd2Sjpk ts_label_t *l_admin_low; 56*45916cd2Sjpk ts_label_t *l_admin_high; 57*45916cd2Sjpk 58*45916cd2Sjpk uint32_t default_doi = DEFAULT_DOI; 59*45916cd2Sjpk 60*45916cd2Sjpk /* 61*45916cd2Sjpk * Initialize labels infrastructure. 62*45916cd2Sjpk * This is called during startup() time (before vfs_mntroot) by thread_init(). 63*45916cd2Sjpk * It has to be called early so that the is_system_labeled() function returns 64*45916cd2Sjpk * the right value when called by the networking code on a diskless boot. 65*45916cd2Sjpk */ 66*45916cd2Sjpk void 67*45916cd2Sjpk label_init(void) 68*45916cd2Sjpk { 69*45916cd2Sjpk bslabel_t label; 70*45916cd2Sjpk 71*45916cd2Sjpk /* 72*45916cd2Sjpk * Use the value of "label_services" within the edition module. 73*45916cd2Sjpk * If for some reason label_services is not found, this will 74*45916cd2Sjpk * result in the appropriate default -- "off." 75*45916cd2Sjpk */ 76*45916cd2Sjpk if (modgetsymvalue("label_services", B_FALSE) != 0) 77*45916cd2Sjpk sys_labeling = 1; 78*45916cd2Sjpk else 79*45916cd2Sjpk sys_labeling = 0; 80*45916cd2Sjpk 81*45916cd2Sjpk tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t), 82*45916cd2Sjpk 0, NULL, NULL, NULL, NULL, NULL, 0); 83*45916cd2Sjpk bsllow(&label); 84*45916cd2Sjpk l_admin_low = labelalloc(&label, default_doi, KM_SLEEP); 85*45916cd2Sjpk bslhigh(&label); 86*45916cd2Sjpk l_admin_high = labelalloc(&label, default_doi, KM_SLEEP); 87*45916cd2Sjpk } 88*45916cd2Sjpk 89*45916cd2Sjpk /* 90*45916cd2Sjpk * Allocate new ts_label_t. 91*45916cd2Sjpk */ 92*45916cd2Sjpk ts_label_t * 93*45916cd2Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag) 94*45916cd2Sjpk { 95*45916cd2Sjpk ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 96*45916cd2Sjpk 97*45916cd2Sjpk if (lab != NULL) { 98*45916cd2Sjpk lab->tsl_ref = 1; 99*45916cd2Sjpk lab->tsl_doi = doi; 100*45916cd2Sjpk if (val == NULL) 101*45916cd2Sjpk bzero(&lab->tsl_label, sizeof (bslabel_t)); 102*45916cd2Sjpk else 103*45916cd2Sjpk bcopy(val, &lab->tsl_label, sizeof (bslabel_t)); 104*45916cd2Sjpk } 105*45916cd2Sjpk return (lab); 106*45916cd2Sjpk } 107*45916cd2Sjpk 108*45916cd2Sjpk /* 109*45916cd2Sjpk * Put a hold on a label structure. 110*45916cd2Sjpk */ 111*45916cd2Sjpk void 112*45916cd2Sjpk label_hold(ts_label_t *lab) 113*45916cd2Sjpk { 114*45916cd2Sjpk atomic_add_32(&lab->tsl_ref, 1); 115*45916cd2Sjpk } 116*45916cd2Sjpk 117*45916cd2Sjpk /* 118*45916cd2Sjpk * Release previous hold on a label structure. Free it if refcnt == 0. 119*45916cd2Sjpk */ 120*45916cd2Sjpk void 121*45916cd2Sjpk label_rele(ts_label_t *lab) 122*45916cd2Sjpk { 123*45916cd2Sjpk if (atomic_add_32_nv(&lab->tsl_ref, -1) == 0) 124*45916cd2Sjpk kmem_cache_free(tslabel_cache, lab); 125*45916cd2Sjpk } 126*45916cd2Sjpk 127*45916cd2Sjpk bslabel_t * 128*45916cd2Sjpk label2bslabel(ts_label_t *lab) 129*45916cd2Sjpk { 130*45916cd2Sjpk return (&lab->tsl_label); 131*45916cd2Sjpk } 132*45916cd2Sjpk 133*45916cd2Sjpk 134*45916cd2Sjpk uint32_t 135*45916cd2Sjpk label2doi(ts_label_t *lab) 136*45916cd2Sjpk { 137*45916cd2Sjpk return (lab->tsl_doi); 138*45916cd2Sjpk } 139*45916cd2Sjpk 140*45916cd2Sjpk /* 141*45916cd2Sjpk * Compare labels. Return 1 if equal, 0 otherwise. 142*45916cd2Sjpk */ 143*45916cd2Sjpk boolean_t 144*45916cd2Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2) 145*45916cd2Sjpk { 146*45916cd2Sjpk return ((l1->tsl_doi == l2->tsl_doi) && 147*45916cd2Sjpk blequal(&l1->tsl_label, &l2->tsl_label)); 148*45916cd2Sjpk } 149*45916cd2Sjpk 150*45916cd2Sjpk /* 151*45916cd2Sjpk * There's no protocol today to obtain the label from the server. 152*45916cd2Sjpk * So we rely on conventions: zones, zone names, and zone paths 153*45916cd2Sjpk * must match across TX servers and their TX clients. Now use 154*45916cd2Sjpk * the exported name to find the equivalent local zone and its 155*45916cd2Sjpk * label. Caller is responsible for doing a label_rele of the 156*45916cd2Sjpk * returned ts_label. 157*45916cd2Sjpk */ 158*45916cd2Sjpk ts_label_t * 159*45916cd2Sjpk getflabel_cipso(vfs_t *vfsp) 160*45916cd2Sjpk { 161*45916cd2Sjpk zone_t *reszone; 162*45916cd2Sjpk zone_t *new_reszone; 163*45916cd2Sjpk char *nfspath, *respath; 164*45916cd2Sjpk refstr_t *resource_ref; 165*45916cd2Sjpk boolean_t treat_abs = B_FALSE; 166*45916cd2Sjpk 167*45916cd2Sjpk if (vfsp->vfs_resource == NULL) 168*45916cd2Sjpk return (NULL); /* error */ 169*45916cd2Sjpk resource_ref = vfs_getresource(vfsp); 170*45916cd2Sjpk 171*45916cd2Sjpk nfspath = (char *)refstr_value(resource_ref); 172*45916cd2Sjpk respath = strchr(nfspath, ':'); /* skip server name */ 173*45916cd2Sjpk if (respath) 174*45916cd2Sjpk respath++; /* skip over ":" */ 175*45916cd2Sjpk if (*respath != '/') { 176*45916cd2Sjpk /* treat path as absolute but it doesn't have leading '/' */ 177*45916cd2Sjpk treat_abs = B_TRUE; 178*45916cd2Sjpk } 179*45916cd2Sjpk 180*45916cd2Sjpk reszone = zone_find_by_any_path(respath, treat_abs); 181*45916cd2Sjpk if (reszone == global_zone) { 182*45916cd2Sjpk refstr_rele(resource_ref); 183*45916cd2Sjpk label_hold(l_admin_low); 184*45916cd2Sjpk zone_rele(reszone); 185*45916cd2Sjpk return (l_admin_low); 186*45916cd2Sjpk } 187*45916cd2Sjpk 188*45916cd2Sjpk /* 189*45916cd2Sjpk * Skip over zonepath (not including "root"), e.g. /zone/internal 190*45916cd2Sjpk */ 191*45916cd2Sjpk respath += reszone->zone_rootpathlen - 7; 192*45916cd2Sjpk if (treat_abs) 193*45916cd2Sjpk respath--; /* no leading '/' to skip */ 194*45916cd2Sjpk if (strncmp(respath, "/root/", 6) == 0) { 195*45916cd2Sjpk /* Check if we now have something like "/zone/public/" */ 196*45916cd2Sjpk 197*45916cd2Sjpk respath += 5; /* skip "/root" first */ 198*45916cd2Sjpk new_reszone = zone_find_by_any_path(respath, B_FALSE); 199*45916cd2Sjpk if (new_reszone != global_zone) { 200*45916cd2Sjpk zone_rele(reszone); 201*45916cd2Sjpk reszone = new_reszone; 202*45916cd2Sjpk } else { 203*45916cd2Sjpk zone_rele(new_reszone); 204*45916cd2Sjpk } 205*45916cd2Sjpk } 206*45916cd2Sjpk 207*45916cd2Sjpk refstr_rele(resource_ref); 208*45916cd2Sjpk label_hold(reszone->zone_slabel); 209*45916cd2Sjpk zone_rele(reszone); 210*45916cd2Sjpk 211*45916cd2Sjpk return (reszone->zone_slabel); 212*45916cd2Sjpk } 213*45916cd2Sjpk 214*45916cd2Sjpk static ts_label_t * 215*45916cd2Sjpk getflabel_nfs(vfs_t *vfsp) 216*45916cd2Sjpk { 217*45916cd2Sjpk bslabel_t *server_sl; 218*45916cd2Sjpk ts_label_t *srv_label; 219*45916cd2Sjpk tsol_tpc_t *tp; 220*45916cd2Sjpk int addr_type; 221*45916cd2Sjpk void *ipaddr; 222*45916cd2Sjpk struct servinfo *svp; 223*45916cd2Sjpk struct netbuf *addr; 224*45916cd2Sjpk struct knetconfig *knconf; 225*45916cd2Sjpk mntinfo_t *mi; 226*45916cd2Sjpk 227*45916cd2Sjpk mi = VFTOMI(vfsp); 228*45916cd2Sjpk svp = mi->mi_curr_serv; 229*45916cd2Sjpk addr = &svp->sv_addr; 230*45916cd2Sjpk knconf = svp->sv_knconf; 231*45916cd2Sjpk 232*45916cd2Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) { 233*45916cd2Sjpk addr_type = IPV4_VERSION; 234*45916cd2Sjpk /* LINTED: following cast to ipaddr is OK */ 235*45916cd2Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr; 236*45916cd2Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) { 237*45916cd2Sjpk addr_type = IPV6_VERSION; 238*45916cd2Sjpk /* LINTED: following cast to ipaddr is OK */ 239*45916cd2Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr; 240*45916cd2Sjpk } else { 241*45916cd2Sjpk goto errout; 242*45916cd2Sjpk } 243*45916cd2Sjpk 244*45916cd2Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 245*45916cd2Sjpk if (tp == NULL) 246*45916cd2Sjpk goto errout; 247*45916cd2Sjpk 248*45916cd2Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) { 249*45916cd2Sjpk TPC_RELE(tp); 250*45916cd2Sjpk return (getflabel_cipso(vfsp)); 251*45916cd2Sjpk } 252*45916cd2Sjpk 253*45916cd2Sjpk if (tp->tpc_tp.host_type != UNLABELED) 254*45916cd2Sjpk goto errout; 255*45916cd2Sjpk 256*45916cd2Sjpk server_sl = &tp->tpc_tp.tp_def_label; 257*45916cd2Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP); 258*45916cd2Sjpk 259*45916cd2Sjpk TPC_RELE(tp); 260*45916cd2Sjpk 261*45916cd2Sjpk return (srv_label); 262*45916cd2Sjpk 263*45916cd2Sjpk errout: 264*45916cd2Sjpk return (NULL); 265*45916cd2Sjpk } 266*45916cd2Sjpk 267*45916cd2Sjpk /* 268*45916cd2Sjpk * getflabel - 269*45916cd2Sjpk * 270*45916cd2Sjpk * Return pointer to the ts_label associated with the specified file, 271*45916cd2Sjpk * or returns NULL if error occurs. Caller is responsible for doing 272*45916cd2Sjpk * a label_rele of the ts_label. 273*45916cd2Sjpk */ 274*45916cd2Sjpk ts_label_t * 275*45916cd2Sjpk getflabel(vnode_t *vp) 276*45916cd2Sjpk { 277*45916cd2Sjpk vfs_t *vfsp, *rvfsp, *nvfs; 278*45916cd2Sjpk vnode_t *rvp, *rvp2; 279*45916cd2Sjpk zone_t *zone; 280*45916cd2Sjpk ts_label_t *zl; 281*45916cd2Sjpk boolean_t vfs_is_held = B_FALSE; 282*45916cd2Sjpk refstr_t *resource_ref = NULL; 283*45916cd2Sjpk char *resource = NULL; 284*45916cd2Sjpk char vpath[MAXPATHLEN]; 285*45916cd2Sjpk 286*45916cd2Sjpk ASSERT(vp); 287*45916cd2Sjpk vfsp = rvfsp = nvfs = vp->v_vfsp; 288*45916cd2Sjpk if (vfsp == NULL) 289*45916cd2Sjpk return (NULL); 290*45916cd2Sjpk 291*45916cd2Sjpk rvp = rvp2 = vp; 292*45916cd2Sjpk 293*45916cd2Sjpk /* 294*45916cd2Sjpk * Get rid of all but the last loopback vfs, since the last such mount 295*45916cd2Sjpk * has the correct resource to use (except for nfs case, handled later). 296*45916cd2Sjpk */ 297*45916cd2Sjpk while (strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "lofs") == 0) { 298*45916cd2Sjpk rvp = rvp2; 299*45916cd2Sjpk rvfsp = nvfs; 300*45916cd2Sjpk if ((rvp2 = realvp(rvp)) == NULL) 301*45916cd2Sjpk break; 302*45916cd2Sjpk if (((nvfs = rvp2->v_vfsp) == NULL) || (nvfs == rvfsp)) 303*45916cd2Sjpk break; 304*45916cd2Sjpk } 305*45916cd2Sjpk 306*45916cd2Sjpk /* 307*45916cd2Sjpk * rvp/rvfsp now represent the preliminary vnode/vfs we may use. Now 308*45916cd2Sjpk * check if the next vfs is nfs; if so, then it has the correct info 309*45916cd2Sjpk * to use. And finally, for some cases on loop-back mounts there will 310*45916cd2Sjpk * be no resource; for these, use the underlying vfs also. 311*45916cd2Sjpk */ 312*45916cd2Sjpk if (strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, "lofs") == 0) { 313*45916cd2Sjpk if (((rvp2 = realvp(rvp)) != NULL) && 314*45916cd2Sjpk ((nvfs = rvp2->v_vfsp) != NULL) && 315*45916cd2Sjpk ((strcmp(vfssw[nvfs->vfs_fstype].vsw_name, "nfs") == 0)) || 316*45916cd2Sjpk (rvfsp->vfs_resource == NULL)) { 317*45916cd2Sjpk rvp = rvp2; 318*45916cd2Sjpk rvfsp = nvfs; 319*45916cd2Sjpk } 320*45916cd2Sjpk } 321*45916cd2Sjpk 322*45916cd2Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */ 323*45916cd2Sjpk 324*45916cd2Sjpk /* Go elsewhere to handle all nfs files. */ 325*45916cd2Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0) 326*45916cd2Sjpk return (getflabel_nfs(rvfsp)); 327*45916cd2Sjpk 328*45916cd2Sjpk /* 329*45916cd2Sjpk * Fast path, for objects in a labeled zone: everything except 330*45916cd2Sjpk * for lofs/nfs will be just the label of that zone. 331*45916cd2Sjpk */ 332*45916cd2Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) { 333*45916cd2Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, 334*45916cd2Sjpk "lofs") != 0)) { 335*45916cd2Sjpk zone = rvfsp->vfs_zone; 336*45916cd2Sjpk zone_hold(zone); 337*45916cd2Sjpk goto zone_out; /* return this label */ 338*45916cd2Sjpk } 339*45916cd2Sjpk } 340*45916cd2Sjpk 341*45916cd2Sjpk if (rvfsp->vfs_resource) { 342*45916cd2Sjpk resource_ref = vfs_getresource(rvfsp); 343*45916cd2Sjpk resource = (char *)refstr_value(resource_ref); 344*45916cd2Sjpk } 345*45916cd2Sjpk 346*45916cd2Sjpk /* 347*45916cd2Sjpk * Sanity check - resource may be weird for some cases, like devices. 348*45916cd2Sjpk * In this case, the label must be "local", so just use the mount point. 349*45916cd2Sjpk */ 350*45916cd2Sjpk if ((resource == NULL) || (*resource != '/')) { 351*45916cd2Sjpk if (resource_ref) 352*45916cd2Sjpk refstr_rele(resource_ref); 353*45916cd2Sjpk if (rvfsp->vfs_mntpt) { 354*45916cd2Sjpk resource_ref = vfs_getmntpoint(rvfsp); 355*45916cd2Sjpk resource = (char *)refstr_value(resource_ref); 356*45916cd2Sjpk } 357*45916cd2Sjpk if ((resource == NULL) || (*resource != '/')) { 358*45916cd2Sjpk zone = curproc->p_zone; 359*45916cd2Sjpk zone_hold(zone); 360*45916cd2Sjpk goto zone_out; 361*45916cd2Sjpk } 362*45916cd2Sjpk } 363*45916cd2Sjpk 364*45916cd2Sjpk VFS_HOLD(vfsp); 365*45916cd2Sjpk vfs_is_held = B_TRUE; 366*45916cd2Sjpk 367*45916cd2Sjpk zone = zone_find_by_any_path(resource, B_FALSE); 368*45916cd2Sjpk 369*45916cd2Sjpk /* 370*45916cd2Sjpk * If the vfs source zone is properly set to a non-global zone, or 371*45916cd2Sjpk * any zone if the mount is R/W, then use the label of that zone. 372*45916cd2Sjpk */ 373*45916cd2Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0)) 374*45916cd2Sjpk goto zone_out; /* return this label */ 375*45916cd2Sjpk 376*45916cd2Sjpk /* 377*45916cd2Sjpk * Otherwise, if we're not in the global zone, use the label of 378*45916cd2Sjpk * our zone. 379*45916cd2Sjpk */ 380*45916cd2Sjpk if ((zone = curproc->p_zone) != global_zone) { 381*45916cd2Sjpk zone_hold(zone); 382*45916cd2Sjpk goto zone_out; /* return this label */ 383*45916cd2Sjpk } 384*45916cd2Sjpk 385*45916cd2Sjpk /* 386*45916cd2Sjpk * We're in the global zone and the mount is R/W ... so the file 387*45916cd2Sjpk * may actually be in the global zone -- or in the root of any zone. 388*45916cd2Sjpk * Always build our own path for the file, to be sure it's simplified 389*45916cd2Sjpk * (i.e., no ".", "..", "//", and so on). 390*45916cd2Sjpk */ 391*45916cd2Sjpk if (vnodetopath(NULL, vp, vpath, sizeof (vpath), CRED()) != 0) { 392*45916cd2Sjpk if (vfs_is_held) 393*45916cd2Sjpk VFS_RELE(vfsp); 394*45916cd2Sjpk if (resource_ref) 395*45916cd2Sjpk refstr_rele(resource_ref); 396*45916cd2Sjpk zone_rele(zone); 397*45916cd2Sjpk return (NULL); 398*45916cd2Sjpk } 399*45916cd2Sjpk 400*45916cd2Sjpk zone_rele(zone); 401*45916cd2Sjpk zone = zone_find_by_any_path(vpath, B_FALSE); 402*45916cd2Sjpk 403*45916cd2Sjpk zone_out: 404*45916cd2Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) { 405*45916cd2Sjpk vfs_t *nvfs; 406*45916cd2Sjpk boolean_t exported = B_FALSE; 407*45916cd2Sjpk refstr_t *mntpt_ref; 408*45916cd2Sjpk char *mntpt; 409*45916cd2Sjpk 410*45916cd2Sjpk /* 411*45916cd2Sjpk * File is in the global zone - check whether it's admin_high. 412*45916cd2Sjpk * If it's in a filesys that was exported from the global zone, 413*45916cd2Sjpk * it's admin_low by definition. Otherwise, if it's in a 414*45916cd2Sjpk * filesys that's NOT exported to any zone, it's admin_high. 415*45916cd2Sjpk * 416*45916cd2Sjpk * And for these files if there wasn't a valid mount resource, 417*45916cd2Sjpk * the file must be admin_high (not exported, probably a global 418*45916cd2Sjpk * zone device). 419*45916cd2Sjpk */ 420*45916cd2Sjpk if (!vfs_is_held) 421*45916cd2Sjpk goto out_high; 422*45916cd2Sjpk 423*45916cd2Sjpk mntpt_ref = vfs_getmntpoint(vfsp); 424*45916cd2Sjpk mntpt = (char *)refstr_value(mntpt_ref); 425*45916cd2Sjpk 426*45916cd2Sjpk if ((mntpt != NULL) && (*mntpt == '/')) { 427*45916cd2Sjpk zone_t *to_zone; 428*45916cd2Sjpk 429*45916cd2Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE); 430*45916cd2Sjpk zone_rele(to_zone); 431*45916cd2Sjpk if (to_zone != global_zone) { 432*45916cd2Sjpk /* force admin_low */ 433*45916cd2Sjpk exported = B_TRUE; 434*45916cd2Sjpk } 435*45916cd2Sjpk } 436*45916cd2Sjpk if (mntpt_ref) 437*45916cd2Sjpk refstr_rele(mntpt_ref); 438*45916cd2Sjpk 439*45916cd2Sjpk if (!exported) { 440*45916cd2Sjpk size_t plen = strlen(vpath); 441*45916cd2Sjpk 442*45916cd2Sjpk vfs_list_read_lock(); 443*45916cd2Sjpk nvfs = vfsp->vfs_next; 444*45916cd2Sjpk while (nvfs != vfsp) { 445*45916cd2Sjpk const char *rstr; 446*45916cd2Sjpk size_t rlen = 0; 447*45916cd2Sjpk 448*45916cd2Sjpk rstr = refstr_value(nvfs->vfs_resource); 449*45916cd2Sjpk if (rstr != NULL) 450*45916cd2Sjpk rlen = strlen(rstr); 451*45916cd2Sjpk 452*45916cd2Sjpk /* 453*45916cd2Sjpk * Check for a match: does this vfs correspond 454*45916cd2Sjpk * to our global zone file path? I.e., check 455*45916cd2Sjpk * if the resource string of this vfs is a 456*45916cd2Sjpk * prefix of our path. 457*45916cd2Sjpk */ 458*45916cd2Sjpk if ((rlen > 0) && (rlen <= plen) && 459*45916cd2Sjpk (strncmp(rstr, vpath, rlen) == 0) && 460*45916cd2Sjpk (vpath[rlen] == '/' || 461*45916cd2Sjpk vpath[rlen] == '\0')) { 462*45916cd2Sjpk /* force admin_low */ 463*45916cd2Sjpk exported = B_TRUE; 464*45916cd2Sjpk break; 465*45916cd2Sjpk } 466*45916cd2Sjpk nvfs = nvfs->vfs_next; 467*45916cd2Sjpk } 468*45916cd2Sjpk vfs_list_unlock(); 469*45916cd2Sjpk } 470*45916cd2Sjpk 471*45916cd2Sjpk if (!exported) 472*45916cd2Sjpk goto out_high; 473*45916cd2Sjpk } 474*45916cd2Sjpk 475*45916cd2Sjpk if (vfs_is_held) 476*45916cd2Sjpk VFS_RELE(vfsp); 477*45916cd2Sjpk 478*45916cd2Sjpk if (resource_ref) 479*45916cd2Sjpk refstr_rele(resource_ref); 480*45916cd2Sjpk 481*45916cd2Sjpk /* 482*45916cd2Sjpk * Now that we have the "home" zone for the file, return the slabel 483*45916cd2Sjpk * of that zone. 484*45916cd2Sjpk */ 485*45916cd2Sjpk zl = zone->zone_slabel; 486*45916cd2Sjpk label_hold(zl); 487*45916cd2Sjpk zone_rele(zone); 488*45916cd2Sjpk return (zl); 489*45916cd2Sjpk 490*45916cd2Sjpk out_high: 491*45916cd2Sjpk if (vfs_is_held) 492*45916cd2Sjpk VFS_RELE(vfsp); 493*45916cd2Sjpk if (resource_ref) 494*45916cd2Sjpk refstr_rele(resource_ref); 495*45916cd2Sjpk 496*45916cd2Sjpk label_hold(l_admin_high); 497*45916cd2Sjpk zone_rele(zone); 498*45916cd2Sjpk return (l_admin_high); 499*45916cd2Sjpk } 500*45916cd2Sjpk 501*45916cd2Sjpk static int 502*45916cd2Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp) 503*45916cd2Sjpk { 504*45916cd2Sjpk ts_label_t *tsl; 505*45916cd2Sjpk int error = 0; 506*45916cd2Sjpk 507*45916cd2Sjpk if ((tsl = getflabel(vp)) == NULL) 508*45916cd2Sjpk return (EIO); 509*45916cd2Sjpk 510*45916cd2Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p, 511*45916cd2Sjpk sizeof (*(label_p))) != 0) 512*45916cd2Sjpk error = EFAULT; 513*45916cd2Sjpk 514*45916cd2Sjpk label_rele(tsl); 515*45916cd2Sjpk return (error); 516*45916cd2Sjpk } 517*45916cd2Sjpk 518*45916cd2Sjpk /* 519*45916cd2Sjpk * fgetlabel(2TSOL) - get file label 520*45916cd2Sjpk * getlabel(2TSOL) - get file label 521*45916cd2Sjpk */ 522*45916cd2Sjpk int 523*45916cd2Sjpk getlabel(const char *path, bslabel_t *label_p) 524*45916cd2Sjpk { 525*45916cd2Sjpk struct vnode *vp; 526*45916cd2Sjpk char *spath; 527*45916cd2Sjpk int error; 528*45916cd2Sjpk 529*45916cd2Sjpk /* Sanity check arguments */ 530*45916cd2Sjpk if (path == NULL) 531*45916cd2Sjpk return (set_errno(EINVAL)); 532*45916cd2Sjpk 533*45916cd2Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 534*45916cd2Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) { 535*45916cd2Sjpk kmem_free(spath, MAXPATHLEN); 536*45916cd2Sjpk return (set_errno(error)); 537*45916cd2Sjpk } 538*45916cd2Sjpk 539*45916cd2Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) { 540*45916cd2Sjpk kmem_free(spath, MAXPATHLEN); 541*45916cd2Sjpk return (set_errno(error)); 542*45916cd2Sjpk } 543*45916cd2Sjpk kmem_free(spath, MAXPATHLEN); 544*45916cd2Sjpk 545*45916cd2Sjpk error = cgetlabel(label_p, vp); 546*45916cd2Sjpk 547*45916cd2Sjpk VN_RELE(vp); 548*45916cd2Sjpk if (error != 0) 549*45916cd2Sjpk return (set_errno(error)); 550*45916cd2Sjpk else 551*45916cd2Sjpk return (0); 552*45916cd2Sjpk } 553*45916cd2Sjpk 554*45916cd2Sjpk int 555*45916cd2Sjpk fgetlabel(int fd, bslabel_t *label_p) 556*45916cd2Sjpk { 557*45916cd2Sjpk file_t *fp; 558*45916cd2Sjpk int error; 559*45916cd2Sjpk 560*45916cd2Sjpk if ((fp = getf(fd)) == NULL) 561*45916cd2Sjpk return (set_errno(EBADF)); 562*45916cd2Sjpk 563*45916cd2Sjpk error = cgetlabel(label_p, fp->f_vnode); 564*45916cd2Sjpk releasef(fd); 565*45916cd2Sjpk 566*45916cd2Sjpk if (error != 0) 567*45916cd2Sjpk return (set_errno(error)); 568*45916cd2Sjpk else 569*45916cd2Sjpk return (0); 570*45916cd2Sjpk } 571*45916cd2Sjpk 572*45916cd2Sjpk /* 573*45916cd2Sjpk * Used by NFSv4 to query label of a pathname 574*45916cd2Sjpk * component during lookup/access ops. 575*45916cd2Sjpk */ 576*45916cd2Sjpk ts_label_t * 577*45916cd2Sjpk nfs4_getflabel(vnode_t *vp) 578*45916cd2Sjpk { 579*45916cd2Sjpk zone_t *zone; 580*45916cd2Sjpk ts_label_t *zone_label; 581*45916cd2Sjpk char path[MAXNAMELEN]; 582*45916cd2Sjpk vnode_t *pvp, *tvp; 583*45916cd2Sjpk 584*45916cd2Sjpk mutex_enter(&vp->v_lock); 585*45916cd2Sjpk /* 586*45916cd2Sjpk * mount traverse has been done by caller 587*45916cd2Sjpk * before calling this routine. 588*45916cd2Sjpk */ 589*45916cd2Sjpk ASSERT(!vn_ismntpt(vp)); 590*45916cd2Sjpk if (vp->v_path != NULL) { 591*45916cd2Sjpk zone = zone_find_by_any_path(vp->v_path, B_FALSE); 592*45916cd2Sjpk mutex_exit(&vp->v_lock); 593*45916cd2Sjpk } else { 594*45916cd2Sjpk /* 595*45916cd2Sjpk * v_path not cached. Since we rely on path 596*45916cd2Sjpk * of an obj to get its label, we need to get 597*45916cd2Sjpk * path corresponding to the parent vnode. 598*45916cd2Sjpk */ 599*45916cd2Sjpk tvp = vp; 600*45916cd2Sjpk do { 601*45916cd2Sjpk mutex_exit(&tvp->v_lock); 602*45916cd2Sjpk if ((pvp = dnlc_reverse_lookup(tvp, path, 603*45916cd2Sjpk sizeof (path))) == NULL) 604*45916cd2Sjpk return (NULL); 605*45916cd2Sjpk mutex_enter(&pvp->v_lock); 606*45916cd2Sjpk tvp = pvp; 607*45916cd2Sjpk } while (pvp->v_path == NULL); 608*45916cd2Sjpk zone = zone_find_by_any_path(pvp->v_path, B_FALSE); 609*45916cd2Sjpk mutex_exit(&pvp->v_lock); 610*45916cd2Sjpk } 611*45916cd2Sjpk /* 612*45916cd2Sjpk * Caller has verified that the file is either 613*45916cd2Sjpk * exported or visible. So if the path falls in 614*45916cd2Sjpk * global zone, admin_low is returned; otherwise 615*45916cd2Sjpk * the zone's label is returned. 616*45916cd2Sjpk */ 617*45916cd2Sjpk zone_label = zone->zone_slabel; 618*45916cd2Sjpk label_hold(zone_label); 619*45916cd2Sjpk zone_rele(zone); 620*45916cd2Sjpk return (zone_label); 621*45916cd2Sjpk } 622