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
brand_init()779acbbeafSnn35248 brand_init()
789acbbeafSnn35248 {
799acbbeafSnn35248 mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL);
809acbbeafSnn35248 p0.p_brand = &native_brand;
819acbbeafSnn35248 }
829acbbeafSnn35248
839acbbeafSnn35248 int
brand_register(brand_t * brand)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
brand_unregister(brand_t * brand)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 *
brand_register_zone(struct brand_attr * attr)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
brand_zone_count(struct brand * bp)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
brand_unregister_zone(struct brand * bp)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
brand_setbrand(proc_t * p)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
brand_clearbrand(proc_t * p,boolean_t no_lwps)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
brand_plat_interposition_enable(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
brand_plat_interposition_disable(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
Ehdr32to64(Elf32_Ehdr * src,Ehdr * dst)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
brand_solaris_cmd(int cmd,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,struct brand * pbrand,int brandvers)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
brand_solaris_copy_procdata(proc_t * child,proc_t * parent,struct brand * pbrand)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
restoreexecenv(struct execenv * ep,stack_t * sp)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
brand_solaris_elfexec(vnode_t * vp,execa_t * uap,uarg_t * args,intpdata_t * idatap,int level,long * execsz,int setid,caddr_t exec_file,cred_t * cred,int brand_action,struct brand * pbrand,char * bname,char * brandlib,char * brandlib32,char * brandlinker,char * brandlinker32)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
brand_solaris_exec(struct brand * pbrand)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
brand_solaris_fini(char ** emul_table,struct modlinkage * modlinkage,struct brand * pbrand)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
brand_solaris_forklwp(klwp_t * p,klwp_t * c,struct brand * pbrand)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
brand_solaris_freelwp(klwp_t * l,struct brand * pbrand)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
brand_solaris_initlwp(klwp_t * l,struct brand * pbrand)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
brand_solaris_lwpexit(klwp_t * l,struct brand * pbrand)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
brand_solaris_proc_exit(struct proc * p,klwp_t * l,struct brand * pbrand)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
brand_solaris_setbrand(proc_t * p,struct brand * pbrand)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