19acbbeafSnn35248 /* 29acbbeafSnn35248 * CDDL HEADER START 39acbbeafSnn35248 * 49acbbeafSnn35248 * The contents of this file are subject to the terms of the 59acbbeafSnn35248 * Common Development and Distribution License (the "License"). 69acbbeafSnn35248 * You may not use this file except in compliance with the License. 79acbbeafSnn35248 * 89acbbeafSnn35248 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99acbbeafSnn35248 * or http://www.opensolaris.org/os/licensing. 109acbbeafSnn35248 * See the License for the specific language governing permissions 119acbbeafSnn35248 * and limitations under the License. 129acbbeafSnn35248 * 139acbbeafSnn35248 * When distributing Covered Code, include this CDDL HEADER in each 149acbbeafSnn35248 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159acbbeafSnn35248 * If applicable, add the following below this CDDL HEADER, with the 169acbbeafSnn35248 * fields enclosed by brackets "[]" replaced with your own identifying 179acbbeafSnn35248 * information: Portions Copyright [yyyy] [name of copyright owner] 189acbbeafSnn35248 * 199acbbeafSnn35248 * CDDL HEADER END 209acbbeafSnn35248 */ 219acbbeafSnn35248 /* 2280e2ca85S * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 239acbbeafSnn35248 */ 249acbbeafSnn35248 259acbbeafSnn35248 #include <sys/kmem.h> 269acbbeafSnn35248 #include <sys/errno.h> 279acbbeafSnn35248 #include <sys/systm.h> 289acbbeafSnn35248 #include <sys/cmn_err.h> 299acbbeafSnn35248 #include <sys/brand.h> 309acbbeafSnn35248 #include <sys/machbrand.h> 319acbbeafSnn35248 #include <sys/modctl.h> 329acbbeafSnn35248 #include <sys/rwlock.h> 339acbbeafSnn35248 #include <sys/zone.h> 3480e2ca85S #include <sys/pathname.h> 359acbbeafSnn35248 369acbbeafSnn35248 #define SUPPORTED_BRAND_VERSION BRAND_VER_1 379acbbeafSnn35248 389acbbeafSnn35248 #if defined(__sparcv9) 39725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */ 40725deb8fSedp static void brand_plat_interposition_enable(void); 41725deb8fSedp static void brand_plat_interposition_disable(void); 42725deb8fSedp 439acbbeafSnn35248 struct brand_mach_ops native_mach_ops = { 449acbbeafSnn35248 NULL, NULL 459acbbeafSnn35248 }; 4659f2ff5cSedp #else /* !__sparcv9 */ 479acbbeafSnn35248 struct brand_mach_ops native_mach_ops = { 48eb5a5c78SSurya Prakki NULL, NULL, NULL, NULL 499acbbeafSnn35248 }; 5059f2ff5cSedp #endif /* !__sparcv9 */ 519acbbeafSnn35248 529acbbeafSnn35248 brand_t native_brand = { 539acbbeafSnn35248 BRAND_VER_1, 549acbbeafSnn35248 "native", 559acbbeafSnn35248 NULL, 569acbbeafSnn35248 &native_mach_ops 579acbbeafSnn35248 }; 589acbbeafSnn35248 599acbbeafSnn35248 /* 609acbbeafSnn35248 * Used to maintain a list of all the brands currently loaded into the 619acbbeafSnn35248 * kernel. 629acbbeafSnn35248 */ 639acbbeafSnn35248 struct brand_list { 649acbbeafSnn35248 int bl_refcnt; 659acbbeafSnn35248 struct brand_list *bl_next; 669acbbeafSnn35248 brand_t *bl_brand; 679acbbeafSnn35248 }; 689acbbeafSnn35248 699acbbeafSnn35248 static struct brand_list *brand_list = NULL; 709acbbeafSnn35248 719acbbeafSnn35248 /* 729acbbeafSnn35248 * This lock protects the integrity of the brand list. 739acbbeafSnn35248 */ 749acbbeafSnn35248 static kmutex_t brand_list_lock; 759acbbeafSnn35248 769acbbeafSnn35248 void 779acbbeafSnn35248 brand_init() 789acbbeafSnn35248 { 799acbbeafSnn35248 mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL); 809acbbeafSnn35248 p0.p_brand = &native_brand; 819acbbeafSnn35248 } 829acbbeafSnn35248 839acbbeafSnn35248 int 849acbbeafSnn35248 brand_register(brand_t *brand) 859acbbeafSnn35248 { 869acbbeafSnn35248 struct brand_list *list, *scan; 879acbbeafSnn35248 889acbbeafSnn35248 if (brand == NULL) 899acbbeafSnn35248 return (EINVAL); 909acbbeafSnn35248 919acbbeafSnn35248 if (brand->b_version != SUPPORTED_BRAND_VERSION) { 929acbbeafSnn35248 if (brand->b_version < SUPPORTED_BRAND_VERSION) { 939acbbeafSnn35248 cmn_err(CE_WARN, 949acbbeafSnn35248 "brand '%s' was built to run on older versions " 959acbbeafSnn35248 "of Solaris.", 969acbbeafSnn35248 brand->b_name); 979acbbeafSnn35248 } else { 989acbbeafSnn35248 cmn_err(CE_WARN, 999acbbeafSnn35248 "brand '%s' was built to run on a newer version " 1009acbbeafSnn35248 "of Solaris.", 1019acbbeafSnn35248 brand->b_name); 1029acbbeafSnn35248 } 1039acbbeafSnn35248 return (EINVAL); 1049acbbeafSnn35248 } 1059acbbeafSnn35248 1069acbbeafSnn35248 /* Sanity checks */ 1079acbbeafSnn35248 if (brand->b_name == NULL || brand->b_ops == NULL || 1089acbbeafSnn35248 brand->b_ops->b_brandsys == NULL) { 1099acbbeafSnn35248 cmn_err(CE_WARN, "Malformed brand"); 1109acbbeafSnn35248 return (EINVAL); 1119acbbeafSnn35248 } 1129acbbeafSnn35248 1139acbbeafSnn35248 list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP); 1149acbbeafSnn35248 1159acbbeafSnn35248 /* Add the brand to the list of loaded brands. */ 1169acbbeafSnn35248 mutex_enter(&brand_list_lock); 1179acbbeafSnn35248 1189acbbeafSnn35248 /* 1199acbbeafSnn35248 * Check to be sure we haven't already registered this brand. 1209acbbeafSnn35248 */ 1219acbbeafSnn35248 for (scan = brand_list; scan != NULL; scan = scan->bl_next) { 1229acbbeafSnn35248 if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) { 1239acbbeafSnn35248 cmn_err(CE_WARN, 1249acbbeafSnn35248 "Invalid attempt to load a second instance of " 1259acbbeafSnn35248 "brand %s", brand->b_name); 1269acbbeafSnn35248 mutex_exit(&brand_list_lock); 1279acbbeafSnn35248 kmem_free(list, sizeof (struct brand_list)); 1289acbbeafSnn35248 return (EINVAL); 1299acbbeafSnn35248 } 1309acbbeafSnn35248 } 1319acbbeafSnn35248 132725deb8fSedp #if defined(__sparcv9) 133725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */ 134725deb8fSedp if (brand_list == NULL) 135725deb8fSedp brand_plat_interposition_enable(); 136725deb8fSedp #endif /* __sparcv9 */ 137725deb8fSedp 1389acbbeafSnn35248 list->bl_brand = brand; 1399acbbeafSnn35248 list->bl_refcnt = 0; 1409acbbeafSnn35248 list->bl_next = brand_list; 1419acbbeafSnn35248 brand_list = list; 142725deb8fSedp 1439acbbeafSnn35248 mutex_exit(&brand_list_lock); 1449acbbeafSnn35248 1459acbbeafSnn35248 return (0); 1469acbbeafSnn35248 } 1479acbbeafSnn35248 1489acbbeafSnn35248 /* 1499acbbeafSnn35248 * The kernel module implementing this brand is being unloaded, so remove 1509acbbeafSnn35248 * it from the list of active brands. 1519acbbeafSnn35248 */ 1529acbbeafSnn35248 int 1539acbbeafSnn35248 brand_unregister(brand_t *brand) 1549acbbeafSnn35248 { 1559acbbeafSnn35248 struct brand_list *list, *prev; 1569acbbeafSnn35248 1579acbbeafSnn35248 /* Sanity checks */ 1589acbbeafSnn35248 if (brand == NULL || brand->b_name == NULL) { 1599acbbeafSnn35248 cmn_err(CE_WARN, "Malformed brand"); 1609acbbeafSnn35248 return (EINVAL); 1619acbbeafSnn35248 } 1629acbbeafSnn35248 1639acbbeafSnn35248 prev = NULL; 1649acbbeafSnn35248 mutex_enter(&brand_list_lock); 1659acbbeafSnn35248 1669acbbeafSnn35248 for (list = brand_list; list != NULL; list = list->bl_next) { 1679acbbeafSnn35248 if (list->bl_brand == brand) 1689acbbeafSnn35248 break; 1699acbbeafSnn35248 prev = list; 1709acbbeafSnn35248 } 1719acbbeafSnn35248 1729acbbeafSnn35248 if (list == NULL) { 1739acbbeafSnn35248 cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name); 1749acbbeafSnn35248 mutex_exit(&brand_list_lock); 1759acbbeafSnn35248 return (EINVAL); 1769acbbeafSnn35248 } 1779acbbeafSnn35248 1789acbbeafSnn35248 if (list->bl_refcnt > 0) { 1799acbbeafSnn35248 cmn_err(CE_WARN, "Unregistering brand %s which is still in use", 1809acbbeafSnn35248 brand->b_name); 1819acbbeafSnn35248 mutex_exit(&brand_list_lock); 1829acbbeafSnn35248 return (EBUSY); 1839acbbeafSnn35248 } 1849acbbeafSnn35248 1859acbbeafSnn35248 /* Remove brand from the list */ 1869acbbeafSnn35248 if (prev != NULL) 1879acbbeafSnn35248 prev->bl_next = list->bl_next; 1889acbbeafSnn35248 else 1899acbbeafSnn35248 brand_list = list->bl_next; 1909acbbeafSnn35248 191725deb8fSedp #if defined(__sparcv9) 192725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */ 193725deb8fSedp if (brand_list == NULL) 194725deb8fSedp brand_plat_interposition_disable(); 195725deb8fSedp #endif /* __sparcv9 */ 196725deb8fSedp 1979acbbeafSnn35248 mutex_exit(&brand_list_lock); 1989acbbeafSnn35248 1999acbbeafSnn35248 kmem_free(list, sizeof (struct brand_list)); 2009acbbeafSnn35248 2019acbbeafSnn35248 return (0); 2029acbbeafSnn35248 } 2039acbbeafSnn35248 2049acbbeafSnn35248 /* 2059acbbeafSnn35248 * Record that a zone of this brand has been instantiated. If the kernel 2069acbbeafSnn35248 * module implementing this brand's functionality is not present, this 2079acbbeafSnn35248 * routine attempts to load the module as a side effect. 2089acbbeafSnn35248 */ 2099acbbeafSnn35248 brand_t * 2109acbbeafSnn35248 brand_register_zone(struct brand_attr *attr) 2119acbbeafSnn35248 { 2129acbbeafSnn35248 struct brand_list *l = NULL; 2139acbbeafSnn35248 ddi_modhandle_t hdl = NULL; 2149acbbeafSnn35248 char *modname; 2159acbbeafSnn35248 int err = 0; 2169acbbeafSnn35248 2179acbbeafSnn35248 if (is_system_labeled()) { 2189acbbeafSnn35248 cmn_err(CE_WARN, 2199acbbeafSnn35248 "Branded zones are not allowed on labeled systems."); 2209acbbeafSnn35248 return (NULL); 2219acbbeafSnn35248 } 2229acbbeafSnn35248 2239acbbeafSnn35248 /* 2249acbbeafSnn35248 * We make at most two passes through this loop. The first time 2259acbbeafSnn35248 * through, we're looking to see if this is a new user of an 2269acbbeafSnn35248 * already loaded brand. If the brand hasn't been loaded, we 2279acbbeafSnn35248 * call ddi_modopen() to force it to be loaded and then make a 2289acbbeafSnn35248 * second pass through the list of brands. If we don't find the 2299acbbeafSnn35248 * brand the second time through it means that the modname 2309acbbeafSnn35248 * specified in the brand_attr structure doesn't provide the brand 2319acbbeafSnn35248 * specified in the brandname field. This would suggest a bug in 2329acbbeafSnn35248 * the brand's config.xml file. We close the module and return 2339acbbeafSnn35248 * 'NULL' to the caller. 2349acbbeafSnn35248 */ 2359acbbeafSnn35248 for (;;) { 2369acbbeafSnn35248 /* 2379acbbeafSnn35248 * Search list of loaded brands 2389acbbeafSnn35248 */ 2399acbbeafSnn35248 mutex_enter(&brand_list_lock); 2409acbbeafSnn35248 for (l = brand_list; l != NULL; l = l->bl_next) 2419acbbeafSnn35248 if (strcmp(attr->ba_brandname, 2429acbbeafSnn35248 l->bl_brand->b_name) == 0) 2439acbbeafSnn35248 break; 2449acbbeafSnn35248 if ((l != NULL) || (hdl != NULL)) 2459acbbeafSnn35248 break; 2469acbbeafSnn35248 mutex_exit(&brand_list_lock); 2479acbbeafSnn35248 2489acbbeafSnn35248 /* 2499acbbeafSnn35248 * We didn't find that the requested brand has been loaded 2509acbbeafSnn35248 * yet, so we trigger the load of the appropriate kernel 2519acbbeafSnn35248 * module and search the list again. 2529acbbeafSnn35248 */ 2539acbbeafSnn35248 modname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2549acbbeafSnn35248 (void) strcpy(modname, "brand/"); 2559acbbeafSnn35248 (void) strcat(modname, attr->ba_modname); 2569acbbeafSnn35248 hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err); 2579acbbeafSnn35248 kmem_free(modname, MAXPATHLEN); 2589acbbeafSnn35248 2599acbbeafSnn35248 if (err != 0) 2609acbbeafSnn35248 return (NULL); 2619acbbeafSnn35248 } 2629acbbeafSnn35248 2639acbbeafSnn35248 /* 2649acbbeafSnn35248 * If we found the matching brand, bump its reference count. 2659acbbeafSnn35248 */ 2669acbbeafSnn35248 if (l != NULL) 2679acbbeafSnn35248 l->bl_refcnt++; 2689acbbeafSnn35248 2699acbbeafSnn35248 mutex_exit(&brand_list_lock); 2709acbbeafSnn35248 2719acbbeafSnn35248 if (hdl != NULL) 2729acbbeafSnn35248 (void) ddi_modclose(hdl); 2739acbbeafSnn35248 2749acbbeafSnn35248 return ((l != NULL) ? l->bl_brand : NULL); 2759acbbeafSnn35248 } 2769acbbeafSnn35248 2779acbbeafSnn35248 /* 2789acbbeafSnn35248 * Return the number of zones currently using this brand. 2799acbbeafSnn35248 */ 2809acbbeafSnn35248 int 2819acbbeafSnn35248 brand_zone_count(struct brand *bp) 2829acbbeafSnn35248 { 2839acbbeafSnn35248 struct brand_list *l; 2849acbbeafSnn35248 int cnt = 0; 2859acbbeafSnn35248 2869acbbeafSnn35248 mutex_enter(&brand_list_lock); 2879acbbeafSnn35248 for (l = brand_list; l != NULL; l = l->bl_next) 2889acbbeafSnn35248 if (l->bl_brand == bp) { 2899acbbeafSnn35248 cnt = l->bl_refcnt; 2909acbbeafSnn35248 break; 2919acbbeafSnn35248 } 2929acbbeafSnn35248 mutex_exit(&brand_list_lock); 2939acbbeafSnn35248 2949acbbeafSnn35248 return (cnt); 2959acbbeafSnn35248 } 2969acbbeafSnn35248 2979acbbeafSnn35248 void 2989acbbeafSnn35248 brand_unregister_zone(struct brand *bp) 2999acbbeafSnn35248 { 3009acbbeafSnn35248 struct brand_list *list; 3019acbbeafSnn35248 3029acbbeafSnn35248 mutex_enter(&brand_list_lock); 3039acbbeafSnn35248 for (list = brand_list; list != NULL; list = list->bl_next) { 3049acbbeafSnn35248 if (list->bl_brand == bp) { 3059acbbeafSnn35248 ASSERT(list->bl_refcnt > 0); 3069acbbeafSnn35248 list->bl_refcnt--; 3079acbbeafSnn35248 break; 3089acbbeafSnn35248 } 3099acbbeafSnn35248 } 3109acbbeafSnn35248 mutex_exit(&brand_list_lock); 3119acbbeafSnn35248 } 3129acbbeafSnn35248 3139acbbeafSnn35248 void 3149acbbeafSnn35248 brand_setbrand(proc_t *p) 3159acbbeafSnn35248 { 3169acbbeafSnn35248 brand_t *bp = p->p_zone->zone_brand; 3179acbbeafSnn35248 3189acbbeafSnn35248 ASSERT(bp != NULL); 3199acbbeafSnn35248 ASSERT(p->p_brand == &native_brand); 3209acbbeafSnn35248 3219acbbeafSnn35248 /* 3229acbbeafSnn35248 * We should only be called from exec(), when we know the process 3239acbbeafSnn35248 * is single-threaded. 3249acbbeafSnn35248 */ 3259acbbeafSnn35248 ASSERT(p->p_tlist == p->p_tlist->t_forw); 3269acbbeafSnn35248 3279acbbeafSnn35248 p->p_brand = bp; 328fd9e7635Sedp ASSERT(PROC_IS_BRANDED(p)); 3299acbbeafSnn35248 BROP(p)->b_setbrand(p); 3309acbbeafSnn35248 } 331fd9e7635Sedp 332fd9e7635Sedp void 333*e9f7cbf0SVamsi Nagineni brand_clearbrand(proc_t *p, boolean_t no_lwps) 334fd9e7635Sedp { 335fd9e7635Sedp brand_t *bp = p->p_zone->zone_brand; 336*e9f7cbf0SVamsi Nagineni klwp_t *lwp = NULL; 337fd9e7635Sedp ASSERT(bp != NULL); 338*e9f7cbf0SVamsi Nagineni ASSERT(!no_lwps || (p->p_tlist == NULL)); 339fd9e7635Sedp 340fd9e7635Sedp /* 341*e9f7cbf0SVamsi Nagineni * If called from exec_common() or proc_exit(), 342*e9f7cbf0SVamsi Nagineni * we know the process is single-threaded. 343*e9f7cbf0SVamsi Nagineni * If called from fork_fail, p_tlist is NULL. 344fd9e7635Sedp */ 345*e9f7cbf0SVamsi Nagineni if (!no_lwps) { 346fd9e7635Sedp ASSERT(p->p_tlist == p->p_tlist->t_forw); 347*e9f7cbf0SVamsi Nagineni lwp = p->p_tlist->t_lwp; 348*e9f7cbf0SVamsi Nagineni } 349fd9e7635Sedp 350fd9e7635Sedp ASSERT(PROC_IS_BRANDED(p)); 351*e9f7cbf0SVamsi Nagineni BROP(p)->b_proc_exit(p, lwp); 352fd9e7635Sedp p->p_brand = &native_brand; 3539acbbeafSnn35248 } 35459f2ff5cSedp 35559f2ff5cSedp #if defined(__sparcv9) 35659f2ff5cSedp /* 357725deb8fSedp * Currently, only sparc has system level brand syscall interposition. 35859f2ff5cSedp * On x86 we're able to enable syscall interposition on a per-cpu basis 35959f2ff5cSedp * when a branded thread is scheduled to run on a cpu. 36059f2ff5cSedp */ 36159f2ff5cSedp 36259f2ff5cSedp /* Local variables needed for dynamic syscall interposition support */ 36359f2ff5cSedp static uint32_t syscall_trap_patch_instr_orig; 36459f2ff5cSedp static uint32_t syscall_trap32_patch_instr_orig; 36559f2ff5cSedp 36659f2ff5cSedp /* Trap Table syscall entry hot patch points */ 36759f2ff5cSedp extern void syscall_trap_patch_point(void); 36859f2ff5cSedp extern void syscall_trap32_patch_point(void); 36959f2ff5cSedp 37059f2ff5cSedp /* Alternate syscall entry handlers used when branded zones are running */ 37159f2ff5cSedp extern void syscall_wrapper(void); 37259f2ff5cSedp extern void syscall_wrapper32(void); 37359f2ff5cSedp 37459f2ff5cSedp /* Macros used to facilitate sparcv9 instruction generation */ 37559f2ff5cSedp #define BA_A_INSTR 0x30800000 /* ba,a addr */ 37659f2ff5cSedp #define DISP22(from, to) \ 37759f2ff5cSedp ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & 0x3fffff) 37859f2ff5cSedp 37959f2ff5cSedp /*ARGSUSED*/ 380725deb8fSedp static void 381725deb8fSedp brand_plat_interposition_enable(void) 38259f2ff5cSedp { 383725deb8fSedp ASSERT(MUTEX_HELD(&brand_list_lock)); 38459f2ff5cSedp 38559f2ff5cSedp /* 38659f2ff5cSedp * Before we hot patch the kernel save the current instructions 387725deb8fSedp * so that we can restore them later. 38859f2ff5cSedp */ 38959f2ff5cSedp syscall_trap_patch_instr_orig = 39059f2ff5cSedp *(uint32_t *)syscall_trap_patch_point; 39159f2ff5cSedp syscall_trap32_patch_instr_orig = 39259f2ff5cSedp *(uint32_t *)syscall_trap32_patch_point; 39359f2ff5cSedp 39459f2ff5cSedp /* 39559f2ff5cSedp * Modify the trap table at the patch points. 39659f2ff5cSedp * 39759f2ff5cSedp * We basically replace the first instruction at the patch 39859f2ff5cSedp * point with a ba,a instruction that will transfer control 39959f2ff5cSedp * to syscall_wrapper or syscall_wrapper32 for 64-bit and 40059f2ff5cSedp * 32-bit syscalls respectively. It's important to note that 40159f2ff5cSedp * the annul bit is set in the branch so we don't execute 40259f2ff5cSedp * the instruction directly following the one we're patching 40359f2ff5cSedp * during the branch's delay slot. 40459f2ff5cSedp * 40559f2ff5cSedp * It also doesn't matter that we're not atomically updating both 40659f2ff5cSedp * the 64 and 32 bit syscall paths at the same time since there's 40759f2ff5cSedp * no actual branded processes running on the system yet. 40859f2ff5cSedp */ 40959f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point, 41059f2ff5cSedp BA_A_INSTR | DISP22(syscall_trap_patch_point, syscall_wrapper), 41159f2ff5cSedp 4); 41259f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point, 41359f2ff5cSedp BA_A_INSTR | DISP22(syscall_trap32_patch_point, syscall_wrapper32), 41459f2ff5cSedp 4); 41559f2ff5cSedp } 41659f2ff5cSedp 41759f2ff5cSedp /*ARGSUSED*/ 418725deb8fSedp static void 419725deb8fSedp brand_plat_interposition_disable(void) 42059f2ff5cSedp { 421725deb8fSedp ASSERT(MUTEX_HELD(&brand_list_lock)); 42259f2ff5cSedp 42359f2ff5cSedp /* 42459f2ff5cSedp * Restore the original instructions at the trap table syscall 42559f2ff5cSedp * patch points to disable the brand syscall interposition 42659f2ff5cSedp * mechanism. 42759f2ff5cSedp */ 42859f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point, 42959f2ff5cSedp syscall_trap_patch_instr_orig, 4); 43059f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point, 43159f2ff5cSedp syscall_trap32_patch_instr_orig, 4); 43259f2ff5cSedp } 43359f2ff5cSedp #endif /* __sparcv9 */ 43480e2ca85S 43580e2ca85S /* 43680e2ca85S * The following functions can be shared among kernel brand modules which 43780e2ca85S * implement Solaris-derived brands, all of which need to do similar tasks 43880e2ca85S * to manage the brand. 43980e2ca85S */ 44080e2ca85S 44180e2ca85S #if defined(_LP64) 44280e2ca85S static void 44380e2ca85S Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst) 44480e2ca85S { 44580e2ca85S bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident)); 44680e2ca85S dst->e_type = src->e_type; 44780e2ca85S dst->e_machine = src->e_machine; 44880e2ca85S dst->e_version = src->e_version; 44980e2ca85S dst->e_entry = src->e_entry; 45080e2ca85S dst->e_phoff = src->e_phoff; 45180e2ca85S dst->e_shoff = src->e_shoff; 45280e2ca85S dst->e_flags = src->e_flags; 45380e2ca85S dst->e_ehsize = src->e_ehsize; 45480e2ca85S dst->e_phentsize = src->e_phentsize; 45580e2ca85S dst->e_phnum = src->e_phnum; 45680e2ca85S dst->e_shentsize = src->e_shentsize; 45780e2ca85S dst->e_shnum = src->e_shnum; 45880e2ca85S dst->e_shstrndx = src->e_shstrndx; 45980e2ca85S } 46080e2ca85S #endif /* _LP64 */ 46180e2ca85S 46280e2ca85S /* 46380e2ca85S * Return -1 if the cmd was not handled by this function. 46480e2ca85S */ 46580e2ca85S /*ARGSUSED*/ 46680e2ca85S int 46780e2ca85S brand_solaris_cmd(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, 46880e2ca85S struct brand *pbrand, int brandvers) 46980e2ca85S { 47080e2ca85S brand_proc_data_t *spd; 47180e2ca85S brand_proc_reg_t reg; 47280e2ca85S proc_t *p = curproc; 47380e2ca85S int err; 47480e2ca85S 47580e2ca85S /* 47680e2ca85S * There is one operation that is supported for a native 47780e2ca85S * process; B_EXEC_BRAND. This brand operaion is redundant 47880e2ca85S * since the kernel assumes a native process doing an exec 47980e2ca85S * in a branded zone is going to run a branded processes. 48080e2ca85S * hence we don't support this operation. 48180e2ca85S */ 48280e2ca85S if (cmd == B_EXEC_BRAND) 48380e2ca85S return (ENOSYS); 48480e2ca85S 48580e2ca85S /* For all other operations this must be a branded process. */ 48680e2ca85S if (p->p_brand == &native_brand) 48780e2ca85S return (ENOSYS); 48880e2ca85S 48980e2ca85S ASSERT(p->p_brand == pbrand); 49080e2ca85S ASSERT(p->p_brand_data != NULL); 49180e2ca85S 49280e2ca85S spd = (brand_proc_data_t *)p->p_brand_data; 49380e2ca85S 49480e2ca85S switch ((cmd)) { 49580e2ca85S case B_EXEC_NATIVE: 49680e2ca85S err = exec_common((char *)arg1, (const char **)arg2, 49780e2ca85S (const char **)arg3, EBA_NATIVE); 49880e2ca85S return (err); 49980e2ca85S 50080e2ca85S /* 50180e2ca85S * Get the address of the user-space system call handler from 50280e2ca85S * the user process and attach it to the proc structure. 50380e2ca85S */ 50480e2ca85S case B_REGISTER: 50580e2ca85S if (p->p_model == DATAMODEL_NATIVE) { 50680e2ca85S if (copyin((void *)arg1, ®, sizeof (reg)) != 0) 50780e2ca85S return (EFAULT); 50880e2ca85S } 50980e2ca85S #if defined(_LP64) 51080e2ca85S else { 51180e2ca85S brand_common_reg32_t reg32; 51280e2ca85S 51380e2ca85S if (copyin((void *)arg1, ®32, sizeof (reg32)) != 0) 51480e2ca85S return (EFAULT); 51580e2ca85S reg.sbr_version = reg32.sbr_version; 51680e2ca85S reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler; 51780e2ca85S } 51880e2ca85S #endif /* _LP64 */ 51980e2ca85S 52080e2ca85S if (reg.sbr_version != brandvers) 52180e2ca85S return (ENOTSUP); 52280e2ca85S spd->spd_handler = reg.sbr_handler; 52380e2ca85S return (0); 52480e2ca85S 52580e2ca85S case B_ELFDATA: 52680e2ca85S if (p->p_model == DATAMODEL_NATIVE) { 52780e2ca85S if (copyout(&spd->spd_elf_data, (void *)arg1, 52880e2ca85S sizeof (brand_elf_data_t)) != 0) 52980e2ca85S return (EFAULT); 53080e2ca85S } 53180e2ca85S #if defined(_LP64) 53280e2ca85S else { 53380e2ca85S brand_elf_data32_t sed32; 53480e2ca85S 53580e2ca85S sed32.sed_phdr = spd->spd_elf_data.sed_phdr; 53680e2ca85S sed32.sed_phent = spd->spd_elf_data.sed_phent; 53780e2ca85S sed32.sed_phnum = spd->spd_elf_data.sed_phnum; 53880e2ca85S sed32.sed_entry = spd->spd_elf_data.sed_entry; 53980e2ca85S sed32.sed_base = spd->spd_elf_data.sed_base; 54080e2ca85S sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry; 54180e2ca85S sed32.sed_lddata = spd->spd_elf_data.sed_lddata; 54280e2ca85S if (copyout(&sed32, (void *)arg1, sizeof (sed32)) 54380e2ca85S != 0) 54480e2ca85S return (EFAULT); 54580e2ca85S } 54680e2ca85S #endif /* _LP64 */ 54780e2ca85S return (0); 54880e2ca85S 54980e2ca85S /* 55080e2ca85S * The B_TRUSS_POINT subcommand exists so that we can see 55180e2ca85S * truss output from interposed system calls that return 55280e2ca85S * without first calling any other system call, meaning they 55380e2ca85S * would be invisible to truss(1). 55480e2ca85S * If the second argument is set non-zero, set errno to that 55580e2ca85S * value as well. 55680e2ca85S * 55780e2ca85S * Common arguments seen with truss are: 55880e2ca85S * 55980e2ca85S * arg1: syscall number 56080e2ca85S * arg2: errno 56180e2ca85S */ 56280e2ca85S case B_TRUSS_POINT: 56380e2ca85S return ((arg2 == 0) ? 0 : set_errno((uint_t)arg2)); 56480e2ca85S } 56580e2ca85S 56680e2ca85S return (-1); 56780e2ca85S } 56880e2ca85S 56980e2ca85S /*ARGSUSED*/ 57080e2ca85S void 57180e2ca85S brand_solaris_copy_procdata(proc_t *child, proc_t *parent, struct brand *pbrand) 57280e2ca85S { 57380e2ca85S brand_proc_data_t *spd; 57480e2ca85S 57580e2ca85S ASSERT(parent->p_brand == pbrand); 57680e2ca85S ASSERT(child->p_brand == pbrand); 57780e2ca85S ASSERT(parent->p_brand_data != NULL); 57880e2ca85S ASSERT(child->p_brand_data == NULL); 57980e2ca85S 58080e2ca85S /* 58180e2ca85S * Just duplicate all the proc data of the parent for the 58280e2ca85S * child 58380e2ca85S */ 58480e2ca85S spd = kmem_alloc(sizeof (brand_proc_data_t), KM_SLEEP); 58580e2ca85S bcopy(parent->p_brand_data, spd, sizeof (brand_proc_data_t)); 58680e2ca85S child->p_brand_data = spd; 58780e2ca85S } 58880e2ca85S 5892ab1f1ecS static void 5902ab1f1ecS restoreexecenv(struct execenv *ep, stack_t *sp) 5912ab1f1ecS { 5922ab1f1ecS klwp_t *lwp = ttolwp(curthread); 5932ab1f1ecS 5942ab1f1ecS setexecenv(ep); 5952ab1f1ecS lwp->lwp_sigaltstack.ss_sp = sp->ss_sp; 5962ab1f1ecS lwp->lwp_sigaltstack.ss_size = sp->ss_size; 5972ab1f1ecS lwp->lwp_sigaltstack.ss_flags = sp->ss_flags; 5982ab1f1ecS } 5992ab1f1ecS 60080e2ca85S /*ARGSUSED*/ 60180e2ca85S int 60280e2ca85S brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, 60380e2ca85S intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file, 60480e2ca85S cred_t *cred, int brand_action, struct brand *pbrand, char *bname, 60580e2ca85S char *brandlib, char *brandlib32, char *brandlinker, char *brandlinker32) 60680e2ca85S { 60780e2ca85S 60880e2ca85S vnode_t *nvp; 60980e2ca85S Ehdr ehdr; 61080e2ca85S Addr uphdr_vaddr; 61180e2ca85S intptr_t voffset; 61280e2ca85S int interp; 61380e2ca85S int i, err; 61480e2ca85S struct execenv env; 6152ab1f1ecS struct execenv origenv; 6162ab1f1ecS stack_t orig_sigaltstack; 61780e2ca85S struct user *up = PTOU(curproc); 6182ab1f1ecS proc_t *p = ttoproc(curthread); 6192ab1f1ecS klwp_t *lwp = ttolwp(curthread); 62080e2ca85S brand_proc_data_t *spd; 62180e2ca85S brand_elf_data_t sed, *sedp; 62280e2ca85S char *linker; 62380e2ca85S uintptr_t lddata; /* lddata of executable's linker */ 62480e2ca85S 62580e2ca85S ASSERT(curproc->p_brand == pbrand); 62680e2ca85S ASSERT(curproc->p_brand_data != NULL); 62780e2ca85S 62880e2ca85S spd = (brand_proc_data_t *)curproc->p_brand_data; 62980e2ca85S sedp = &spd->spd_elf_data; 63080e2ca85S 63180e2ca85S args->brandname = bname; 63280e2ca85S 63380e2ca85S /* 63480e2ca85S * We will exec the brand library and then map in the target 63580e2ca85S * application and (optionally) the brand's default linker. 63680e2ca85S */ 63780e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 63880e2ca85S args->emulator = brandlib; 63980e2ca85S linker = brandlinker; 64080e2ca85S } 64180e2ca85S #if defined(_LP64) 64280e2ca85S else { 64380e2ca85S args->emulator = brandlib32; 64480e2ca85S linker = brandlinker32; 64580e2ca85S } 64680e2ca85S #endif /* _LP64 */ 64780e2ca85S 64880e2ca85S if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW, 64980e2ca85S NULLVPP, &nvp)) != 0) { 65080e2ca85S uprintf("%s: not found.", args->emulator); 65180e2ca85S return (err); 65280e2ca85S } 65380e2ca85S 6542ab1f1ecS /* 6552ab1f1ecS * The following elf{32}exec call changes the execenv in the proc 6562ab1f1ecS * struct which includes changing the p_exec member to be the vnode 6572ab1f1ecS * for the brand library (e.g. /.SUNWnative/usr/lib/s10_brand.so.1). 6582ab1f1ecS * We will eventually set the p_exec member to be the vnode for the new 6592ab1f1ecS * executable when we call setexecenv(). However, if we get an error 6602ab1f1ecS * before that call we need to restore the execenv to its original 6612ab1f1ecS * values so that when we return to the caller fop_close() works 6622ab1f1ecS * properly while cleaning up from the failed exec(). Restoring the 6632ab1f1ecS * original value will also properly decrement the 2nd VN_RELE that we 6642ab1f1ecS * took on the brand library. 6652ab1f1ecS */ 6662ab1f1ecS origenv.ex_bssbase = p->p_bssbase; 6672ab1f1ecS origenv.ex_brkbase = p->p_brkbase; 6682ab1f1ecS origenv.ex_brksize = p->p_brksize; 6692ab1f1ecS origenv.ex_vp = p->p_exec; 6702ab1f1ecS orig_sigaltstack.ss_sp = lwp->lwp_sigaltstack.ss_sp; 6712ab1f1ecS orig_sigaltstack.ss_size = lwp->lwp_sigaltstack.ss_size; 6722ab1f1ecS orig_sigaltstack.ss_flags = lwp->lwp_sigaltstack.ss_flags; 6732ab1f1ecS 67480e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 67580e2ca85S err = elfexec(nvp, uap, args, idatap, level + 1, execsz, 67680e2ca85S setid, exec_file, cred, brand_action); 67780e2ca85S } 67880e2ca85S #if defined(_LP64) 67980e2ca85S else { 68080e2ca85S err = elf32exec(nvp, uap, args, idatap, level + 1, execsz, 68180e2ca85S setid, exec_file, cred, brand_action); 68280e2ca85S } 68380e2ca85S #endif /* _LP64 */ 68480e2ca85S VN_RELE(nvp); 6852ab1f1ecS if (err != 0) { 6862ab1f1ecS restoreexecenv(&origenv, &orig_sigaltstack); 68780e2ca85S return (err); 6882ab1f1ecS } 68980e2ca85S 69080e2ca85S /* 69180e2ca85S * The u_auxv veCTors are set up by elfexec to point to the 69280e2ca85S * brand emulation library and linker. Save these so they can 69380e2ca85S * be copied to the specific brand aux vectors. 69480e2ca85S */ 69580e2ca85S bzero(&sed, sizeof (sed)); 69680e2ca85S for (i = 0; i < __KERN_NAUXV_IMPL; i++) { 69780e2ca85S switch (up->u_auxv[i].a_type) { 69880e2ca85S case AT_SUN_LDDATA: 69980e2ca85S sed.sed_lddata = up->u_auxv[i].a_un.a_val; 70080e2ca85S break; 70180e2ca85S case AT_BASE: 70280e2ca85S sed.sed_base = up->u_auxv[i].a_un.a_val; 70380e2ca85S break; 70480e2ca85S case AT_ENTRY: 70580e2ca85S sed.sed_entry = up->u_auxv[i].a_un.a_val; 70680e2ca85S break; 70780e2ca85S case AT_PHDR: 70880e2ca85S sed.sed_phdr = up->u_auxv[i].a_un.a_val; 70980e2ca85S break; 71080e2ca85S case AT_PHENT: 71180e2ca85S sed.sed_phent = up->u_auxv[i].a_un.a_val; 71280e2ca85S break; 71380e2ca85S case AT_PHNUM: 71480e2ca85S sed.sed_phnum = up->u_auxv[i].a_un.a_val; 71580e2ca85S break; 71680e2ca85S default: 71780e2ca85S break; 71880e2ca85S } 71980e2ca85S } 72080e2ca85S /* Make sure the emulator has an entry point */ 72180e2ca85S ASSERT(sed.sed_entry != NULL); 72280e2ca85S ASSERT(sed.sed_phdr != NULL); 72380e2ca85S 72480e2ca85S bzero(&env, sizeof (env)); 72580e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 72680e2ca85S err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr, 72780e2ca85S &voffset, exec_file, &interp, &env.ex_bssbase, 72880e2ca85S &env.ex_brkbase, &env.ex_brksize, NULL); 72980e2ca85S } 73080e2ca85S #if defined(_LP64) 73180e2ca85S else { 73280e2ca85S Elf32_Ehdr ehdr32; 73380e2ca85S Elf32_Addr uphdr_vaddr32; 73480e2ca85S err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32, 73580e2ca85S &voffset, exec_file, &interp, &env.ex_bssbase, 73680e2ca85S &env.ex_brkbase, &env.ex_brksize, NULL); 73780e2ca85S Ehdr32to64(&ehdr32, &ehdr); 73880e2ca85S 73980e2ca85S if (uphdr_vaddr32 == (Elf32_Addr)-1) 74080e2ca85S uphdr_vaddr = (Addr)-1; 74180e2ca85S else 74280e2ca85S uphdr_vaddr = uphdr_vaddr32; 74380e2ca85S } 74480e2ca85S #endif /* _LP64 */ 7452ab1f1ecS if (err != 0) { 7462ab1f1ecS restoreexecenv(&origenv, &orig_sigaltstack); 74780e2ca85S return (err); 7482ab1f1ecS } 74980e2ca85S 75080e2ca85S /* 75180e2ca85S * Save off the important properties of the executable. The 75280e2ca85S * brand library will ask us for this data later, when it is 75380e2ca85S * initializing and getting ready to transfer control to the 75480e2ca85S * brand application. 75580e2ca85S */ 75680e2ca85S if (uphdr_vaddr == (Addr)-1) 75780e2ca85S sedp->sed_phdr = voffset + ehdr.e_phoff; 75880e2ca85S else 75980e2ca85S sedp->sed_phdr = voffset + uphdr_vaddr; 76080e2ca85S sedp->sed_entry = voffset + ehdr.e_entry; 76180e2ca85S sedp->sed_phent = ehdr.e_phentsize; 76280e2ca85S sedp->sed_phnum = ehdr.e_phnum; 76380e2ca85S 76480e2ca85S if (interp) { 76580e2ca85S if (ehdr.e_type == ET_DYN) { 76680e2ca85S /* 76780e2ca85S * This is a shared object executable, so we 76880e2ca85S * need to pick a reasonable place to put the 76980e2ca85S * heap. Just don't use the first page. 77080e2ca85S */ 77180e2ca85S env.ex_brkbase = (caddr_t)PAGESIZE; 77280e2ca85S env.ex_bssbase = (caddr_t)PAGESIZE; 77380e2ca85S } 77480e2ca85S 77580e2ca85S /* 77680e2ca85S * If the program needs an interpreter (most do), map 77780e2ca85S * it in and store relevant information about it in the 77880e2ca85S * aux vector, where the brand library can find it. 77980e2ca85S */ 78080e2ca85S if ((err = lookupname(linker, UIO_SYSSPACE, 78180e2ca85S FOLLOW, NULLVPP, &nvp)) != 0) { 78280e2ca85S uprintf("%s: not found.", brandlinker); 7832ab1f1ecS restoreexecenv(&origenv, &orig_sigaltstack); 78480e2ca85S return (err); 78580e2ca85S } 78680e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 78780e2ca85S err = mapexec_brand(nvp, args, &ehdr, 78880e2ca85S &uphdr_vaddr, &voffset, exec_file, &interp, 78980e2ca85S NULL, NULL, NULL, &lddata); 79080e2ca85S } 79180e2ca85S #if defined(_LP64) 79280e2ca85S else { 79380e2ca85S Elf32_Ehdr ehdr32; 79480e2ca85S Elf32_Addr uphdr_vaddr32; 79580e2ca85S err = mapexec32_brand(nvp, args, &ehdr32, 79680e2ca85S &uphdr_vaddr32, &voffset, exec_file, &interp, 79780e2ca85S NULL, NULL, NULL, &lddata); 79880e2ca85S Ehdr32to64(&ehdr32, &ehdr); 79980e2ca85S 80080e2ca85S if (uphdr_vaddr32 == (Elf32_Addr)-1) 80180e2ca85S uphdr_vaddr = (Addr)-1; 80280e2ca85S else 80380e2ca85S uphdr_vaddr = uphdr_vaddr32; 80480e2ca85S } 80580e2ca85S #endif /* _LP64 */ 80680e2ca85S VN_RELE(nvp); 8072ab1f1ecS if (err != 0) { 8082ab1f1ecS restoreexecenv(&origenv, &orig_sigaltstack); 80980e2ca85S return (err); 8102ab1f1ecS } 81180e2ca85S 81280e2ca85S /* 81380e2ca85S * Now that we know the base address of the brand's 81480e2ca85S * linker, place it in the aux vector. 81580e2ca85S */ 81680e2ca85S sedp->sed_base = voffset; 81780e2ca85S sedp->sed_ldentry = voffset + ehdr.e_entry; 81880e2ca85S sedp->sed_lddata = voffset + lddata; 81980e2ca85S } else { 82080e2ca85S /* 82180e2ca85S * This program has no interpreter. The brand library 82280e2ca85S * will jump to the address in the AT_SUN_BRAND_LDENTRY 82380e2ca85S * aux vector, so in this case, put the entry point of 82480e2ca85S * the main executable there. 82580e2ca85S */ 82680e2ca85S if (ehdr.e_type == ET_EXEC) { 82780e2ca85S /* 82880e2ca85S * An executable with no interpreter, this must 82980e2ca85S * be a statically linked executable, which 83080e2ca85S * means we loaded it at the address specified 83180e2ca85S * in the elf header, in which case the e_entry 83280e2ca85S * field of the elf header is an absolute 83380e2ca85S * address. 83480e2ca85S */ 83580e2ca85S sedp->sed_ldentry = ehdr.e_entry; 83680e2ca85S sedp->sed_entry = ehdr.e_entry; 83780e2ca85S sedp->sed_lddata = NULL; 83880e2ca85S sedp->sed_base = NULL; 83980e2ca85S } else { 84080e2ca85S /* 84180e2ca85S * A shared object with no interpreter, we use 84280e2ca85S * the calculated address from above. 84380e2ca85S */ 84480e2ca85S sedp->sed_ldentry = sedp->sed_entry; 84580e2ca85S sedp->sed_entry = NULL; 84680e2ca85S sedp->sed_phdr = NULL; 84780e2ca85S sedp->sed_phent = NULL; 84880e2ca85S sedp->sed_phnum = NULL; 84980e2ca85S sedp->sed_lddata = NULL; 85080e2ca85S sedp->sed_base = voffset; 85180e2ca85S 85280e2ca85S if (ehdr.e_type == ET_DYN) { 85380e2ca85S /* 85480e2ca85S * Delay setting the brkbase until the 85580e2ca85S * first call to brk(); see elfexec() 85680e2ca85S * for details. 85780e2ca85S */ 85880e2ca85S env.ex_bssbase = (caddr_t)0; 85980e2ca85S env.ex_brkbase = (caddr_t)0; 86080e2ca85S env.ex_brksize = 0; 86180e2ca85S } 86280e2ca85S } 86380e2ca85S } 86480e2ca85S 86580e2ca85S env.ex_magic = elfmagic; 86680e2ca85S env.ex_vp = vp; 86780e2ca85S setexecenv(&env); 86880e2ca85S 86980e2ca85S /* 87080e2ca85S * It's time to manipulate the process aux vectors. First 87180e2ca85S * we need to update the AT_SUN_AUXFLAGS aux vector to set 87280e2ca85S * the AF_SUN_NOPLM flag. 87380e2ca85S */ 87480e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 87580e2ca85S auxv_t auxflags_auxv; 87680e2ca85S 87780e2ca85S if (copyin(args->auxp_auxflags, &auxflags_auxv, 87880e2ca85S sizeof (auxflags_auxv)) != 0) 87980e2ca85S return (EFAULT); 88080e2ca85S 88180e2ca85S ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS); 88280e2ca85S auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM; 88380e2ca85S if (copyout(&auxflags_auxv, args->auxp_auxflags, 88480e2ca85S sizeof (auxflags_auxv)) != 0) 88580e2ca85S return (EFAULT); 88680e2ca85S } 88780e2ca85S #if defined(_LP64) 88880e2ca85S else { 88980e2ca85S auxv32_t auxflags_auxv32; 89080e2ca85S 89180e2ca85S if (copyin(args->auxp_auxflags, &auxflags_auxv32, 89280e2ca85S sizeof (auxflags_auxv32)) != 0) 89380e2ca85S return (EFAULT); 89480e2ca85S 89580e2ca85S ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS); 89680e2ca85S auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM; 89780e2ca85S if (copyout(&auxflags_auxv32, args->auxp_auxflags, 89880e2ca85S sizeof (auxflags_auxv32)) != 0) 89980e2ca85S return (EFAULT); 90080e2ca85S } 90180e2ca85S #endif /* _LP64 */ 90280e2ca85S 90380e2ca85S /* Second, copy out the brand specific aux vectors. */ 90480e2ca85S if (args->to_model == DATAMODEL_NATIVE) { 90580e2ca85S auxv_t brand_auxv[] = { 90680e2ca85S { AT_SUN_BRAND_AUX1, 0 }, 90780e2ca85S { AT_SUN_BRAND_AUX2, 0 }, 90880e2ca85S { AT_SUN_BRAND_AUX3, 0 } 90980e2ca85S }; 91080e2ca85S 91180e2ca85S ASSERT(brand_auxv[0].a_type == 91280e2ca85S AT_SUN_BRAND_COMMON_LDDATA); 91380e2ca85S brand_auxv[0].a_un.a_val = sed.sed_lddata; 91480e2ca85S 91580e2ca85S if (copyout(&brand_auxv, args->auxp_brand, 91680e2ca85S sizeof (brand_auxv)) != 0) 91780e2ca85S return (EFAULT); 91880e2ca85S } 91980e2ca85S #if defined(_LP64) 92080e2ca85S else { 92180e2ca85S auxv32_t brand_auxv32[] = { 92280e2ca85S { AT_SUN_BRAND_AUX1, 0 }, 92380e2ca85S { AT_SUN_BRAND_AUX2, 0 }, 92480e2ca85S { AT_SUN_BRAND_AUX3, 0 } 92580e2ca85S }; 92680e2ca85S 92780e2ca85S ASSERT(brand_auxv32[0].a_type == AT_SUN_BRAND_COMMON_LDDATA); 92880e2ca85S brand_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata; 92980e2ca85S if (copyout(&brand_auxv32, args->auxp_brand, 93080e2ca85S sizeof (brand_auxv32)) != 0) 93180e2ca85S return (EFAULT); 93280e2ca85S } 93380e2ca85S #endif /* _LP64 */ 93480e2ca85S 93580e2ca85S /* 93680e2ca85S * Third, the /proc aux vectors set up by elfexec() point to 93780e2ca85S * brand emulation library and it's linker. Copy these to the 93880e2ca85S * /proc brand specific aux vector, and update the regular 93980e2ca85S * /proc aux vectors to point to the executable (and it's 94080e2ca85S * linker). This will enable debuggers to access the 94180e2ca85S * executable via the usual /proc or elf notes aux vectors. 94280e2ca85S * 94380e2ca85S * The brand emulation library's linker will get it's aux 94480e2ca85S * vectors off the stack, and then update the stack with the 94580e2ca85S * executable's aux vectors before jumping to the executable's 94680e2ca85S * linker. 94780e2ca85S * 94880e2ca85S * Debugging the brand emulation library must be done from 94980e2ca85S * the global zone, where the librtld_db module knows how to 95080e2ca85S * fetch the brand specific aux vectors to access the brand 95180e2ca85S * emulation libraries linker. 95280e2ca85S */ 95380e2ca85S for (i = 0; i < __KERN_NAUXV_IMPL; i++) { 95480e2ca85S ulong_t val; 95580e2ca85S 95680e2ca85S switch (up->u_auxv[i].a_type) { 95780e2ca85S case AT_SUN_BRAND_COMMON_LDDATA: 95880e2ca85S up->u_auxv[i].a_un.a_val = sed.sed_lddata; 95980e2ca85S continue; 96080e2ca85S case AT_BASE: 96180e2ca85S val = sedp->sed_base; 96280e2ca85S break; 96380e2ca85S case AT_ENTRY: 96480e2ca85S val = sedp->sed_entry; 96580e2ca85S break; 96680e2ca85S case AT_PHDR: 96780e2ca85S val = sedp->sed_phdr; 96880e2ca85S break; 96980e2ca85S case AT_PHENT: 97080e2ca85S val = sedp->sed_phent; 97180e2ca85S break; 97280e2ca85S case AT_PHNUM: 97380e2ca85S val = sedp->sed_phnum; 97480e2ca85S break; 97580e2ca85S case AT_SUN_LDDATA: 97680e2ca85S val = sedp->sed_lddata; 97780e2ca85S break; 97880e2ca85S default: 97980e2ca85S continue; 98080e2ca85S } 98180e2ca85S 98280e2ca85S up->u_auxv[i].a_un.a_val = val; 98380e2ca85S if (val == NULL) { 98480e2ca85S /* Hide the entry for static binaries */ 98580e2ca85S up->u_auxv[i].a_type = AT_IGNORE; 98680e2ca85S } 98780e2ca85S } 98880e2ca85S 98980e2ca85S /* 99080e2ca85S * The last thing we do here is clear spd->spd_handler. This 99180e2ca85S * is important because if we're already a branded process and 99280e2ca85S * if this exec succeeds, there is a window between when the 99380e2ca85S * exec() first returns to the userland of the new process and 99480e2ca85S * when our brand library get's initialized, during which we 99580e2ca85S * don't want system calls to be re-directed to our brand 99680e2ca85S * library since it hasn't been initialized yet. 99780e2ca85S */ 99880e2ca85S spd->spd_handler = NULL; 99980e2ca85S 100080e2ca85S return (0); 100180e2ca85S } 100280e2ca85S 100380e2ca85S void 100480e2ca85S brand_solaris_exec(struct brand *pbrand) 100580e2ca85S { 100680e2ca85S brand_proc_data_t *spd = curproc->p_brand_data; 100780e2ca85S 100880e2ca85S ASSERT(curproc->p_brand == pbrand); 100980e2ca85S ASSERT(curproc->p_brand_data != NULL); 101080e2ca85S ASSERT(ttolwp(curthread)->lwp_brand != NULL); 101180e2ca85S 101280e2ca85S /* 101380e2ca85S * We should only be called from exec(), when we know the process 101480e2ca85S * is single-threaded. 101580e2ca85S */ 101680e2ca85S ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw); 101780e2ca85S 101880e2ca85S /* Upon exec, reset our lwp brand data. */ 101980e2ca85S (void) brand_solaris_freelwp(ttolwp(curthread), pbrand); 102080e2ca85S (void) brand_solaris_initlwp(ttolwp(curthread), pbrand); 102180e2ca85S 102280e2ca85S /* 102380e2ca85S * Upon exec, reset all the proc brand data, except for the elf 102480e2ca85S * data associated with the executable we are exec'ing. 102580e2ca85S */ 102680e2ca85S spd->spd_handler = NULL; 102780e2ca85S } 102880e2ca85S 102980e2ca85S int 103080e2ca85S brand_solaris_fini(char **emul_table, struct modlinkage *modlinkage, 103180e2ca85S struct brand *pbrand) 103280e2ca85S { 103380e2ca85S int err; 103480e2ca85S 103580e2ca85S /* 103680e2ca85S * If there are any zones using this brand, we can't allow it 103780e2ca85S * to be unloaded. 103880e2ca85S */ 103980e2ca85S if (brand_zone_count(pbrand)) 104080e2ca85S return (EBUSY); 104180e2ca85S 104280e2ca85S kmem_free(*emul_table, NSYSCALL); 104380e2ca85S *emul_table = NULL; 104480e2ca85S 104580e2ca85S err = mod_remove(modlinkage); 104680e2ca85S if (err) 104780e2ca85S cmn_err(CE_WARN, "Couldn't unload brand module"); 104880e2ca85S 104980e2ca85S return (err); 105080e2ca85S } 105180e2ca85S 105280e2ca85S /*ARGSUSED*/ 105380e2ca85S void 105480e2ca85S brand_solaris_forklwp(klwp_t *p, klwp_t *c, struct brand *pbrand) 105580e2ca85S { 105680e2ca85S ASSERT(p->lwp_procp->p_brand == pbrand); 105780e2ca85S ASSERT(c->lwp_procp->p_brand == pbrand); 105880e2ca85S 105980e2ca85S ASSERT(p->lwp_procp->p_brand_data != NULL); 106080e2ca85S ASSERT(c->lwp_procp->p_brand_data != NULL); 106180e2ca85S 106280e2ca85S /* 106380e2ca85S * Both LWPs have already had been initialized via 106480e2ca85S * brand_solaris_initlwp(). 106580e2ca85S */ 106680e2ca85S ASSERT(p->lwp_brand != NULL); 106780e2ca85S ASSERT(c->lwp_brand != NULL); 106880e2ca85S } 106980e2ca85S 107080e2ca85S /*ARGSUSED*/ 107180e2ca85S void 107280e2ca85S brand_solaris_freelwp(klwp_t *l, struct brand *pbrand) 107380e2ca85S { 107480e2ca85S ASSERT(l->lwp_procp->p_brand == pbrand); 107580e2ca85S ASSERT(l->lwp_procp->p_brand_data != NULL); 107680e2ca85S ASSERT(l->lwp_brand != NULL); 107780e2ca85S l->lwp_brand = NULL; 107880e2ca85S } 107980e2ca85S 108080e2ca85S /*ARGSUSED*/ 108180e2ca85S int 108280e2ca85S brand_solaris_initlwp(klwp_t *l, struct brand *pbrand) 108380e2ca85S { 108480e2ca85S ASSERT(l->lwp_procp->p_brand == pbrand); 108580e2ca85S ASSERT(l->lwp_procp->p_brand_data != NULL); 108680e2ca85S ASSERT(l->lwp_brand == NULL); 108780e2ca85S l->lwp_brand = (void *)-1; 108880e2ca85S return (0); 108980e2ca85S } 109080e2ca85S 109180e2ca85S /*ARGSUSED*/ 109280e2ca85S void 109380e2ca85S brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand) 109480e2ca85S { 109580e2ca85S proc_t *p = l->lwp_procp; 109680e2ca85S 109780e2ca85S ASSERT(l->lwp_procp->p_brand == pbrand); 109880e2ca85S ASSERT(l->lwp_procp->p_brand_data != NULL); 109980e2ca85S ASSERT(l->lwp_brand != NULL); 110080e2ca85S 110180e2ca85S /* 110280e2ca85S * We should never be called for the last thread in a process. 110380e2ca85S * (That case is handled by brand_solaris_proc_exit().) 110480e2ca85S * Therefore this lwp must be exiting from a multi-threaded 110580e2ca85S * process. 110680e2ca85S */ 110780e2ca85S ASSERT(p->p_tlist != p->p_tlist->t_forw); 110880e2ca85S 110980e2ca85S l->lwp_brand = NULL; 111080e2ca85S } 111180e2ca85S 111280e2ca85S /*ARGSUSED*/ 111380e2ca85S void 111480e2ca85S brand_solaris_proc_exit(struct proc *p, klwp_t *l, struct brand *pbrand) 111580e2ca85S { 111680e2ca85S ASSERT(p->p_brand == pbrand); 111780e2ca85S ASSERT(p->p_brand_data != NULL); 111880e2ca85S 111980e2ca85S /* 1120*e9f7cbf0SVamsi Nagineni * When called from proc_exit(), we know that process is 1121*e9f7cbf0SVamsi Nagineni * single-threaded and free our lwp brand data. 1122*e9f7cbf0SVamsi Nagineni * otherwise just free p_brand_data and return. 112380e2ca85S */ 1124*e9f7cbf0SVamsi Nagineni if (l != NULL) { 112580e2ca85S ASSERT(p->p_tlist == p->p_tlist->t_forw); 1126*e9f7cbf0SVamsi Nagineni ASSERT(p->p_tlist->t_lwp == l); 1127*e9f7cbf0SVamsi Nagineni (void) brand_solaris_freelwp(l, pbrand); 1128*e9f7cbf0SVamsi Nagineni } 112980e2ca85S 113080e2ca85S /* upon exit, free our proc brand data */ 113180e2ca85S kmem_free(p->p_brand_data, sizeof (brand_proc_data_t)); 113280e2ca85S p->p_brand_data = NULL; 113380e2ca85S } 113480e2ca85S 113580e2ca85S void 113680e2ca85S brand_solaris_setbrand(proc_t *p, struct brand *pbrand) 113780e2ca85S { 113880e2ca85S ASSERT(p->p_brand == pbrand); 113980e2ca85S ASSERT(p->p_brand_data == NULL); 114080e2ca85S 114180e2ca85S /* 114280e2ca85S * We should only be called from exec(), when we know the process 114380e2ca85S * is single-threaded. 114480e2ca85S */ 114580e2ca85S ASSERT(p->p_tlist == p->p_tlist->t_forw); 114680e2ca85S 114780e2ca85S p->p_brand_data = kmem_zalloc(sizeof (brand_proc_data_t), KM_SLEEP); 114880e2ca85S (void) brand_solaris_initlwp(p->p_tlist->t_lwp, pbrand); 114980e2ca85S } 1150