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