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