145916cd2Sjpk /* 245916cd2Sjpk * CDDL HEADER START 345916cd2Sjpk * 445916cd2Sjpk * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 745916cd2Sjpk * 845916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 1045916cd2Sjpk * See the License for the specific language governing permissions 1145916cd2Sjpk * and limitations under the License. 1245916cd2Sjpk * 1345916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 1445916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 1645916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 1745916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 1845916cd2Sjpk * 1945916cd2Sjpk * CDDL HEADER END 2045916cd2Sjpk */ 2145916cd2Sjpk /* 228034149bSRic Aleshire * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 2345916cd2Sjpk */ 2445916cd2Sjpk 2545916cd2Sjpk #include <sys/types.h> 2645916cd2Sjpk #include <sys/param.h> 2745916cd2Sjpk #include <sys/cmn_err.h> 2845916cd2Sjpk #include <sys/systm.h> 2945916cd2Sjpk #include <sys/cred.h> 3045916cd2Sjpk #include <sys/modctl.h> 3145916cd2Sjpk #include <sys/vfs.h> 3245916cd2Sjpk #include <sys/vnode.h> 3345916cd2Sjpk #include <sys/tiuser.h> 3445916cd2Sjpk #include <sys/kmem.h> 3545916cd2Sjpk #include <sys/pathname.h> 3645916cd2Sjpk #include <sys/zone.h> 3745916cd2Sjpk #include <sys/tsol/label.h> 3845916cd2Sjpk #include <sys/tsol/tnet.h> 3945916cd2Sjpk #include <sys/fs/lofs_node.h> 408034149bSRic Aleshire #include <sys/fs/zfs.h> 418034149bSRic Aleshire #include <sys/dsl_prop.h> 4245916cd2Sjpk #include <inet/ip6.h> 4345916cd2Sjpk #include <rpc/auth.h> 4445916cd2Sjpk #include <rpc/clnt.h> 4545916cd2Sjpk #include <nfs/nfs.h> 4645916cd2Sjpk #include <nfs/nfs4.h> 4745916cd2Sjpk #include <nfs/nfs_clnt.h> 4845916cd2Sjpk 4945916cd2Sjpk 50f875b4ebSrica int sys_labeling = 0; /* the default is "off" */ 5145916cd2Sjpk 5245916cd2Sjpk static kmem_cache_t *tslabel_cache; 5345916cd2Sjpk ts_label_t *l_admin_low; 5445916cd2Sjpk ts_label_t *l_admin_high; 5545916cd2Sjpk 5645916cd2Sjpk uint32_t default_doi = DEFAULT_DOI; 5745916cd2Sjpk 5845916cd2Sjpk /* 5945916cd2Sjpk * Initialize labels infrastructure. 6045916cd2Sjpk * This is called during startup() time (before vfs_mntroot) by thread_init(). 6145916cd2Sjpk * It has to be called early so that the is_system_labeled() function returns 6245916cd2Sjpk * the right value when called by the networking code on a diskless boot. 6345916cd2Sjpk */ 6445916cd2Sjpk void 6545916cd2Sjpk label_init(void) 6645916cd2Sjpk { 6745916cd2Sjpk bslabel_t label; 6845916cd2Sjpk 6945916cd2Sjpk /* 70f875b4ebSrica * sys_labeling will default to "off" unless it is overridden 71f875b4ebSrica * in /etc/system. 7245916cd2Sjpk */ 7345916cd2Sjpk 7445916cd2Sjpk tslabel_cache = kmem_cache_create("tslabel_cache", sizeof (ts_label_t), 7545916cd2Sjpk 0, NULL, NULL, NULL, NULL, NULL, 0); 7645916cd2Sjpk bsllow(&label); 7745916cd2Sjpk l_admin_low = labelalloc(&label, default_doi, KM_SLEEP); 7845916cd2Sjpk bslhigh(&label); 7945916cd2Sjpk l_admin_high = labelalloc(&label, default_doi, KM_SLEEP); 8045916cd2Sjpk } 8145916cd2Sjpk 8245916cd2Sjpk /* 8345916cd2Sjpk * Allocate new ts_label_t. 8445916cd2Sjpk */ 8545916cd2Sjpk ts_label_t * 8645916cd2Sjpk labelalloc(const bslabel_t *val, uint32_t doi, int flag) 8745916cd2Sjpk { 8845916cd2Sjpk ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 8945916cd2Sjpk 9045916cd2Sjpk if (lab != NULL) { 9145916cd2Sjpk lab->tsl_ref = 1; 9245916cd2Sjpk lab->tsl_doi = doi; 93e071b5fbSkp158701 lab->tsl_flags = 0; 9445916cd2Sjpk if (val == NULL) 9545916cd2Sjpk bzero(&lab->tsl_label, sizeof (bslabel_t)); 9645916cd2Sjpk else 9745916cd2Sjpk bcopy(val, &lab->tsl_label, sizeof (bslabel_t)); 9845916cd2Sjpk } 9945916cd2Sjpk return (lab); 10045916cd2Sjpk } 10145916cd2Sjpk 10245916cd2Sjpk /* 1035f9878b0Sken Powell - Sun Microsystem * Duplicate an existing ts_label_t to a new one, with only 1045f9878b0Sken Powell - Sun Microsystem * the current reference. 1055f9878b0Sken Powell - Sun Microsystem */ 1065f9878b0Sken Powell - Sun Microsystem ts_label_t * 1075f9878b0Sken Powell - Sun Microsystem labeldup(const ts_label_t *val, int flag) 1085f9878b0Sken Powell - Sun Microsystem { 1095f9878b0Sken Powell - Sun Microsystem ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag); 1105f9878b0Sken Powell - Sun Microsystem 1115f9878b0Sken Powell - Sun Microsystem if (lab != NULL) { 1125f9878b0Sken Powell - Sun Microsystem bcopy(val, lab, sizeof (ts_label_t)); 1135f9878b0Sken Powell - Sun Microsystem lab->tsl_ref = 1; 1145f9878b0Sken Powell - Sun Microsystem } 1155f9878b0Sken Powell - Sun Microsystem return (lab); 1165f9878b0Sken Powell - Sun Microsystem } 1175f9878b0Sken Powell - Sun Microsystem 1185f9878b0Sken Powell - Sun Microsystem /* 11945916cd2Sjpk * Put a hold on a label structure. 12045916cd2Sjpk */ 12145916cd2Sjpk void 12245916cd2Sjpk label_hold(ts_label_t *lab) 12345916cd2Sjpk { 124*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&lab->tsl_ref); 12545916cd2Sjpk } 12645916cd2Sjpk 12745916cd2Sjpk /* 12845916cd2Sjpk * Release previous hold on a label structure. Free it if refcnt == 0. 12945916cd2Sjpk */ 13045916cd2Sjpk void 13145916cd2Sjpk label_rele(ts_label_t *lab) 13245916cd2Sjpk { 133*1a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&lab->tsl_ref) == 0) 13445916cd2Sjpk kmem_cache_free(tslabel_cache, lab); 13545916cd2Sjpk } 13645916cd2Sjpk 13745916cd2Sjpk bslabel_t * 13845916cd2Sjpk label2bslabel(ts_label_t *lab) 13945916cd2Sjpk { 14045916cd2Sjpk return (&lab->tsl_label); 14145916cd2Sjpk } 14245916cd2Sjpk 14345916cd2Sjpk 14445916cd2Sjpk uint32_t 14545916cd2Sjpk label2doi(ts_label_t *lab) 14645916cd2Sjpk { 14745916cd2Sjpk return (lab->tsl_doi); 14845916cd2Sjpk } 14945916cd2Sjpk 15045916cd2Sjpk /* 15145916cd2Sjpk * Compare labels. Return 1 if equal, 0 otherwise. 15245916cd2Sjpk */ 15345916cd2Sjpk boolean_t 15445916cd2Sjpk label_equal(const ts_label_t *l1, const ts_label_t *l2) 15545916cd2Sjpk { 15645916cd2Sjpk return ((l1->tsl_doi == l2->tsl_doi) && 15745916cd2Sjpk blequal(&l1->tsl_label, &l2->tsl_label)); 15845916cd2Sjpk } 15945916cd2Sjpk 16045916cd2Sjpk /* 16145916cd2Sjpk * There's no protocol today to obtain the label from the server. 16245916cd2Sjpk * So we rely on conventions: zones, zone names, and zone paths 16345916cd2Sjpk * must match across TX servers and their TX clients. Now use 16445916cd2Sjpk * the exported name to find the equivalent local zone and its 16545916cd2Sjpk * label. Caller is responsible for doing a label_rele of the 16645916cd2Sjpk * returned ts_label. 16745916cd2Sjpk */ 16845916cd2Sjpk ts_label_t * 16945916cd2Sjpk getflabel_cipso(vfs_t *vfsp) 17045916cd2Sjpk { 17145916cd2Sjpk zone_t *reszone; 17245916cd2Sjpk zone_t *new_reszone; 17345916cd2Sjpk char *nfspath, *respath; 17445916cd2Sjpk refstr_t *resource_ref; 17545916cd2Sjpk boolean_t treat_abs = B_FALSE; 17645916cd2Sjpk 17745916cd2Sjpk if (vfsp->vfs_resource == NULL) 17845916cd2Sjpk return (NULL); /* error */ 17945916cd2Sjpk resource_ref = vfs_getresource(vfsp); 18045916cd2Sjpk 18145916cd2Sjpk nfspath = (char *)refstr_value(resource_ref); 18245916cd2Sjpk respath = strchr(nfspath, ':'); /* skip server name */ 18345916cd2Sjpk if (respath) 18445916cd2Sjpk respath++; /* skip over ":" */ 18545916cd2Sjpk if (*respath != '/') { 18645916cd2Sjpk /* treat path as absolute but it doesn't have leading '/' */ 18745916cd2Sjpk treat_abs = B_TRUE; 18845916cd2Sjpk } 18945916cd2Sjpk 19045916cd2Sjpk reszone = zone_find_by_any_path(respath, treat_abs); 19145916cd2Sjpk if (reszone == global_zone) { 19245916cd2Sjpk refstr_rele(resource_ref); 19345916cd2Sjpk label_hold(l_admin_low); 19445916cd2Sjpk zone_rele(reszone); 19545916cd2Sjpk return (l_admin_low); 19645916cd2Sjpk } 19745916cd2Sjpk 19845916cd2Sjpk /* 19945916cd2Sjpk * Skip over zonepath (not including "root"), e.g. /zone/internal 20045916cd2Sjpk */ 20145916cd2Sjpk respath += reszone->zone_rootpathlen - 7; 20245916cd2Sjpk if (treat_abs) 20345916cd2Sjpk respath--; /* no leading '/' to skip */ 20445916cd2Sjpk if (strncmp(respath, "/root/", 6) == 0) { 20545916cd2Sjpk /* Check if we now have something like "/zone/public/" */ 20645916cd2Sjpk 20745916cd2Sjpk respath += 5; /* skip "/root" first */ 20845916cd2Sjpk new_reszone = zone_find_by_any_path(respath, B_FALSE); 20945916cd2Sjpk if (new_reszone != global_zone) { 21045916cd2Sjpk zone_rele(reszone); 21145916cd2Sjpk reszone = new_reszone; 21245916cd2Sjpk } else { 21345916cd2Sjpk zone_rele(new_reszone); 21445916cd2Sjpk } 21545916cd2Sjpk } 21645916cd2Sjpk 21745916cd2Sjpk refstr_rele(resource_ref); 21845916cd2Sjpk label_hold(reszone->zone_slabel); 21945916cd2Sjpk zone_rele(reszone); 22045916cd2Sjpk 22145916cd2Sjpk return (reszone->zone_slabel); 22245916cd2Sjpk } 22345916cd2Sjpk 2248034149bSRic Aleshire /* 2258034149bSRic Aleshire * Get the label if any of a zfs filesystem. Get the dataset, then 2268034149bSRic Aleshire * get its mlslabel property, convert as needed, and return it. If 2278034149bSRic Aleshire * there's no mlslabel or it is the default one, return NULL. 2288034149bSRic Aleshire */ 2298034149bSRic Aleshire static ts_label_t * 2308034149bSRic Aleshire getflabel_zfs(vfs_t *vfsp) 2318034149bSRic Aleshire { 2328034149bSRic Aleshire int error; 2338034149bSRic Aleshire ts_label_t *tsl = NULL; 2348034149bSRic Aleshire refstr_t *resource_ref; 2358034149bSRic Aleshire bslabel_t ds_sl; 2368034149bSRic Aleshire char ds_hexsl[MAXNAMELEN]; 2378034149bSRic Aleshire const char *osname; 2388034149bSRic Aleshire 2398034149bSRic Aleshire resource_ref = vfs_getresource(vfsp); 2408034149bSRic Aleshire osname = refstr_value(resource_ref); 2418034149bSRic Aleshire 2428034149bSRic Aleshire error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), 2438034149bSRic Aleshire 1, sizeof (ds_hexsl), &ds_hexsl, NULL); 2448034149bSRic Aleshire refstr_rele(resource_ref); 2458034149bSRic Aleshire 2468034149bSRic Aleshire if ((error) || (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0)) 2478034149bSRic Aleshire return (NULL); 2488034149bSRic Aleshire if (hexstr_to_label(ds_hexsl, &ds_sl) != 0) 2498034149bSRic Aleshire return (NULL); 2508034149bSRic Aleshire 2518034149bSRic Aleshire tsl = labelalloc(&ds_sl, default_doi, KM_SLEEP); 2528034149bSRic Aleshire return (tsl); 2538034149bSRic Aleshire } 2548034149bSRic Aleshire 25545916cd2Sjpk static ts_label_t * 25645916cd2Sjpk getflabel_nfs(vfs_t *vfsp) 25745916cd2Sjpk { 25845916cd2Sjpk bslabel_t *server_sl; 25945916cd2Sjpk ts_label_t *srv_label; 26045916cd2Sjpk tsol_tpc_t *tp; 26145916cd2Sjpk int addr_type; 26245916cd2Sjpk void *ipaddr; 26345916cd2Sjpk struct servinfo *svp; 26445916cd2Sjpk struct netbuf *addr; 26545916cd2Sjpk struct knetconfig *knconf; 26645916cd2Sjpk mntinfo_t *mi; 26745916cd2Sjpk 26845916cd2Sjpk mi = VFTOMI(vfsp); 26945916cd2Sjpk svp = mi->mi_curr_serv; 27045916cd2Sjpk addr = &svp->sv_addr; 27145916cd2Sjpk knconf = svp->sv_knconf; 27245916cd2Sjpk 27345916cd2Sjpk if (strcmp(knconf->knc_protofmly, NC_INET) == 0) { 27445916cd2Sjpk addr_type = IPV4_VERSION; 27545916cd2Sjpk /* LINTED: following cast to ipaddr is OK */ 27645916cd2Sjpk ipaddr = &((struct sockaddr_in *)addr->buf)->sin_addr; 27745916cd2Sjpk } else if (strcmp(knconf->knc_protofmly, NC_INET6) == 0) { 27845916cd2Sjpk addr_type = IPV6_VERSION; 27945916cd2Sjpk /* LINTED: following cast to ipaddr is OK */ 28045916cd2Sjpk ipaddr = &((struct sockaddr_in6 *)addr->buf)->sin6_addr; 28145916cd2Sjpk } else { 28245916cd2Sjpk goto errout; 28345916cd2Sjpk } 28445916cd2Sjpk 28545916cd2Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 28645916cd2Sjpk if (tp == NULL) 28745916cd2Sjpk goto errout; 28845916cd2Sjpk 28945916cd2Sjpk if (tp->tpc_tp.host_type == SUN_CIPSO) { 29045916cd2Sjpk TPC_RELE(tp); 29145916cd2Sjpk return (getflabel_cipso(vfsp)); 29245916cd2Sjpk } 29345916cd2Sjpk 29445916cd2Sjpk if (tp->tpc_tp.host_type != UNLABELED) 29545916cd2Sjpk goto errout; 29645916cd2Sjpk 29745916cd2Sjpk server_sl = &tp->tpc_tp.tp_def_label; 29845916cd2Sjpk srv_label = labelalloc(server_sl, default_doi, KM_SLEEP); 29945916cd2Sjpk 30045916cd2Sjpk TPC_RELE(tp); 30145916cd2Sjpk 30245916cd2Sjpk return (srv_label); 30345916cd2Sjpk 30445916cd2Sjpk errout: 30545916cd2Sjpk return (NULL); 30645916cd2Sjpk } 30745916cd2Sjpk 30845916cd2Sjpk /* 30945916cd2Sjpk * getflabel - 31045916cd2Sjpk * 31145916cd2Sjpk * Return pointer to the ts_label associated with the specified file, 31245916cd2Sjpk * or returns NULL if error occurs. Caller is responsible for doing 31345916cd2Sjpk * a label_rele of the ts_label. 31445916cd2Sjpk */ 31545916cd2Sjpk ts_label_t * 31645916cd2Sjpk getflabel(vnode_t *vp) 31745916cd2Sjpk { 3186fc927dcSgfaden vfs_t *vfsp, *rvfsp; 31945916cd2Sjpk vnode_t *rvp, *rvp2; 32045916cd2Sjpk zone_t *zone; 32145916cd2Sjpk ts_label_t *zl; 322770915ebSRic Aleshire int err; 32345916cd2Sjpk boolean_t vfs_is_held = B_FALSE; 32445916cd2Sjpk char vpath[MAXPATHLEN]; 32545916cd2Sjpk 32645916cd2Sjpk ASSERT(vp); 3276fc927dcSgfaden vfsp = vp->v_vfsp; 32845916cd2Sjpk if (vfsp == NULL) 32945916cd2Sjpk return (NULL); 33045916cd2Sjpk 3316fc927dcSgfaden rvp = vp; 33245916cd2Sjpk 33345916cd2Sjpk /* 3346fc927dcSgfaden * Traverse lofs mounts and fattach'es to get the real vnode 33545916cd2Sjpk */ 336da6c28aaSamw if (VOP_REALVP(rvp, &rvp2, NULL) == 0) 33745916cd2Sjpk rvp = rvp2; 33845916cd2Sjpk 3396fc927dcSgfaden rvfsp = rvp->v_vfsp; 34045916cd2Sjpk 34145916cd2Sjpk /* rvp/rvfsp now represent the real vnode/vfs we will be using */ 34245916cd2Sjpk 34345916cd2Sjpk /* Go elsewhere to handle all nfs files. */ 34445916cd2Sjpk if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0) 34545916cd2Sjpk return (getflabel_nfs(rvfsp)); 34645916cd2Sjpk 34745916cd2Sjpk /* 34845916cd2Sjpk * Fast path, for objects in a labeled zone: everything except 34945916cd2Sjpk * for lofs/nfs will be just the label of that zone. 35045916cd2Sjpk */ 35145916cd2Sjpk if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) { 35245916cd2Sjpk if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name, 35345916cd2Sjpk "lofs") != 0)) { 35445916cd2Sjpk zone = rvfsp->vfs_zone; 35545916cd2Sjpk zone_hold(zone); 35645916cd2Sjpk goto zone_out; /* return this label */ 35745916cd2Sjpk } 35845916cd2Sjpk } 35945916cd2Sjpk 36045916cd2Sjpk /* 361770915ebSRic Aleshire * Get the vnode path -- it may be missing or weird for some 362770915ebSRic Aleshire * cases, like devices. In those cases use the label of the 363770915ebSRic Aleshire * current zone. 36445916cd2Sjpk */ 365770915ebSRic Aleshire err = vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred); 366770915ebSRic Aleshire if ((err != 0) || (*vpath != '/')) { 36745916cd2Sjpk zone = curproc->p_zone; 36845916cd2Sjpk zone_hold(zone); 36945916cd2Sjpk goto zone_out; 37045916cd2Sjpk } 37145916cd2Sjpk 372afed4af4Srica /* 3738034149bSRic Aleshire * For zfs filesystem, return the explicit label property if a 3748034149bSRic Aleshire * meaningful one exists. 3758034149bSRic Aleshire */ 3768034149bSRic Aleshire if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "zfs", 3) == 0) { 3778034149bSRic Aleshire ts_label_t *tsl; 3788034149bSRic Aleshire 3798034149bSRic Aleshire tsl = getflabel_zfs(rvfsp); 3808034149bSRic Aleshire 3818034149bSRic Aleshire /* if label found, return it, otherwise continue... */ 3828034149bSRic Aleshire if (tsl != NULL) 3838034149bSRic Aleshire return (tsl); 3848034149bSRic Aleshire } 3858034149bSRic Aleshire 3868034149bSRic Aleshire /* 387afed4af4Srica * If a mountpoint exists, hold the vfs while we reference it. 388afed4af4Srica * Otherwise if mountpoint is NULL it should not be held (e.g., 389afed4af4Srica * a hold/release on spec_vfs would result in an attempted free 390afed4af4Srica * and panic.) 391afed4af4Srica */ 392afed4af4Srica if (vfsp->vfs_mntpt != NULL) { 39345916cd2Sjpk VFS_HOLD(vfsp); 39445916cd2Sjpk vfs_is_held = B_TRUE; 395afed4af4Srica } 39645916cd2Sjpk 3976fc927dcSgfaden zone = zone_find_by_any_path(vpath, B_FALSE); 39845916cd2Sjpk 39945916cd2Sjpk /* 4006fc927dcSgfaden * If the vnode source zone is properly set to a non-global zone, or 40145916cd2Sjpk * any zone if the mount is R/W, then use the label of that zone. 40245916cd2Sjpk */ 40345916cd2Sjpk if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0)) 40445916cd2Sjpk goto zone_out; /* return this label */ 40545916cd2Sjpk 40645916cd2Sjpk /* 40745916cd2Sjpk * Otherwise, if we're not in the global zone, use the label of 40845916cd2Sjpk * our zone. 40945916cd2Sjpk */ 41045916cd2Sjpk if ((zone = curproc->p_zone) != global_zone) { 41145916cd2Sjpk zone_hold(zone); 41245916cd2Sjpk goto zone_out; /* return this label */ 41345916cd2Sjpk } 41445916cd2Sjpk 41545916cd2Sjpk /* 41645916cd2Sjpk * We're in the global zone and the mount is R/W ... so the file 41745916cd2Sjpk * may actually be in the global zone -- or in the root of any zone. 41845916cd2Sjpk * Always build our own path for the file, to be sure it's simplified 41945916cd2Sjpk * (i.e., no ".", "..", "//", and so on). 42045916cd2Sjpk */ 42145916cd2Sjpk 42245916cd2Sjpk zone_rele(zone); 42345916cd2Sjpk zone = zone_find_by_any_path(vpath, B_FALSE); 42445916cd2Sjpk 42545916cd2Sjpk zone_out: 42645916cd2Sjpk if ((curproc->p_zone == global_zone) && (zone == global_zone)) { 42745916cd2Sjpk vfs_t *nvfs; 42845916cd2Sjpk boolean_t exported = B_FALSE; 42945916cd2Sjpk refstr_t *mntpt_ref; 43045916cd2Sjpk char *mntpt; 43145916cd2Sjpk 43245916cd2Sjpk /* 43345916cd2Sjpk * File is in the global zone - check whether it's admin_high. 43445916cd2Sjpk * If it's in a filesys that was exported from the global zone, 43545916cd2Sjpk * it's admin_low by definition. Otherwise, if it's in a 43645916cd2Sjpk * filesys that's NOT exported to any zone, it's admin_high. 43745916cd2Sjpk * 43845916cd2Sjpk * And for these files if there wasn't a valid mount resource, 43945916cd2Sjpk * the file must be admin_high (not exported, probably a global 44045916cd2Sjpk * zone device). 44145916cd2Sjpk */ 44245916cd2Sjpk if (!vfs_is_held) 44345916cd2Sjpk goto out_high; 44445916cd2Sjpk 44545916cd2Sjpk mntpt_ref = vfs_getmntpoint(vfsp); 44645916cd2Sjpk mntpt = (char *)refstr_value(mntpt_ref); 44745916cd2Sjpk 44845916cd2Sjpk if ((mntpt != NULL) && (*mntpt == '/')) { 44945916cd2Sjpk zone_t *to_zone; 45045916cd2Sjpk 45145916cd2Sjpk to_zone = zone_find_by_any_path(mntpt, B_FALSE); 45245916cd2Sjpk zone_rele(to_zone); 45345916cd2Sjpk if (to_zone != global_zone) { 45445916cd2Sjpk /* force admin_low */ 45545916cd2Sjpk exported = B_TRUE; 45645916cd2Sjpk } 45745916cd2Sjpk } 45845916cd2Sjpk if (mntpt_ref) 45945916cd2Sjpk refstr_rele(mntpt_ref); 46045916cd2Sjpk 46145916cd2Sjpk if (!exported) { 46245916cd2Sjpk size_t plen = strlen(vpath); 46345916cd2Sjpk 46445916cd2Sjpk vfs_list_read_lock(); 46545916cd2Sjpk nvfs = vfsp->vfs_next; 46645916cd2Sjpk while (nvfs != vfsp) { 46745916cd2Sjpk const char *rstr; 46845916cd2Sjpk size_t rlen = 0; 46945916cd2Sjpk 4708034149bSRic Aleshire /* 4718034149bSRic Aleshire * Skip checking this vfs if it's not lofs 4728034149bSRic Aleshire * (the only way to export from the global 4738034149bSRic Aleshire * zone to a zone). 4748034149bSRic Aleshire */ 4758034149bSRic Aleshire if (strncmp(vfssw[nvfs->vfs_fstype].vsw_name, 4768034149bSRic Aleshire "lofs", 4) != 0) { 4778034149bSRic Aleshire nvfs = nvfs->vfs_next; 4788034149bSRic Aleshire continue; 4798034149bSRic Aleshire } 4808034149bSRic Aleshire 48145916cd2Sjpk rstr = refstr_value(nvfs->vfs_resource); 48245916cd2Sjpk if (rstr != NULL) 48345916cd2Sjpk rlen = strlen(rstr); 48445916cd2Sjpk 48545916cd2Sjpk /* 48645916cd2Sjpk * Check for a match: does this vfs correspond 48745916cd2Sjpk * to our global zone file path? I.e., check 48845916cd2Sjpk * if the resource string of this vfs is a 48945916cd2Sjpk * prefix of our path. 49045916cd2Sjpk */ 49145916cd2Sjpk if ((rlen > 0) && (rlen <= plen) && 49245916cd2Sjpk (strncmp(rstr, vpath, rlen) == 0) && 49345916cd2Sjpk (vpath[rlen] == '/' || 49445916cd2Sjpk vpath[rlen] == '\0')) { 49545916cd2Sjpk /* force admin_low */ 49645916cd2Sjpk exported = B_TRUE; 49745916cd2Sjpk break; 49845916cd2Sjpk } 49945916cd2Sjpk nvfs = nvfs->vfs_next; 50045916cd2Sjpk } 50145916cd2Sjpk vfs_list_unlock(); 50245916cd2Sjpk } 50345916cd2Sjpk 50445916cd2Sjpk if (!exported) 50545916cd2Sjpk goto out_high; 50645916cd2Sjpk } 50745916cd2Sjpk 50845916cd2Sjpk if (vfs_is_held) 50945916cd2Sjpk VFS_RELE(vfsp); 51045916cd2Sjpk 51145916cd2Sjpk /* 51245916cd2Sjpk * Now that we have the "home" zone for the file, return the slabel 51345916cd2Sjpk * of that zone. 51445916cd2Sjpk */ 51545916cd2Sjpk zl = zone->zone_slabel; 51645916cd2Sjpk label_hold(zl); 51745916cd2Sjpk zone_rele(zone); 51845916cd2Sjpk return (zl); 51945916cd2Sjpk 52045916cd2Sjpk out_high: 52145916cd2Sjpk if (vfs_is_held) 52245916cd2Sjpk VFS_RELE(vfsp); 52345916cd2Sjpk 52445916cd2Sjpk label_hold(l_admin_high); 52545916cd2Sjpk zone_rele(zone); 52645916cd2Sjpk return (l_admin_high); 52745916cd2Sjpk } 52845916cd2Sjpk 52945916cd2Sjpk static int 53045916cd2Sjpk cgetlabel(bslabel_t *label_p, vnode_t *vp) 53145916cd2Sjpk { 53245916cd2Sjpk ts_label_t *tsl; 53345916cd2Sjpk int error = 0; 53445916cd2Sjpk 53545916cd2Sjpk if ((tsl = getflabel(vp)) == NULL) 53645916cd2Sjpk return (EIO); 53745916cd2Sjpk 53845916cd2Sjpk if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p, 53945916cd2Sjpk sizeof (*(label_p))) != 0) 54045916cd2Sjpk error = EFAULT; 54145916cd2Sjpk 54245916cd2Sjpk label_rele(tsl); 54345916cd2Sjpk return (error); 54445916cd2Sjpk } 54545916cd2Sjpk 54645916cd2Sjpk /* 54745916cd2Sjpk * fgetlabel(2TSOL) - get file label 54845916cd2Sjpk * getlabel(2TSOL) - get file label 54945916cd2Sjpk */ 55045916cd2Sjpk int 55145916cd2Sjpk getlabel(const char *path, bslabel_t *label_p) 55245916cd2Sjpk { 55345916cd2Sjpk struct vnode *vp; 55445916cd2Sjpk char *spath; 55545916cd2Sjpk int error; 55645916cd2Sjpk 55745916cd2Sjpk /* Sanity check arguments */ 55845916cd2Sjpk if (path == NULL) 55945916cd2Sjpk return (set_errno(EINVAL)); 56045916cd2Sjpk 56145916cd2Sjpk spath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 56245916cd2Sjpk if ((error = copyinstr(path, spath, MAXPATHLEN, NULL)) != 0) { 56345916cd2Sjpk kmem_free(spath, MAXPATHLEN); 56445916cd2Sjpk return (set_errno(error)); 56545916cd2Sjpk } 56645916cd2Sjpk 56745916cd2Sjpk if (error = lookupname(spath, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) { 56845916cd2Sjpk kmem_free(spath, MAXPATHLEN); 56945916cd2Sjpk return (set_errno(error)); 57045916cd2Sjpk } 57145916cd2Sjpk kmem_free(spath, MAXPATHLEN); 57245916cd2Sjpk 57345916cd2Sjpk error = cgetlabel(label_p, vp); 57445916cd2Sjpk 57545916cd2Sjpk VN_RELE(vp); 57645916cd2Sjpk if (error != 0) 57745916cd2Sjpk return (set_errno(error)); 57845916cd2Sjpk else 57945916cd2Sjpk return (0); 58045916cd2Sjpk } 58145916cd2Sjpk 58245916cd2Sjpk int 58345916cd2Sjpk fgetlabel(int fd, bslabel_t *label_p) 58445916cd2Sjpk { 58545916cd2Sjpk file_t *fp; 58645916cd2Sjpk int error; 58745916cd2Sjpk 58845916cd2Sjpk if ((fp = getf(fd)) == NULL) 58945916cd2Sjpk return (set_errno(EBADF)); 59045916cd2Sjpk 59145916cd2Sjpk error = cgetlabel(label_p, fp->f_vnode); 59245916cd2Sjpk releasef(fd); 59345916cd2Sjpk 59445916cd2Sjpk if (error != 0) 59545916cd2Sjpk return (set_errno(error)); 59645916cd2Sjpk else 59745916cd2Sjpk return (0); 59845916cd2Sjpk } 599