/* * 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 __BEGIN_DECLS #pragma GCC visibility push(hidden) __enum_decl(ipc_kotype_t, natural_t, { IKOT_NONE = 0, IKOT_THREAD_CONTROL = 1, IKOT_TASK_CONTROL = 2, IKOT_HOST = 3, IKOT_HOST_PRIV = 4, IKOT_PROCESSOR = 5, IKOT_PSET = 6, IKOT_PSET_NAME = 7, IKOT_TIMER = 8, IKOT_PORT_SUBST_ONCE = 9, // IKOT_MIG = 10, IKOT_MEMORY_OBJECT = 11, // IKOT_XMM_PAGER = 12, // IKOT_XMM_KERNEL = 13, // IKOT_XMM_REPLY = 14, IKOT_UND_REPLY = 15, // IKOT_HOST_NOTIFY = 16, // IKOT_HOST_SECURITY = 17, // IKOT_LEDGER = 18, IKOT_MAIN_DEVICE = 19, IKOT_TASK_NAME = 20, // IKOT_SUBSYSTEM = 21, // IKOT_IO_DONE_QUEUE = 22, IKOT_SEMAPHORE = 23, // IKOT_LOCK_SET = 24, IKOT_CLOCK = 25, // IKOT_CLOCK_CTRL = 26, IKOT_IOKIT_IDENT = 27, IKOT_NAMED_ENTRY = 28, IKOT_IOKIT_CONNECT = 29, IKOT_IOKIT_OBJECT = 30, // IKOT_UPL = 31, // IKOT_MEM_OBJ_CONTROL = 32, #if CONFIG_AUDIT IKOT_AU_SESSIONPORT = 33, #endif IKOT_FILEPORT = 34, // IKOT_LABELH = 35, IKOT_TASK_RESUME = 36, IKOT_VOUCHER = 37, // IKOT_VOUCHER_ATTR_CONTROL = 38, IKOT_WORK_INTERVAL = 39, IKOT_UX_HANDLER = 40, IKOT_UEXT_OBJECT = 41, IKOT_ARCADE_REG = 42, IKOT_EVENTLINK = 43, IKOT_TASK_INSPECT = 44, IKOT_TASK_READ = 45, IKOT_THREAD_INSPECT = 46, IKOT_THREAD_READ = 47, // IKOT_SUID_CRED = 48, #if HYPERVISOR IKOT_HYPERVISOR = 49, #endif IKOT_TASK_ID_TOKEN = 50, #if CONFIG_PROC_RESOURCE_LIMITS IKOT_TASK_FATAL = 51, #endif IKOT_KCDATA = 52, #if CONFIG_EXCLAVES IKOT_EXCLAVES_RESOURCE = 53, #endif /* magic catch-all; should be the last entry */ IKOT_UNKNOWN, }); #define IKOT_MAX_TYPE (IKOT_UNKNOWN+1) /* # of IKOT_ types */ #ifdef __cplusplus /* preserve legacy ABI for c++ */ typedef natural_t ipc_kobject_type_t; #else typedef ipc_kotype_t ipc_kobject_type_t; #endif /* 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 IKOT_* 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. * * 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. * * @field iko_op_destroy * A callback to run as part of destroying 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. */ typedef const struct ipc_kobject_ops { ipc_kobject_type_t iko_op_type; unsigned long iko_op_stable : 1, iko_op_permanent : 1; const char *iko_op_name; void (*iko_op_no_senders)(ipc_port_t port, mach_port_mscount_t mscount); void (*iko_op_destroy)(ipc_port_t port); } *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; }; __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, /* Register for no-more-senders */ IPC_KOBJECT_ALLOC_NSREQUEST = 0x00000002, /* Make it no grant port */ IPC_KOBJECT_ALLOC_NO_GRANT = 0x00000004, /* Mark the port as immovable send right */ IPC_KOBJECT_ALLOC_IMMOVABLE_SEND = 0x00000008, /* Add a label structure to the port */ IPC_KOBJECT_ALLOC_LABEL = 0x00000010, /* Mark the port as pinned (non dealloc-able) in an ipc space */ IPC_KOBJECT_ALLOC_PINNED = 0x00000020, }); /* Allocates a kobject port, never fails */ extern ipc_port_t ipc_kobject_alloc_port( ipc_kobject_t kobject, ipc_kobject_type_t type, ipc_kobject_alloc_options_t options); /* Allocates a kobject port, never fails */ extern ipc_port_t ipc_kobject_alloc_labeled_port( ipc_kobject_t kobject, ipc_kobject_type_t type, ipc_label_t label, ipc_kobject_alloc_options_t options); extern ipc_port_t ipc_kobject_alloc_subst_once( ipc_port_t target); /* Makes a send right, lazily allocating a kobject port, arming for no-senders, never fails */ extern bool ipc_kobject_make_send_lazy_alloc_port( ipc_port_t *port_store, ipc_kobject_t kobject, ipc_kobject_type_t type, ipc_kobject_alloc_options_t alloc_opts); /* Makes a send right, lazily allocating a kobject port, arming for no-senders, never fails */ extern boolean_t ipc_kobject_make_send_lazy_alloc_labeled_port( ipc_port_t *port_store, ipc_kobject_t kobject, ipc_kobject_type_t type, ipc_label_t label) __result_use_check; extern kern_return_t ipc_kobject_nsrequest( ipc_port_t port, mach_port_mscount_t sync, mach_port_mscount_t *mscount) __result_use_check; /*! * @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; /*! * @function ipc_kobject_make_send_nsrequest() * * @brief * Makes a naked send right for the specified kobject port, * and arms no-more-senders if it wasn't already. * * @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 * - KERN_SUCCESS: the notification was armed * - KERN_ALREADY_WAITING: the notification was already armed * - KERN_INVALID_RIGHT: the port is dead */ extern kern_return_t ipc_kobject_make_send_nsrequest( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t kotype) __result_use_check; extern kern_return_t ipc_kobject_make_send_nsrequest_locked( ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t kotype) __result_use_check; extern ipc_kobject_t ipc_kobject_dealloc_port_and_unlock( ipc_port_t port, mach_port_mscount_t mscount, ipc_kobject_type_t type); extern ipc_kobject_t ipc_kobject_dealloc_port( ipc_port_t port, mach_port_mscount_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); extern void ipc_kobject_upgrade_mktimer_locked( ipc_port_t port, ipc_kobject_t kobject); /* Check if a kobject can be copied out to a given space */ extern bool ipc_kobject_label_check( ipc_space_t space, ipc_port_t port, mach_msg_type_name_t msgt_name, ipc_object_copyout_flags_t *flags, ipc_port_t *subst_portp) __result_use_check; __result_use_check static inline bool ip_label_check( ipc_space_t space, ipc_port_t port, mach_msg_type_name_t msgt_name, ipc_object_copyout_flags_t *flags, ipc_port_t *subst_portp) { if (!ip_is_kolabeled(port)) { *subst_portp = IP_NULL; return true; } return ipc_kobject_label_check(space, port, msgt_name, flags, subst_portp); } /* implementation details */ __startup_func extern void ipc_kobject_register_startup( ipc_kobject_ops_t ops); /* initialization of kobject subsystem */ extern void ipc_kobject_init(void); /* 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); /* Release any kernel object resources associated with a port */ extern void ipc_kobject_destroy( ipc_port_t port); #define null_conversion(port) (port) extern void ipc_kobject_notify_no_senders( ipc_port_t port, mach_port_mscount_t mscount); 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 */ #pragma GCC visibility pop __END_DECLS #endif /* _KERN_IPC_KOBJECT_H_ */