/* * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce * support for mandatory and extensible security protections. This notice * is included in support of clause 2.2 (b) of the Apple Public License, * Version 2.0. */ /* */ /* * File: kern/ipc_kobject.h * Author: Rich Draves * Date: 1989 * * Declarations for letting a port represent a kernel object. */ #ifndef _KERN_IPC_KOBJECT_H_ #define _KERN_IPC_KOBJECT_H_ #ifdef MACH_KERNEL_PRIVATE #include #include #include #endif /* MACH_KERNEL_PRIVATE */ #include #include #include __BEGIN_DECLS #pragma GCC visibility push(hidden) typedef ipc_object_type_t ipc_kobject_type_t; /* set the bitstring index for kobject */ extern kern_return_t ipc_kobject_set_kobjidx( int msgid, int index); #ifdef MACH_KERNEL_PRIVATE /*! * @typedef ipc_kobject_ops_t * * @brief * Describes the operations for a given kobject. * * @field iko_ko_type * An @c IOT_* value. * * @field iko_op_stable * The kobject/port association is stable: * - ipc_kobject_dealloc_port() cannot be called * while there are outstanding send rights, * - ipc_kobject_enable() is never called. * - ipc_kobject_disable() is never called. * * @field iko_op_permanent * The port is never destroyed. * This doesn't necessarily imply iko_op_stable. * * @field iko_op_no_senders * A callback to run when a NO_SENDERS notification fires. * * This callback is called each time a kobject port reaches 0 send rights * (from a non 0 value). There is no need to actively arm no-senders. * * Kobjects that destroy their port on no senders only are guaranteed * to be called with an active port only. * * However kobject ports that can be destroyed concurrently need * to be prepared for no senders to fail to acquire the kobject port. * * When this callback is set, @c ipc_kobject_dealloc_port() * will not implicitly call @c ipc_kobject_disable(). * * The callback runs after the port has been marked inactive, * hence @c ipc_kobject_get_raw() needs to be used to get to the port. * * @field iko_op_label_free * How to free the label on this kobject port (if it supports one). * * @field iko_op_movable_send * Whether send rights created to this kobject are movable */ typedef const struct ipc_kobject_ops { ipc_kobject_type_t iko_op_type; unsigned long iko_op_stable : 1, iko_op_permanent : 1, iko_op_movable_send : 1; const char *iko_op_name; void (*iko_op_no_senders)(ipc_port_t port, mach_port_mscount_t mscount); void (*iko_op_label_free)(ipc_object_label_t label); } *ipc_kobject_ops_t; #define IPC_KOBJECT_DEFINE(type, ...) \ __startup_data \ static struct ipc_kobject_ops ipc_kobject_ops_##type = { \ .iko_op_type = type, \ .iko_op_name = #type, \ __VA_ARGS__ \ }; \ STARTUP_ARG(MACH_IPC, STARTUP_RANK_FIRST, ipc_kobject_register_startup, \ &ipc_kobject_ops_##type) struct ipc_kobject_label { ipc_label_t ikol_label; /* [private] mandatory access label */ ipc_port_t XNU_PTRAUTH_SIGNED_PTR("ipc_kobject_label.ikol_alt_port") ikol_alt_port; }; extern ipc_object_label_t ipc_kobject_label_alloc( ipc_object_type_t otype, ipc_label_t label_tag, ipc_port_t alt_port); extern void ipc_kobject_label_free( ipc_object_label_t label); __options_decl(ipc_kobject_alloc_options_t, uint32_t, { /* Just make the naked port */ IPC_KOBJECT_ALLOC_NONE = 0x00000000, /* Make a send right */ IPC_KOBJECT_ALLOC_MAKE_SEND = 0x00000001, }); /* Allocates a kobject port, never fails */ extern ipc_port_t ipc_kobject_alloc_port( ipc_kobject_t kobject, ipc_object_label_t label, ipc_kobject_alloc_options_t options); __attribute__((always_inline, overloadable)) static inline ipc_port_t ipc_kobject_alloc_port( ipc_kobject_t kobject, ipc_object_type_t otype, ipc_kobject_alloc_options_t options) { return ipc_kobject_alloc_port(kobject, IPC_OBJECT_LABEL(otype), options); } /*! * @function ipc_kobject_make_send_lazy_alloc_port() * * @brief * Make a send once for a kobject port, lazily allocating the port. * * @discussion * A location owning this port is passed in port_store. * If no port exists, a port is made lazily. * * A send right is made for the port, and if this is the first one * (possibly not for the first time), then the no-more-senders * notification is rearmed. * * When a notification is armed, the kobject must donate * one of its references to the port. It is expected * the no-more-senders notification will consume this reference. * * In order to use this function, the kobject type requested must: * - be use stable objects (iko_op_stable is true), * - have a no-senders callback (iko_op_no_senders is set). * * @returns * - true, if this was the first send right made for this port, * and an object reference must be donated to the port; * - false otherwise. */ extern bool ipc_kobject_make_send_lazy_alloc_port( ipc_port_t *port_store, ipc_kobject_t kobject, ipc_kobject_type_t type); /*! * @function ipc_kobject_is_mscount_current() * * @brief * Returns whether the current make-send count is the current one. * * @discussion * This is meant to be called from the context of a no-senders notification * callout to determine whether the object/port has since been rematerialized. * * Most kobjects are uniquely owned by their port, and the object is otherwise * not reachable from any place in the system (see semaphores, eventlink, etc), * and die when the port has no more senders. * * However some kobjects might still be reachable from other means, * and can make new send rights in a way that isn't synchronized with Mach IPC. * (See IKOT_TASK_RESUME for an example of that). * * This function allows for such kobject types to verify under the * synchronization it uses whether this no-senders callout is the last one, * or if there has been new send rights made concurrently. * * @param port The target port. * @param mscount The make-send count for which the no-senders * notification was issued. */ extern bool ipc_kobject_is_mscount_current( ipc_port_t port, mach_port_mscount_t mscount); extern bool ipc_kobject_is_mscount_current_locked( ipc_port_t port, mach_port_mscount_t mscount); /*! * @function ipc_kobject_copy_send() * * @brief * Copies a naked send right for the specified kobject port. * * @decription * This function will validate that the specified port is pointing * to the expected kobject pointer and type (by calling ipc_kobject_require()). * * @param port The target port. * @param kobject The kobject pointer this port should be associated to. * @param kotype The kobject type this port should have. * * @returns * - IP_DEAD if @c port was dead. * - @c port if @c port was valid, in which case * a naked send right was made. */ extern ipc_port_t ipc_kobject_copy_send( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t kotype) __result_use_check; /*! * @function ipc_kobject_make_send() * * @brief * Makes a naked send right for the specified kobject port. * * @decription * @see ipc_port_make_send_any_locked() for a general warning about * making send rights. * * This function will validate that the specified port is pointing * to the expected kobject pointer and type (by calling ipc_kobject_require()). * * @param port The target port. * @param kobject The kobject pointer this port should be associated to. * @param kotype The kobject type this port should have. * * @returns * - IP_DEAD if @c port was dead. * - @c port if @c port was valid, in which case * a naked send right was made. */ extern ipc_port_t ipc_kobject_make_send( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t kotype) __result_use_check; #define IPC_KOBJECT_NO_MSCOUNT (~0ull) extern ipc_kobject_t ipc_kobject_dealloc_port_and_unlock( ipc_port_t port, uint64_t mscount, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_dealloc_port( ipc_port_t port, uint64_t mscount, ipc_kobject_type_t type); extern void ipc_kobject_enable( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t type); /*! * @function ipc_kobject_require() * * @brief * Asserts that a given port is of the specified type * with the expected kobject pointer. * * @decription * Port type confusion can lead to catastrophic system compromise, * this function can be used in choke points to ensure ports are * what they're expected to be before their use. * * @note It is allowed for the kobject pointer to be NULL, * as in some cases ipc_kobject_disable() can be raced with this check. * * @param port The target port. * @param kobject The kobject pointer this port should be associated to. * @param kotype The kobject type this port should have. */ extern void ipc_kobject_require( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t kotype); extern ipc_kobject_t ipc_kobject_get_raw( ipc_port_t port, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_get_locked( ipc_port_t port, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_get_stable( ipc_port_t port, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_disable_locked( ipc_port_t port, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_disable( ipc_port_t port, ipc_kobject_type_t type); /* Check if a kobject can be copied out to a given space */ extern bool ipc_kobject_label_check_or_substitute( ipc_space_t space, ipc_port_t port, ipc_object_label_t *label, mach_msg_type_name_t msgt_name, ipc_port_t *subst_portp) __result_use_check; /*! * @brief * Evaluate a port for substitution and kobject label rules. * * @discussion * This function has a really cumbersome calling convention. * * If it returns false, then it means that some policy was violated, * in that case, @c port has been unlocked, and @c label put. * * If it returns true, and subst_portp is not IP_NULL, then @c port * has been unlocked, and @c label put, and the caller is expected * to redrive evaluation with that substitution port. * * If it returns true, and subst_port is IP_NULL, then @c port * is still locked, and @c label still valid, and the caller is expected * to proceed further. * * @param space The current space * @param port The port to evaluate (must be locked and active) * @param label (In/out) the label for @c port. * @param msgt_name The disposition for @c port in the message. * @param subst_portp (out) an optional substitution port, * to replace @c port with. */ __result_use_check static inline bool ip_label_check_or_substitute( ipc_space_t space, ipc_port_t port, ipc_object_label_t *label, mach_msg_type_name_t msgt_name, ipc_port_t *subst_portp) { if (!io_is_kobject_type(label->io_type) || !label->iol_kobject) { *subst_portp = IP_NULL; return true; } return ipc_kobject_label_check_or_substitute(space, port, label, msgt_name, subst_portp); } /* implementation details */ __startup_func extern void ipc_kobject_register_startup( ipc_kobject_ops_t ops); /* Dispatch a kernel server function */ extern ipc_kmsg_t ipc_kobject_server( ipc_port_t receiver, ipc_kmsg_t request, mach_msg_option64_t option); #define null_conversion(port) (port) extern void ipc_kobject_notify_send_once_and_unlock( ipc_port_t port); extern kern_return_t uext_server( ipc_port_t receiver, ipc_kmsg_t request, ipc_kmsg_t *reply); #endif /* MACH_KERNEL_PRIVATE */ #if XNU_KERNEL_PRIVATE /*! * @function ipc_typed_port_copyin_send() * * @brief * Copies in a naked send right for the specified typed port. * * @decription * This function will validate that the specified port is pointing * to the expected kobject type, unless @c kotype is IOT_ANY, * in which case any right is accepted. * * @param space The space to copyin in from. * @param name The name to copyin. * @param kotype The kobject type this port should have. * @param port The resulting port or IP_NULL. * * @returns * - KERN_SUCCESS Acquired an object, possibly IP_DEAD. * - KERN_INVALID_TASK The space is dead. * - KERN_INVALID_NAME Name doesn't exist in space. * - KERN_INVALID_RIGHT Name doesn't denote correct right. * - KERN_INVALID_CAPABILITY * The right isn't of the right kobject type. */ extern kern_return_t ipc_typed_port_copyin_send( ipc_space_t space, mach_port_name_t name, ipc_kobject_type_t kotype, ipc_port_t *port); /*! * @function ipc_typed_port_release_send() * * @brief * Release a send right for a typed port. * * @description * This is an alias for ipc_port_release_send() that the BSD side can use. * If @c kotype is IOT_ANY, any right is accepted. */ extern void ipc_typed_port_release_send( ipc_port_t port, ipc_kobject_type_t kotype); #endif /* XNU_KERNEL_PRIVATE */ #pragma GCC visibility pop __END_DECLS #endif /* _KERN_IPC_KOBJECT_H_ */