brand.c revision 59f2ff5c96304fcfa3d97e66fbe1c521f42ac103
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * CDDL HEADER START
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn *
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * The contents of this file are subject to the terms of the
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Common Development and Distribution License (the "License").
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * You may not use this file except in compliance with the License.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn *
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * or http://www.opensolaris.org/os/licensing.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * See the License for the specific language governing permissions
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * and limitations under the License.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn *
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * When distributing Covered Code, include this CDDL HEADER in each
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * If applicable, add the following below this CDDL HEADER, with the
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * fields enclosed by brackets "[]" replaced with your own identifying
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * information: Portions Copyright [yyyy] [name of copyright owner]
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn *
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * CDDL HEADER END
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Use is subject to license terms.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#pragma ident "%Z%%M% %I% %E% SMI"
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/kmem.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/errno.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/systm.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/cmn_err.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/brand.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/machbrand.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/modctl.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/rwlock.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#include <sys/zone.h>
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#define SUPPORTED_BRAND_VERSION BRAND_VER_1
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn#if defined(__sparcv9)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnstruct brand_mach_ops native_mach_ops = {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn NULL, NULL
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn};
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#else /* !__sparcv9 */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnstruct brand_mach_ops native_mach_ops = {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn NULL, NULL, NULL, NULL, NULL, NULL
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn};
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#endif /* !__sparcv9 */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_t native_brand = {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn BRAND_VER_1,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "native",
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn NULL,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn &native_mach_ops
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn};
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Used to maintain a list of all the brands currently loaded into the
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * kernel.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnstruct brand_list {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn int bl_refcnt;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *bl_next;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand_t *bl_brand;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn};
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnstatic struct brand_list *brand_list = NULL;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Used to enable brand platform specific interposition code
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#pragma weak brand_plat_interposition_init
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpextern void brand_plat_interposition_init(void);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * This lock protects the integrity of the brand list.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnstatic kmutex_t brand_list_lock;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnvoid
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_init()
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp brand_plat_interposition_init();
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn p0.p_brand = &native_brand;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnint
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_register(brand_t *brand)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *list, *scan;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (brand == NULL)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (is_system_labeled()) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "Branded zones are not allowed on labeled systems.");
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (brand->b_version != SUPPORTED_BRAND_VERSION) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (brand->b_version < SUPPORTED_BRAND_VERSION) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "brand '%s' was built to run on older versions "
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "of Solaris.",
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand->b_name);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn } else {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "brand '%s' was built to run on a newer version "
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "of Solaris.",
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand->b_name);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /* Sanity checks */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (brand->b_name == NULL || brand->b_ops == NULL ||
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand->b_ops->b_brandsys == NULL) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN, "Malformed brand");
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /* Add the brand to the list of loaded brands. */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_enter(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Check to be sure we haven't already registered this brand.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (scan = brand_list; scan != NULL; scan = scan->bl_next) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "Invalid attempt to load a second instance of "
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "brand %s", brand->b_name);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn kmem_free(list, sizeof (struct brand_list));
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn list->bl_brand = brand;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn list->bl_refcnt = 0;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn list->bl_next = brand_list;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand_list = list;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (0);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * The kernel module implementing this brand is being unloaded, so remove
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * it from the list of active brands.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnint
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_unregister(brand_t *brand)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *list, *prev;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /* Sanity checks */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (brand == NULL || brand->b_name == NULL) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN, "Malformed brand");
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn prev = NULL;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_enter(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (list = brand_list; list != NULL; list = list->bl_next) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (list->bl_brand == brand)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn break;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn prev = list;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (list == NULL) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EINVAL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (list->bl_refcnt > 0) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN, "Unregistering brand %s which is still in use",
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand->b_name);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (EBUSY);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /* Remove brand from the list */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (prev != NULL)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn prev->bl_next = list->bl_next;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn else
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand_list = list->bl_next;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn kmem_free(list, sizeof (struct brand_list));
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (0);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Record that a zone of this brand has been instantiated. If the kernel
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * module implementing this brand's functionality is not present, this
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * routine attempts to load the module as a side effect.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_t *
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_register_zone(struct brand_attr *attr)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *l = NULL;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn ddi_modhandle_t hdl = NULL;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn char *modname;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn int err = 0;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (is_system_labeled()) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cmn_err(CE_WARN,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn "Branded zones are not allowed on labeled systems.");
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (NULL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * We make at most two passes through this loop. The first time
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * through, we're looking to see if this is a new user of an
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * already loaded brand. If the brand hasn't been loaded, we
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * call ddi_modopen() to force it to be loaded and then make a
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * second pass through the list of brands. If we don't find the
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * brand the second time through it means that the modname
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * specified in the brand_attr structure doesn't provide the brand
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * specified in the brandname field. This would suggest a bug in
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * the brand's config.xml file. We close the module and return
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * 'NULL' to the caller.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (;;) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Search list of loaded brands
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_enter(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (l = brand_list; l != NULL; l = l->bl_next)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (strcmp(attr->ba_brandname,
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn l->bl_brand->b_name) == 0)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn break;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if ((l != NULL) || (hdl != NULL))
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn break;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * We didn't find that the requested brand has been loaded
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * yet, so we trigger the load of the appropriate kernel
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * module and search the list again.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn modname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn (void) strcpy(modname, "brand/");
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn (void) strcat(modname, attr->ba_modname);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn kmem_free(modname, MAXPATHLEN);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (err != 0)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (NULL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * If we found the matching brand, bump its reference count.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (l != NULL)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn l->bl_refcnt++;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (hdl != NULL)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn (void) ddi_modclose(hdl);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return ((l != NULL) ? l->bl_brand : NULL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn/*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * Return the number of zones currently using this brand.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnint
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_zone_count(struct brand *bp)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *l;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn int cnt = 0;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_enter(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (l = brand_list; l != NULL; l = l->bl_next)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (l->bl_brand == bp) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn cnt = l->bl_refcnt;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn break;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn return (cnt);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnvoid
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_unregister_zone(struct brand *bp)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn struct brand_list *list;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_enter(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn for (list = brand_list; list != NULL; list = list->bl_next) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (list->bl_brand == bp) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn ASSERT(list->bl_refcnt > 0);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn list->bl_refcnt--;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn break;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn mutex_exit(&brand_list_lock);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnvoid
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnnbrand_setbrand(proc_t *p)
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn{
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn brand_t *bp = p->p_zone->zone_brand;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn ASSERT(bp != NULL);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn ASSERT(p->p_brand == &native_brand);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn /*
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * We should only be called from exec(), when we know the process
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn * is single-threaded.
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn */
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn ASSERT(p->p_tlist == p->p_tlist->t_forw);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn p->p_brand = bp;
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn if (PROC_IS_BRANDED(p)) {
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn BROP(p)->b_setbrand(p);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn lwp_attach_brand_hdlrs(p->p_tlist->t_lwp);
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn }
9acbbeaf2a1ffe5c14b244867d427714fab43c5cnn}
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#if defined(__sparcv9)
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Currently, only sparc has platform level brand syscall interposition.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * On x86 we're able to enable syscall interposition on a per-cpu basis
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * when a branded thread is scheduled to run on a cpu.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/* Local variables needed for dynamic syscall interposition support */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpstatic kmutex_t brand_interposition_lock;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpstatic int brand_interposition_count;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpstatic uint32_t syscall_trap_patch_instr_orig;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpstatic uint32_t syscall_trap32_patch_instr_orig;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/* Trap Table syscall entry hot patch points */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpextern void syscall_trap_patch_point(void);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpextern void syscall_trap32_patch_point(void);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/* Alternate syscall entry handlers used when branded zones are running */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpextern void syscall_wrapper(void);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpextern void syscall_wrapper32(void);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/* Macros used to facilitate sparcv9 instruction generation */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#define BA_A_INSTR 0x30800000 /* ba,a addr */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#define DISP22(from, to) \
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & 0x3fffff)
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpvoid
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpbrand_plat_interposition_init(void)
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp{
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_init(&brand_interposition_lock, NULL, MUTEX_DEFAULT, NULL);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp brand_interposition_count = 0;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp}
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/*ARGSUSED*/
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpvoid
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpbrand_plat_interposition_enable(brand_t *bp)
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp{
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp ASSERT((bp != NULL) && (bp != &native_brand));
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_enter(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp ASSERT(brand_interposition_count >= 0);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp if (brand_interposition_count++ > 0) {
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_exit(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp return;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp }
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp /*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * This is the first branded zone that is being enabled on
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * this system.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Before we hot patch the kernel save the current instructions
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * so that we can restore them if all branded zones on the
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * system are shutdown.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp syscall_trap_patch_instr_orig =
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *(uint32_t *)syscall_trap_patch_point;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp syscall_trap32_patch_instr_orig =
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *(uint32_t *)syscall_trap32_patch_point;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp /*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Modify the trap table at the patch points.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * We basically replace the first instruction at the patch
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * point with a ba,a instruction that will transfer control
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * to syscall_wrapper or syscall_wrapper32 for 64-bit and
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * 32-bit syscalls respectively. It's important to note that
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * the annul bit is set in the branch so we don't execute
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * the instruction directly following the one we're patching
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * during the branch's delay slot.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * It also doesn't matter that we're not atomically updating both
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * the 64 and 32 bit syscall paths at the same time since there's
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * no actual branded processes running on the system yet.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp BA_A_INSTR | DISP22(syscall_trap_patch_point, syscall_wrapper),
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp 4);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp BA_A_INSTR | DISP22(syscall_trap32_patch_point, syscall_wrapper32),
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp 4);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_exit(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp}
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp/*ARGSUSED*/
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpvoid
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edpbrand_plat_interposition_disable(brand_t *bp)
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp{
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp ASSERT((bp != NULL) && (bp != &native_brand));
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_enter(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp ASSERT(brand_interposition_count > 0);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp if (--brand_interposition_count > 0) {
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_exit(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp return;
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp }
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp /*
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * The last branded zone on this system has been shutdown.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp *
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * Restore the original instructions at the trap table syscall
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * patch points to disable the brand syscall interposition
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp * mechanism.
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp */
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp syscall_trap_patch_instr_orig, 4);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp syscall_trap32_patch_instr_orig, 4);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp mutex_exit(&brand_interposition_lock);
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp}
59f2ff5c96304fcfa3d97e66fbe1c521f42ac103edp#endif /* __sparcv9 */