19acbbeafSnn /* 29acbbeafSnn * CDDL HEADER START 39acbbeafSnn * 49acbbeafSnn * The contents of this file are subject to the terms of the 59acbbeafSnn * Common Development and Distribution License (the "License"). 69acbbeafSnn * You may not use this file except in compliance with the License. 79acbbeafSnn * 89acbbeafSnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99acbbeafSnn * or http://www.opensolaris.org/os/licensing. 109acbbeafSnn * See the License for the specific language governing permissions 119acbbeafSnn * and limitations under the License. 129acbbeafSnn * 139acbbeafSnn * When distributing Covered Code, include this CDDL HEADER in each 149acbbeafSnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159acbbeafSnn * If applicable, add the following below this CDDL HEADER, with the 169acbbeafSnn * fields enclosed by brackets "[]" replaced with your own identifying 179acbbeafSnn * information: Portions Copyright [yyyy] [name of copyright owner] 189acbbeafSnn * 199acbbeafSnn * CDDL HEADER END 209acbbeafSnn */ 219acbbeafSnn /* 2280e2ca85S * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 239acbbeafSnn */ 249acbbeafSnn 259acbbeafSnn #include <sys/kmem.h> 269acbbeafSnn #include <sys/errno.h> 279acbbeafSnn #include <sys/systm.h> 289acbbeafSnn #include <sys/cmn_err.h> 299acbbeafSnn #include <sys/brand.h> 309acbbeafSnn #include <sys/machbrand.h> 319acbbeafSnn #include <sys/modctl.h> 329acbbeafSnn #include <sys/rwlock.h> 339acbbeafSnn #include <sys/zone.h> 3480e2ca85S #include <sys/pathname.h> 359acbbeafSnn 369acbbeafSnn #define SUPPORTED_BRAND_VERSION BRAND_VER_1 379acbbeafSnn 389acbbeafSnn #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 439acbbeafSnn struct brand_mach_ops native_mach_ops = { 449acbbeafSnn NULL, NULL 459acbbeafSnn }; 4659f2ff5cSedp #else /* !__sparcv9 */ 479acbbeafSnn struct brand_mach_ops native_mach_ops = { 48eb5a5c78SSurya Prakki NULL, NULL, NULL, NULL 499acbbeafSnn }; 5059f2ff5cSedp #endif /* !__sparcv9 */ 519acbbeafSnn 529acbbeafSnn brand_t native_brand = { 539acbbeafSnn BRAND_VER_1, 549acbbeafSnn "native", 559acbbeafSnn NULL, 569acbbeafSnn &native_mach_ops 579acbbeafSnn }; 589acbbeafSnn 599acbbeafSnn /* 609acbbeafSnn * Used to maintain a list of all the brands currently loaded into the 619acbbeafSnn * kernel. 629acbbeafSnn */ 639acbbeafSnn struct brand_list { 649acbbeafSnn int bl_refcnt; 659acbbeafSnn struct brand_list *bl_next; 669acbbeafSnn brand_t *bl_brand; 679acbbeafSnn }; 689acbbeafSnn 699acbbeafSnn static struct brand_list *brand_list = NULL; 709acbbeafSnn 719acbbeafSnn /* 729acbbeafSnn * This lock protects the integrity of the brand list. 739acbbeafSnn */ 749acbbeafSnn static kmutex_t brand_list_lock; 759acbbeafSnn 769acbbeafSnn void 779acbbeafSnn brand_init() 789acbbeafSnn { 799acbbeafSnn mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL); 809acbbeafSnn p0.p_brand = &native_brand; 819acbbeafSnn } 829acbbeafSnn 839acbbeafSnn int 849acbbeafSnn brand_register(brand_t *brand) 859acbbeafSnn { 869acbbeafSnn struct brand_list *list, *scan; 879acbbeafSnn 889acbbeafSnn if (brand == NULL) 899acbbeafSnn return (EINVAL); 909acbbeafSnn 919acbbeafSnn if (brand->b_version != SUPPORTED_BRAND_VERSION) { 929acbbeafSnn if (brand->b_version < SUPPORTED_BRAND_VERSION) { 939acbbeafSnn cmn_err(CE_WARN, 949acbbeafSnn "brand '%s' was built to run on older versions " 959acbbeafSnn "of Solaris.", 969acbbeafSnn brand->b_name); 979acbbeafSnn } else { 989acbbeafSnn cmn_err(CE_WARN, 999acbbeafSnn "brand '%s' was built to run on a newer version " 1009acbbeafSnn "of Solaris.", 1019acbbeafSnn brand->b_name); 1029acbbeafSnn } 1039acbbeafSnn return (EINVAL); 1049acbbeafSnn } 1059acbbeafSnn 1069acbbeafSnn /* Sanity checks */ 1079acbbeafSnn if (brand->b_name == NULL || brand->b_ops == NULL || 1089acbbeafSnn brand->b_ops->b_brandsys == NULL) { 1099acbbeafSnn cmn_err(CE_WARN, "Malformed brand"); 1109acbbeafSnn return (EINVAL); 1119acbbeafSnn } 1129acbbeafSnn 1139acbbeafSnn list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP); 1149acbbeafSnn 1159acbbeafSnn /* Add the brand to the list of loaded brands. */ 1169acbbeafSnn mutex_enter(&brand_list_lock); 1179acbbeafSnn 1189acbbeafSnn /* 1199acbbeafSnn * Check to be sure we haven't already registered this brand. 1209acbbeafSnn */ 1219acbbeafSnn for (scan = brand_list; scan != NULL; scan = scan->bl_next) { 1229acbbeafSnn if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) { 1239acbbeafSnn cmn_err(CE_WARN, 1249acbbeafSnn "Invalid attempt to load a second instance of " 1259acbbeafSnn "brand %s", brand->b_name); 1269acbbeafSnn mutex_exit(&brand_list_lock); 1279acbbeafSnn kmem_free(list, sizeof (struct brand_list)); 1289acbbeafSnn return (EINVAL); 1299acbbeafSnn } 1309acbbeafSnn } 1319acbbeafSnn 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 1389acbbeafSnn list->bl_brand = brand; 1399acbbeafSnn list->bl_refcnt = 0; 1409acbbeafSnn list->bl_next = brand_list; 1419acbbeafSnn brand_list = list; 142725deb8fSedp 1439acbbeafSnn mutex_exit(&brand_list_lock); 1449acbbeafSnn 1459acbbeafSnn return (0); 1469acbbeafSnn } 1479acbbeafSnn 1489acbbeafSnn /* 1499acbbeafSnn * The kernel module implementing this brand is being unloaded, so remove 1509acbbeafSnn * it from the list of active brands. 1519acbbeafSnn */ 1529acbbeafSnn int 1539acbbeafSnn brand_unregister(brand_t *brand) 1549acbbeafSnn { 1559acbbeafSnn struct brand_list *list, *prev; 1569acbbeafSnn 1579acbbeafSnn /* Sanity checks */ 1589acbbeafSnn if (brand == NULL || brand->b_name == NULL) { 1599acbbeafSnn cmn_err(CE_WARN, "Malformed brand"); 1609acbbeafSnn return (EINVAL); 1619acbbeafSnn } 1629acbbeafSnn 1639acbbeafSnn prev = NULL; 1649acbbeafSnn mutex_enter(&brand_list_lock); 1659acbbeafSnn 1669acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) { 1679acbbeafSnn if (list->bl_brand == brand) 1689acbbeafSnn break; 1699acbbeafSnn prev = list; 1709acbbeafSnn } 1719acbbeafSnn 1729acbbeafSnn if (list == NULL) { 1739acbbeafSnn cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name); 1749acbbeafSnn mutex_exit(&brand_list_lock); 1759acbbeafSnn return (EINVAL); 1769acbbeafSnn } 1779acbbeafSnn 1789acbbeafSnn if (list->bl_refcnt > 0) { 1799acbbeafSnn cmn_err(CE_WARN, "Unregistering brand %s which is still in use", 1809acbbeafSnn brand->b_name); 1819acbbeafSnn mutex_exit(&brand_list_lock); 1829acbbeafSnn return (EBUSY); 1839acbbeafSnn } 1849acbbeafSnn 1859acbbeafSnn /* Remove brand from the list */ 1869acbbeafSnn if (prev != NULL) 1879acbbeafSnn prev->bl_next = list->bl_next; 1889acbbeafSnn else 1899acbbeafSnn brand_list = list->bl_next; 1909acbbeafSnn 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 1979acbbeafSnn mutex_exit(&brand_list_lock); 1989acbbeafSnn 1999acbbeafSnn kmem_free(list, sizeof (struct brand_list)); 2009acbbeafSnn 2019acbbeafSnn return (0); 2029acbbeafSnn } 2039acbbeafSnn 2049acbbeafSnn /* 2059acbbeafSnn * Record that a zone of this brand has been instantiated. If the kernel 2069acbbeafSnn * module implementing this brand's functionality is not present, this 2079acbbeafSnn * routine attempts to load the module as a side effect. 2089acbbeafSnn */ 2099acbbeafSnn brand_t * 2109acbbeafSnn brand_register_zone(struct brand_attr *attr) 2119acbbeafSnn { 2129acbbeafSnn struct brand_list *l = NULL; 2139acbbeafSnn ddi_modhandle_t hdl = NULL; 2149acbbeafSnn char *modname; 2159acbbeafSnn int err = 0; 2169acbbeafSnn 2179acbbeafSnn if (is_system_labeled()) { 2189acbbeafSnn cmn_err(CE_WARN, 2199acbbeafSnn "Branded zones are not allowed on labeled systems."); 2209acbbeafSnn return (NULL); 2219acbbeafSnn } 2229acbbeafSnn 2239acbbeafSnn /* 2249acbbeafSnn * We make at most two passes through this loop. The first time 2259acbbeafSnn * through, we're looking to see if this is a new user of an 2269acbbeafSnn * already loaded brand. If the brand hasn't been loaded, we 2279acbbeafSnn * call ddi_modopen() to force it to be loaded and then make a 2289acbbeafSnn * second pass through the list of brands. If we don't find the 2299acbbeafSnn * brand the second time through it means that the modname 2309acbbeafSnn * specified in the brand_attr structure doesn't provide the brand 2319acbbeafSnn * specified in the brandname field. This would suggest a bug in 2329acbbeafSnn * the brand's config.xml file. We close the module and return 2339acbbeafSnn * 'NULL' to the caller. 2349acbbeafSnn */ 2359acbbeafSnn for (;;) { 2369acbbeafSnn /* 2379acbbeafSnn * Search list of loaded brands 2389acbbeafSnn */ 2399acbbeafSnn mutex_enter(&brand_list_lock); 2409acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next) 2419acbbeafSnn if (strcmp(attr->ba_brandname, 2429acbbeafSnn l->bl_brand->b_name) == 0) 2439acbbeafSnn break; 2449acbbeafSnn if ((l != NULL) || (hdl != NULL)) 2459acbbeafSnn break; 2469acbbeafSnn mutex_exit(&brand_list_lock); 2479acbbeafSnn 2489acbbeafSnn /* 2499acbbeafSnn * We didn't find that the requested brand has been loaded 2509acbbeafSnn * yet, so we trigger the load of the appropriate kernel 2519acbbeafSnn * module and search the list again. 2529acbbeafSnn */ 2539acbbeafSnn modname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2549acbbeafSnn (void) strcpy(modname, "brand/"); 2559acbbeafSnn (void) strcat(modname, attr->ba_modname); 2569acbbeafSnn hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err); 2579acbbeafSnn kmem_free(modname, MAXPATHLEN); 2589acbbeafSnn 2599acbbeafSnn if (err != 0) 2609acbbeafSnn return (NULL); 2619acbbeafSnn } 2629acbbeafSnn 2639acbbeafSnn /* 2649acbbeafSnn * If we found the matching brand, bump its reference count. 2659acbbeafSnn */ 2669acbbeafSnn if (l != NULL) 2679acbbeafSnn l->bl_refcnt++; 2689acbbeafSnn 2699acbbeafSnn mutex_exit(&brand_list_lock); 2709acbbeafSnn 2719acbbeafSnn if (hdl != NULL) 2729acbbeafSnn (void) ddi_modclose(hdl); 2739acbbeafSnn 2749acbbeafSnn return ((l != NULL) ? l->bl_brand : NULL); 2759acbbeafSnn } 2769acbbeafSnn 2779acbbeafSnn /* 2789acbbeafSnn * Return the number of zones currently using this brand. 2799acbbeafSnn */ 2809acbbeafSnn int 2819acbbeafSnn brand_zone_count(struct brand *bp) 2829acbbeafSnn { 2839acbbeafSnn struct brand_list *l; 2849acbbeafSnn int cnt = 0; 2859acbbeafSnn 2869acbbeafSnn mutex_enter(&brand_list_lock); 2879acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next) 2889acbbeafSnn if (l->bl_brand == bp) { 2899acbbeafSnn cnt = l->bl_refcnt; 2909acbbeafSnn break; 2919acbbeafSnn } 2929acbbeafSnn mutex_exit(&brand_list_lock); 2939acbbeafSnn 2949acbbeafSnn return (cnt); 2959acbbeafSnn } 2969acbbeafSnn 2979acbbeafSnn void 2989acbbeafSnn brand_unregister_zone(struct brand *bp) 2999acbbeafSnn { 3009acbbeafSnn struct brand_list *list; 3019acbbeafSnn 3029acbbeafSnn mutex_enter(&brand_list_lock); 3039acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) { 3049acbbeafSnn if (list->bl_brand == bp) { 3059acbbeafSnn ASSERT(list->bl_refcnt > 0); 3069acbbeafSnn list->bl_refcnt--; 3079acbbeafSnn break; 3089acbbeafSnn } 3099acbbeafSnn } 3109acbbeafSnn mutex_exit(&brand_list_lock); 3119acbbeafSnn } 3129acbbeafSnn 3139acbbeafSnn void 3149acbbeafSnn brand_setbrand(proc_t *p) 3159acbbeafSnn { 3169acbbeafSnn brand_t *bp = p->p_zone->zone_brand; 3179acbbeafSnn 3189acbbeafSnn ASSERT(bp != NULL); 3199acbbeafSnn ASSERT(p->p_brand == &native_brand); 3209acbbeafSnn 3219acbbeafSnn /* 3229acbbeafSnn * We should only be called from exec(), when we know the process 3239acbbeafSnn * is single-threaded. 3249acbbeafSnn */ 3259acbbeafSnn ASSERT(p->p_tlist == p->p_tlist->t_forw); 3269acbbeafSnn 3279acbbeafSnn p->p_brand = bp; 328fd9e7635Sedp ASSERT(PROC_IS_BRANDED(p)); 329fd9e7635Sedp BROP(p)->b_setbrand(p); 330fd9e7635Sedp } 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) { 346*e9f7cbf0SVamsi Nagineni 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; 3539acbbeafSnn } 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) { 1125*e9f7cbf0SVamsi Nagineni 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