1*9acbbeafSnn /* 2*9acbbeafSnn * CDDL HEADER START 3*9acbbeafSnn * 4*9acbbeafSnn * The contents of this file are subject to the terms of the 5*9acbbeafSnn * Common Development and Distribution License (the "License"). 6*9acbbeafSnn * You may not use this file except in compliance with the License. 7*9acbbeafSnn * 8*9acbbeafSnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9acbbeafSnn * or http://www.opensolaris.org/os/licensing. 10*9acbbeafSnn * See the License for the specific language governing permissions 11*9acbbeafSnn * and limitations under the License. 12*9acbbeafSnn * 13*9acbbeafSnn * When distributing Covered Code, include this CDDL HEADER in each 14*9acbbeafSnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9acbbeafSnn * If applicable, add the following below this CDDL HEADER, with the 16*9acbbeafSnn * fields enclosed by brackets "[]" replaced with your own identifying 17*9acbbeafSnn * information: Portions Copyright [yyyy] [name of copyright owner] 18*9acbbeafSnn * 19*9acbbeafSnn * CDDL HEADER END 20*9acbbeafSnn */ 21*9acbbeafSnn /* 22*9acbbeafSnn * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*9acbbeafSnn * Use is subject to license terms. 24*9acbbeafSnn */ 25*9acbbeafSnn 26*9acbbeafSnn #pragma ident "%Z%%M% %I% %E% SMI" 27*9acbbeafSnn 28*9acbbeafSnn #include <sys/kmem.h> 29*9acbbeafSnn #include <sys/errno.h> 30*9acbbeafSnn #include <sys/systm.h> 31*9acbbeafSnn #include <sys/cmn_err.h> 32*9acbbeafSnn #include <sys/brand.h> 33*9acbbeafSnn #include <sys/machbrand.h> 34*9acbbeafSnn #include <sys/modctl.h> 35*9acbbeafSnn #include <sys/rwlock.h> 36*9acbbeafSnn #include <sys/zone.h> 37*9acbbeafSnn 38*9acbbeafSnn #define SUPPORTED_BRAND_VERSION BRAND_VER_1 39*9acbbeafSnn 40*9acbbeafSnn #if defined(__sparcv9) 41*9acbbeafSnn struct brand_mach_ops native_mach_ops = { 42*9acbbeafSnn NULL, NULL 43*9acbbeafSnn }; 44*9acbbeafSnn #else 45*9acbbeafSnn struct brand_mach_ops native_mach_ops = { 46*9acbbeafSnn NULL, NULL, NULL, NULL, NULL, NULL 47*9acbbeafSnn }; 48*9acbbeafSnn #endif 49*9acbbeafSnn 50*9acbbeafSnn brand_t native_brand = { 51*9acbbeafSnn BRAND_VER_1, 52*9acbbeafSnn "native", 53*9acbbeafSnn NULL, 54*9acbbeafSnn &native_mach_ops 55*9acbbeafSnn }; 56*9acbbeafSnn 57*9acbbeafSnn /* 58*9acbbeafSnn * Used to maintain a list of all the brands currently loaded into the 59*9acbbeafSnn * kernel. 60*9acbbeafSnn */ 61*9acbbeafSnn struct brand_list { 62*9acbbeafSnn int bl_refcnt; 63*9acbbeafSnn struct brand_list *bl_next; 64*9acbbeafSnn brand_t *bl_brand; 65*9acbbeafSnn }; 66*9acbbeafSnn 67*9acbbeafSnn static struct brand_list *brand_list = NULL; 68*9acbbeafSnn 69*9acbbeafSnn /* 70*9acbbeafSnn * This lock protects the integrity of the brand list. 71*9acbbeafSnn */ 72*9acbbeafSnn static kmutex_t brand_list_lock; 73*9acbbeafSnn 74*9acbbeafSnn void 75*9acbbeafSnn brand_init() 76*9acbbeafSnn { 77*9acbbeafSnn mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL); 78*9acbbeafSnn p0.p_brand = &native_brand; 79*9acbbeafSnn } 80*9acbbeafSnn 81*9acbbeafSnn int 82*9acbbeafSnn brand_register(brand_t *brand) 83*9acbbeafSnn { 84*9acbbeafSnn struct brand_list *list, *scan; 85*9acbbeafSnn 86*9acbbeafSnn if (brand == NULL) 87*9acbbeafSnn return (EINVAL); 88*9acbbeafSnn 89*9acbbeafSnn if (is_system_labeled()) { 90*9acbbeafSnn cmn_err(CE_WARN, 91*9acbbeafSnn "Branded zones are not allowed on labeled systems."); 92*9acbbeafSnn return (EINVAL); 93*9acbbeafSnn } 94*9acbbeafSnn 95*9acbbeafSnn if (brand->b_version != SUPPORTED_BRAND_VERSION) { 96*9acbbeafSnn if (brand->b_version < SUPPORTED_BRAND_VERSION) { 97*9acbbeafSnn cmn_err(CE_WARN, 98*9acbbeafSnn "brand '%s' was built to run on older versions " 99*9acbbeafSnn "of Solaris.", 100*9acbbeafSnn brand->b_name); 101*9acbbeafSnn } else { 102*9acbbeafSnn cmn_err(CE_WARN, 103*9acbbeafSnn "brand '%s' was built to run on a newer version " 104*9acbbeafSnn "of Solaris.", 105*9acbbeafSnn brand->b_name); 106*9acbbeafSnn } 107*9acbbeafSnn return (EINVAL); 108*9acbbeafSnn } 109*9acbbeafSnn 110*9acbbeafSnn /* Sanity checks */ 111*9acbbeafSnn if (brand->b_name == NULL || brand->b_ops == NULL || 112*9acbbeafSnn brand->b_ops->b_brandsys == NULL) { 113*9acbbeafSnn cmn_err(CE_WARN, "Malformed brand"); 114*9acbbeafSnn return (EINVAL); 115*9acbbeafSnn } 116*9acbbeafSnn 117*9acbbeafSnn list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP); 118*9acbbeafSnn 119*9acbbeafSnn /* Add the brand to the list of loaded brands. */ 120*9acbbeafSnn mutex_enter(&brand_list_lock); 121*9acbbeafSnn 122*9acbbeafSnn /* 123*9acbbeafSnn * Check to be sure we haven't already registered this brand. 124*9acbbeafSnn */ 125*9acbbeafSnn for (scan = brand_list; scan != NULL; scan = scan->bl_next) { 126*9acbbeafSnn if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) { 127*9acbbeafSnn cmn_err(CE_WARN, 128*9acbbeafSnn "Invalid attempt to load a second instance of " 129*9acbbeafSnn "brand %s", brand->b_name); 130*9acbbeafSnn mutex_exit(&brand_list_lock); 131*9acbbeafSnn kmem_free(list, sizeof (struct brand_list)); 132*9acbbeafSnn return (EINVAL); 133*9acbbeafSnn } 134*9acbbeafSnn } 135*9acbbeafSnn 136*9acbbeafSnn list->bl_brand = brand; 137*9acbbeafSnn list->bl_refcnt = 0; 138*9acbbeafSnn list->bl_next = brand_list; 139*9acbbeafSnn brand_list = list; 140*9acbbeafSnn mutex_exit(&brand_list_lock); 141*9acbbeafSnn 142*9acbbeafSnn return (0); 143*9acbbeafSnn } 144*9acbbeafSnn 145*9acbbeafSnn /* 146*9acbbeafSnn * The kernel module implementing this brand is being unloaded, so remove 147*9acbbeafSnn * it from the list of active brands. 148*9acbbeafSnn */ 149*9acbbeafSnn int 150*9acbbeafSnn brand_unregister(brand_t *brand) 151*9acbbeafSnn { 152*9acbbeafSnn struct brand_list *list, *prev; 153*9acbbeafSnn 154*9acbbeafSnn /* Sanity checks */ 155*9acbbeafSnn if (brand == NULL || brand->b_name == NULL) { 156*9acbbeafSnn cmn_err(CE_WARN, "Malformed brand"); 157*9acbbeafSnn return (EINVAL); 158*9acbbeafSnn } 159*9acbbeafSnn 160*9acbbeafSnn prev = NULL; 161*9acbbeafSnn mutex_enter(&brand_list_lock); 162*9acbbeafSnn 163*9acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) { 164*9acbbeafSnn if (list->bl_brand == brand) 165*9acbbeafSnn break; 166*9acbbeafSnn prev = list; 167*9acbbeafSnn } 168*9acbbeafSnn 169*9acbbeafSnn if (list == NULL) { 170*9acbbeafSnn cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name); 171*9acbbeafSnn mutex_exit(&brand_list_lock); 172*9acbbeafSnn return (EINVAL); 173*9acbbeafSnn } 174*9acbbeafSnn 175*9acbbeafSnn if (list->bl_refcnt > 0) { 176*9acbbeafSnn cmn_err(CE_WARN, "Unregistering brand %s which is still in use", 177*9acbbeafSnn brand->b_name); 178*9acbbeafSnn mutex_exit(&brand_list_lock); 179*9acbbeafSnn return (EBUSY); 180*9acbbeafSnn } 181*9acbbeafSnn 182*9acbbeafSnn /* Remove brand from the list */ 183*9acbbeafSnn if (prev != NULL) 184*9acbbeafSnn prev->bl_next = list->bl_next; 185*9acbbeafSnn else 186*9acbbeafSnn brand_list = list->bl_next; 187*9acbbeafSnn 188*9acbbeafSnn mutex_exit(&brand_list_lock); 189*9acbbeafSnn 190*9acbbeafSnn kmem_free(list, sizeof (struct brand_list)); 191*9acbbeafSnn 192*9acbbeafSnn return (0); 193*9acbbeafSnn } 194*9acbbeafSnn 195*9acbbeafSnn /* 196*9acbbeafSnn * Record that a zone of this brand has been instantiated. If the kernel 197*9acbbeafSnn * module implementing this brand's functionality is not present, this 198*9acbbeafSnn * routine attempts to load the module as a side effect. 199*9acbbeafSnn */ 200*9acbbeafSnn brand_t * 201*9acbbeafSnn brand_register_zone(struct brand_attr *attr) 202*9acbbeafSnn { 203*9acbbeafSnn struct brand_list *l = NULL; 204*9acbbeafSnn ddi_modhandle_t hdl = NULL; 205*9acbbeafSnn char *modname; 206*9acbbeafSnn int err = 0; 207*9acbbeafSnn 208*9acbbeafSnn if (is_system_labeled()) { 209*9acbbeafSnn cmn_err(CE_WARN, 210*9acbbeafSnn "Branded zones are not allowed on labeled systems."); 211*9acbbeafSnn return (NULL); 212*9acbbeafSnn } 213*9acbbeafSnn 214*9acbbeafSnn /* 215*9acbbeafSnn * We make at most two passes through this loop. The first time 216*9acbbeafSnn * through, we're looking to see if this is a new user of an 217*9acbbeafSnn * already loaded brand. If the brand hasn't been loaded, we 218*9acbbeafSnn * call ddi_modopen() to force it to be loaded and then make a 219*9acbbeafSnn * second pass through the list of brands. If we don't find the 220*9acbbeafSnn * brand the second time through it means that the modname 221*9acbbeafSnn * specified in the brand_attr structure doesn't provide the brand 222*9acbbeafSnn * specified in the brandname field. This would suggest a bug in 223*9acbbeafSnn * the brand's config.xml file. We close the module and return 224*9acbbeafSnn * 'NULL' to the caller. 225*9acbbeafSnn */ 226*9acbbeafSnn for (;;) { 227*9acbbeafSnn /* 228*9acbbeafSnn * Search list of loaded brands 229*9acbbeafSnn */ 230*9acbbeafSnn mutex_enter(&brand_list_lock); 231*9acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next) 232*9acbbeafSnn if (strcmp(attr->ba_brandname, 233*9acbbeafSnn l->bl_brand->b_name) == 0) 234*9acbbeafSnn break; 235*9acbbeafSnn if ((l != NULL) || (hdl != NULL)) 236*9acbbeafSnn break; 237*9acbbeafSnn mutex_exit(&brand_list_lock); 238*9acbbeafSnn 239*9acbbeafSnn /* 240*9acbbeafSnn * We didn't find that the requested brand has been loaded 241*9acbbeafSnn * yet, so we trigger the load of the appropriate kernel 242*9acbbeafSnn * module and search the list again. 243*9acbbeafSnn */ 244*9acbbeafSnn modname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 245*9acbbeafSnn (void) strcpy(modname, "brand/"); 246*9acbbeafSnn (void) strcat(modname, attr->ba_modname); 247*9acbbeafSnn hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err); 248*9acbbeafSnn kmem_free(modname, MAXPATHLEN); 249*9acbbeafSnn 250*9acbbeafSnn if (err != 0) 251*9acbbeafSnn return (NULL); 252*9acbbeafSnn } 253*9acbbeafSnn 254*9acbbeafSnn /* 255*9acbbeafSnn * If we found the matching brand, bump its reference count. 256*9acbbeafSnn */ 257*9acbbeafSnn if (l != NULL) 258*9acbbeafSnn l->bl_refcnt++; 259*9acbbeafSnn 260*9acbbeafSnn mutex_exit(&brand_list_lock); 261*9acbbeafSnn 262*9acbbeafSnn if (hdl != NULL) 263*9acbbeafSnn (void) ddi_modclose(hdl); 264*9acbbeafSnn 265*9acbbeafSnn return ((l != NULL) ? l->bl_brand : NULL); 266*9acbbeafSnn } 267*9acbbeafSnn 268*9acbbeafSnn /* 269*9acbbeafSnn * Return the number of zones currently using this brand. 270*9acbbeafSnn */ 271*9acbbeafSnn int 272*9acbbeafSnn brand_zone_count(struct brand *bp) 273*9acbbeafSnn { 274*9acbbeafSnn struct brand_list *l; 275*9acbbeafSnn int cnt = 0; 276*9acbbeafSnn 277*9acbbeafSnn mutex_enter(&brand_list_lock); 278*9acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next) 279*9acbbeafSnn if (l->bl_brand == bp) { 280*9acbbeafSnn cnt = l->bl_refcnt; 281*9acbbeafSnn break; 282*9acbbeafSnn } 283*9acbbeafSnn mutex_exit(&brand_list_lock); 284*9acbbeafSnn 285*9acbbeafSnn return (cnt); 286*9acbbeafSnn } 287*9acbbeafSnn 288*9acbbeafSnn void 289*9acbbeafSnn brand_unregister_zone(struct brand *bp) 290*9acbbeafSnn { 291*9acbbeafSnn struct brand_list *list; 292*9acbbeafSnn 293*9acbbeafSnn mutex_enter(&brand_list_lock); 294*9acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) { 295*9acbbeafSnn if (list->bl_brand == bp) { 296*9acbbeafSnn ASSERT(list->bl_refcnt > 0); 297*9acbbeafSnn list->bl_refcnt--; 298*9acbbeafSnn break; 299*9acbbeafSnn } 300*9acbbeafSnn } 301*9acbbeafSnn mutex_exit(&brand_list_lock); 302*9acbbeafSnn } 303*9acbbeafSnn 304*9acbbeafSnn void 305*9acbbeafSnn brand_setbrand(proc_t *p) 306*9acbbeafSnn { 307*9acbbeafSnn brand_t *bp = p->p_zone->zone_brand; 308*9acbbeafSnn 309*9acbbeafSnn ASSERT(bp != NULL); 310*9acbbeafSnn ASSERT(p->p_brand == &native_brand); 311*9acbbeafSnn 312*9acbbeafSnn /* 313*9acbbeafSnn * We should only be called from exec(), when we know the process 314*9acbbeafSnn * is single-threaded. 315*9acbbeafSnn */ 316*9acbbeafSnn ASSERT(p->p_tlist == p->p_tlist->t_forw); 317*9acbbeafSnn 318*9acbbeafSnn p->p_brand = bp; 319*9acbbeafSnn if (PROC_IS_BRANDED(p)) { 320*9acbbeafSnn BROP(p)->b_setbrand(p); 321*9acbbeafSnn lwp_attach_brand_hdlrs(p->p_tlist->t_lwp); 322*9acbbeafSnn } 323*9acbbeafSnn } 324