xref: /illumos-gate/usr/src/uts/common/os/brand.c (revision e9f7cbf0)
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, &reg, 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, &reg32, 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