X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d9a64523371fa019c4575bb400cbbc3a50ac9903..ea3f04195ba4a5034c9c8e9b726d4f7ce96f1832:/osfmk/kern/ipc_mig.c diff --git a/osfmk/kern/ipc_mig.c b/osfmk/kern/ipc_mig.c index ddbfa0e5a..6896e3793 100644 --- a/osfmk/kern/ipc_mig.c +++ b/osfmk/kern/ipc_mig.c @@ -2,7 +2,7 @@ * Copyright (c) 2000-2004 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 @@ -11,10 +11,10 @@ * 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, @@ -22,34 +22,34 @@ * 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 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. */ @@ -108,31 +108,31 @@ mach_msg_receive_results_complete(ipc_object_t object); #undef mach_msg_send_from_kernel mach_msg_return_t mach_msg_send_from_kernel( - mach_msg_header_t *msg, - mach_msg_size_t send_size); + mach_msg_header_t *msg, + mach_msg_size_t send_size); mach_msg_return_t mach_msg_send_from_kernel( - mach_msg_header_t *msg, - mach_msg_size_t send_size) + mach_msg_header_t *msg, + mach_msg_size_t send_size) { ipc_kmsg_t kmsg; mach_msg_return_t mr; - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; - } + } /* * respect the thread's SEND_IMPORTANCE option to allow importance @@ -140,13 +140,14 @@ mach_msg_send_from_kernel( * (11938665 & 23925818) */ mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT; - if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) + if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) { option &= ~MACH_SEND_NOIMPORTANCE; + } mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } return mr; @@ -156,24 +157,24 @@ mach_msg_send_from_kernel( mach_msg_return_t mach_msg_send_from_kernel_proper( - mach_msg_header_t *msg, - mach_msg_size_t send_size) + mach_msg_header_t *msg, + mach_msg_size_t send_size) { ipc_kmsg_t kmsg; mach_msg_return_t mr; - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } @@ -183,13 +184,14 @@ mach_msg_send_from_kernel_proper( * (11938665 & 23925818) */ mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT; - if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) + if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) { option &= ~MACH_SEND_NOIMPORTANCE; + } mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } return mr; @@ -197,29 +199,48 @@ mach_msg_send_from_kernel_proper( mach_msg_return_t mach_msg_send_from_kernel_with_options( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_option_t option, - mach_msg_timeout_t timeout_val) + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_option_t option, + mach_msg_timeout_t timeout_val) +{ + return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL); +} + +mach_msg_return_t +kernel_mach_msg_send( + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_option_t option, + mach_msg_timeout_t timeout_val, + boolean_t *message_moved) { ipc_kmsg_t kmsg; mach_msg_return_t mr; - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + + if (message_moved) { + *message_moved = FALSE; + } mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } + if (message_moved) { + *message_moved = TRUE; + } + /* * Until we are sure of its effects, we are disabling * importance donation from the kernel-side of user @@ -228,18 +249,19 @@ mach_msg_send_from_kernel_with_options( * or the thread's SEND_IMPORTANCE option has been set. * (11938665 & 23925818) */ - if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) + if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) { option &= ~MACH_SEND_NOIMPORTANCE; - else if ((option & MACH_SEND_IMPORTANCE) == 0) + } else if ((option & MACH_SEND_IMPORTANCE) == 0) { option |= MACH_SEND_NOIMPORTANCE; + } mr = ipc_kmsg_send(kmsg, option, timeout_val); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } - + return mr; } @@ -248,26 +270,26 @@ mach_msg_send_from_kernel_with_options( mach_msg_return_t mach_msg_send_from_kernel_with_options_legacy( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_option_t option, - mach_msg_timeout_t timeout_val) + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_option_t option, + mach_msg_timeout_t timeout_val) { ipc_kmsg_t kmsg; mach_msg_return_t mr; - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } @@ -277,18 +299,19 @@ mach_msg_send_from_kernel_with_options_legacy( * threads in importance-donating tasks. * (11938665 & 23925818) */ - if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) + if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) { option &= ~MACH_SEND_NOIMPORTANCE; - else + } else { option |= MACH_SEND_NOIMPORTANCE; + } mr = ipc_kmsg_send(kmsg, option, timeout_val); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } - + return mr; } @@ -309,47 +332,44 @@ mach_msg_send_from_kernel_with_options_legacy( * MACH_RCV_PORT_DIED The reply port was deallocated. */ -mach_msg_return_t mach_msg_rpc_from_kernel_body(mach_msg_header_t *msg, - mach_msg_size_t send_size, mach_msg_size_t rcv_size, boolean_t legacy); - #if IKM_SUPPORT_LEGACY #undef mach_msg_rpc_from_kernel mach_msg_return_t mach_msg_rpc_from_kernel( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_size_t rcv_size); + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size); mach_msg_return_t mach_msg_rpc_from_kernel( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_size_t rcv_size) + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size) { - return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, TRUE); + return kernel_mach_msg_rpc(msg, send_size, rcv_size, TRUE, NULL); } - #endif /* IKM_SUPPORT_LEGACY */ mach_msg_return_t mach_msg_rpc_from_kernel_proper( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_size_t rcv_size) + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size) { - return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, FALSE); + return kernel_mach_msg_rpc(msg, send_size, rcv_size, FALSE, NULL); } mach_msg_return_t -mach_msg_rpc_from_kernel_body( - mach_msg_header_t *msg, - mach_msg_size_t send_size, - mach_msg_size_t rcv_size, +kernel_mach_msg_rpc( + mach_msg_header_t *msg, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, #if !IKM_SUPPORT_LEGACY __unused #endif - boolean_t legacy) + boolean_t legacy, + boolean_t *message_moved) { thread_t self = current_thread(); ipc_port_t reply; @@ -359,11 +379,15 @@ mach_msg_rpc_from_kernel_body( assert(msg->msgh_local_port == MACH_PORT_NULL); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + + if (message_moved) { + *message_moved = FALSE; + } mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } @@ -371,29 +395,35 @@ mach_msg_rpc_from_kernel_body( if (reply == IP_NULL) { reply = ipc_port_alloc_reply(); if ((reply == IP_NULL) || - (self->ith_rpc_reply != IP_NULL)) + (self->ith_rpc_reply != IP_NULL)) { panic("mach_msg_rpc_from_kernel"); + } self->ith_rpc_reply = reply; } /* insert send-once right for the reply port */ kmsg->ikm_header->msgh_local_port = reply; kmsg->ikm_header->msgh_bits |= - MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); + MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); #if IKM_SUPPORT_LEGACY - if(legacy) - mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); - else - mr = ipc_kmsg_copyin_from_kernel(kmsg); + if (legacy) { + mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); + } else { + mr = ipc_kmsg_copyin_from_kernel(kmsg); + } #else - mr = ipc_kmsg_copyin_from_kernel(kmsg); + mr = ipc_kmsg_copyin_from_kernel(kmsg); #endif - if (mr != MACH_MSG_SUCCESS) { - ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); - return mr; - } + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_free(kmsg); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + return mr; + } + + if (message_moved) { + *message_moved = TRUE; + } /* * respect the thread's SEND_IMPORTANCE option to force importance @@ -401,22 +431,22 @@ mach_msg_rpc_from_kernel_body( * (11938665 & 23925818) */ mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT; - if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) + if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) { option &= ~MACH_SEND_NOIMPORTANCE; + } mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } for (;;) { ipc_mqueue_t mqueue; - ipc_object_t object; assert(reply->ip_in_pset == 0); - assert(ip_active(reply)); + require_ip_active(reply); /* JMM - why this check? */ if (!self->active && !self->inspection) { @@ -429,22 +459,20 @@ mach_msg_rpc_from_kernel_body( mqueue = &reply->ip_messages; ipc_mqueue_receive(mqueue, - MACH_MSG_OPTION_NONE, - MACH_MSG_SIZE_MAX, - MACH_MSG_TIMEOUT_NONE, - THREAD_INTERRUPTIBLE); + MACH_MSG_OPTION_NONE, + MACH_MSG_SIZE_MAX, + MACH_MSG_TIMEOUT_NONE, + THREAD_INTERRUPTIBLE); mr = self->ith_state; kmsg = self->ith_kmsg; seqno = self->ith_seqno; - __IGNORE_WCASTALIGN(object = (ipc_object_t) reply); - mach_msg_receive_results_complete(object); + mach_msg_receive_results_complete(ip_to_object(reply)); - if (mr == MACH_MSG_SUCCESS) - { + if (mr == MACH_MSG_SUCCESS) { break; - } + } assert(mr == MACH_RCV_INTERRUPTED); @@ -453,25 +481,24 @@ mach_msg_rpc_from_kernel_body( if (self->ast & AST_APC) { ipc_port_dealloc_reply(reply); self->ith_rpc_reply = IP_NULL; - return(mr); + return mr; } } - /* + /* * Check to see how much of the message/trailer can be received. * We chose the maximum trailer that will fit, since we don't * have options telling us which trailer elements the caller needed. */ if (rcv_size >= kmsg->ikm_header->msgh_size) { mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) - ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); + ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) { /* Enough room for a maximum trailer */ trailer->msgh_trailer_size = MAX_TRAILER_SIZE; - } - else if (rcv_size < kmsg->ikm_header->msgh_size + - trailer->msgh_trailer_size) { + } else if (rcv_size < kmsg->ikm_header->msgh_size + + trailer->msgh_trailer_size) { /* no room for even the basic (default) trailer */ trailer->msgh_trailer_size = 0; } @@ -489,17 +516,110 @@ mach_msg_rpc_from_kernel_body( * as they are. */ #if IKM_SUPPORT_LEGACY - if(legacy) - ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply); - else - ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); + if (legacy) { + ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply); + } else { + ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); + } #else - ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); + ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); #endif ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); return mr; } +/* + * Routine: mach_msg_destroy_from_kernel_proper + * Purpose: + * mach_msg_destroy_from_kernel_proper is used to destroy + * an unwanted/unexpected reply message from a MIG + * kernel-specific user-side stub. It is like ipc_kmsg_destroy(), + * except we no longer have the kmsg - just the contents. + */ +void +mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg) +{ + mach_msg_bits_t mbits = msg->msgh_bits; + ipc_object_t object; + + object = (ipc_object_t) msg->msgh_remote_port; + if (IO_VALID(object)) { + ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); + } + + /* + * The destination (now in msg->msgh_local_port via + * ipc_kmsg_copyout_to_kernel) has been consumed with + * ipc_object_copyout_dest. + */ + + /* MIG kernel users don't receive vouchers */ + assert(!MACH_MSGH_BITS_VOUCHER(mbits)); + + /* For simple messages, we're done */ + if ((mbits & MACH_MSGH_BITS_COMPLEX) == 0) { + return; + } + + /* Discard descriptor contents */ + mach_msg_body_t *body = (mach_msg_body_t *)(msg + 1); + mach_msg_descriptor_t *daddr = (mach_msg_descriptor_t *)(body + 1); + mach_msg_size_t i; + + for (i = 0; i < body->msgh_descriptor_count; i++, daddr++) { + switch (daddr->type.type) { + case MACH_MSG_PORT_DESCRIPTOR: { + mach_msg_port_descriptor_t *dsc = &daddr->port; + if (IO_VALID((ipc_object_t) dsc->name)) { + ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition); + } + break; + } + case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: + case MACH_MSG_OOL_DESCRIPTOR: { + mach_msg_ool_descriptor_t *dsc = + (mach_msg_ool_descriptor_t *)&daddr->out_of_line; + + if (dsc->size > 0) { + vm_map_copy_discard((vm_map_copy_t) dsc->address); + } else { + assert(dsc->address == (void *) 0); + } + break; + } + case MACH_MSG_OOL_PORTS_DESCRIPTOR: { + ipc_object_t *objects; + mach_msg_type_number_t j; + mach_msg_ool_ports_descriptor_t *dsc; + + dsc = (mach_msg_ool_ports_descriptor_t *)&daddr->ool_ports; + objects = (ipc_object_t *) dsc->address; + + if (dsc->count == 0) { + break; + } + assert(objects != 0); + for (j = 0; j < dsc->count; j++) { + object = objects[j]; + if (IO_VALID(object)) { + ipc_object_destroy(object, dsc->disposition); + } + } + kfree(dsc->address, (vm_size_t) dsc->count * sizeof(mach_port_t)); + break; + } + case MACH_MSG_GUARDED_PORT_DESCRIPTOR: { + mach_msg_guarded_port_descriptor_t *dsc = (mach_msg_guarded_port_descriptor_t *)&daddr->guarded_port; + if (IO_VALID((ipc_object_t) dsc->name)) { + ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition); + } + break; + } + default: + break; + } + } +} /************** These Calls are set up for kernel-loaded tasks/threads **************/ @@ -519,15 +639,15 @@ mach_msg_rpc_from_kernel_body( mach_msg_return_t mach_msg_overwrite( - mach_msg_header_t *msg, - mach_msg_option_t option, - mach_msg_size_t send_size, - mach_msg_size_t rcv_size, - mach_port_name_t rcv_name, - __unused mach_msg_timeout_t msg_timeout, - mach_msg_priority_t override, - __unused mach_msg_header_t *rcv_msg, - __unused mach_msg_size_t rcv_msg_size) + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_name_t rcv_name, + __unused mach_msg_timeout_t msg_timeout, + mach_msg_priority_t override, + __unused mach_msg_header_t *rcv_msg, + __unused mach_msg_size_t rcv_msg_size) { ipc_space_t space = current_space(); vm_map_t map = current_map(); @@ -537,37 +657,39 @@ mach_msg_overwrite( mach_msg_trailer_size_t trailer_size; if (option & MACH_SEND_MSG) { - mach_msg_size_t msg_and_trailer_size; - mach_msg_max_trailer_t *max_trailer; + mach_msg_size_t msg_and_trailer_size; + mach_msg_max_trailer_t *max_trailer; if ((send_size & 3) || send_size < sizeof(mach_msg_header_t) || - (send_size < sizeof(mach_msg_body_t) && (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX))) + (send_size < sizeof(mach_msg_base_t) && (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX))) { return MACH_SEND_MSG_TOO_SMALL; + } - if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) + if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) { return MACH_SEND_TOO_LARGE; + } - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START); msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; kmsg = ipc_kmsg_alloc(msg_and_trailer_size); if (kmsg == IKM_NULL) { - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_NO_BUFFER); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_NO_BUFFER); return MACH_SEND_NO_BUFFER; } - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE, - (uintptr_t)0, /* this should only be called from the kernel! */ - VM_KERNEL_ADDRPERM((uintptr_t)kmsg), - 0, 0, - 0); + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE, + (uintptr_t)0, /* this should only be called from the kernel! */ + VM_KERNEL_ADDRPERM((uintptr_t)kmsg), + 0, 0, + 0); (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); kmsg->ikm_header->msgh_size = send_size; - /* + /* * Reserve for the trailer the largest space (MAX_TRAILER_SIZE) * However, the internal size field of the trailer (msgh_trailer_size) * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize @@ -583,13 +705,13 @@ mach_msg_overwrite( if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); - KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } do { mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, MACH_MSG_TIMEOUT_NONE); - } while (mr == MACH_SEND_INTERRUPTED); + } while (mr == MACH_SEND_INTERRUPTED); assert(mr == MACH_MSG_SUCCESS); } @@ -602,32 +724,33 @@ mach_msg_overwrite( ipc_mqueue_t mqueue; mr = ipc_mqueue_copyin(space, rcv_name, - &mqueue, &object); - if (mr != MACH_MSG_SUCCESS) + &mqueue, &object); + if (mr != MACH_MSG_SUCCESS) { return mr; + } /* hold ref for object */ self->ith_continuation = (void (*)(mach_msg_return_t))0; ipc_mqueue_receive(mqueue, - MACH_MSG_OPTION_NONE, - MACH_MSG_SIZE_MAX, - MACH_MSG_TIMEOUT_NONE, - THREAD_ABORTSAFE); + MACH_MSG_OPTION_NONE, + MACH_MSG_SIZE_MAX, + MACH_MSG_TIMEOUT_NONE, + THREAD_ABORTSAFE); mr = self->ith_state; kmsg = self->ith_kmsg; seqno = self->ith_seqno; mach_msg_receive_results_complete(object); io_release(object); - } while (mr == MACH_RCV_INTERRUPTED); - if (mr != MACH_MSG_SUCCESS) + if (mr != MACH_MSG_SUCCESS) { return mr; + } trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, current_thread(), seqno, TRUE, - kmsg->ikm_header->msgh_remote_port->ip_context); + kmsg->ikm_header->msgh_remote_port->ip_context); if (rcv_size < (kmsg->ikm_header->msgh_size + trailer_size)) { ipc_kmsg_copyout_dest(kmsg, space); @@ -638,9 +761,9 @@ mach_msg_overwrite( mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL, option); if (mr != MACH_MSG_SUCCESS) { - if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { + if ((mr & ~MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ipc_kmsg_put_to_kernel(msg, kmsg, - kmsg->ikm_header->msgh_size + trailer_size); + kmsg->ikm_header->msgh_size + trailer_size); } else { ipc_kmsg_copyout_dest(kmsg, space); (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); @@ -651,7 +774,7 @@ mach_msg_overwrite( } (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, - kmsg->ikm_header->msgh_size + trailer_size); + kmsg->ikm_header->msgh_size + trailer_size); ipc_kmsg_free(kmsg); } @@ -667,7 +790,7 @@ mach_msg_overwrite( mach_port_t mig_get_reply_port(void) { - return (MACH_PORT_NULL); + return MACH_PORT_NULL; } /* @@ -685,7 +808,7 @@ mig_dealloc_reply_port( /* * Routine: mig_put_reply_port * Purpose: - * Called by client side interfaces after each RPC to + * Called by client side interfaces after each RPC to * let the client recycle the reply port if it wishes. */ void @@ -698,35 +821,39 @@ mig_put_reply_port( * mig_strncpy.c - by Joshua Block * * mig_strncp -- Bounded string copy. Does what the library routine strncpy - * OUGHT to do: Copies the (null terminated) string in src into dest, a + * OUGHT to do: Copies the (null terminated) string in src into dest, a * buffer of length len. Assures that the copy is still null terminated * and doesn't overflow the buffer, truncating the copy if necessary. * * Parameters: - * + * * dest - Pointer to destination buffer. - * + * * src - Pointer to source string. - * + * * len - Length of destination buffer. */ -int +int mig_strncpy( - char *dest, - const char *src, - int len) + char *dest, + const char *src, + int len) { - int i = 0; - - if (len > 0) - if (dest != NULL) { - if (src != NULL) - for (i=1; i 0) { + if (dest != NULL) { + if (src != NULL) { + for (i = 1; i < len; i++) { + if (!(*dest++ = *src++)) { + return i; + } + } + } + *dest = '\0'; + } } - return i; + return i; } /* @@ -747,9 +874,9 @@ mig_strncpy( */ int mig_strncpy_zerofill( - char *dest, - const char *src, - int len) + char *dest, + const char *src, + int len) { int i = 0; boolean_t terminated = FALSE; @@ -784,15 +911,15 @@ mig_strncpy_zerofill( void * mig_user_allocate( - vm_size_t size) + vm_size_t size) { return (char *)kalloc(size); } void mig_user_deallocate( - char *data, - vm_size_t size) + char *data, + vm_size_t size) { kfree(data, size); } @@ -805,11 +932,12 @@ mig_user_deallocate( */ kern_return_t mig_object_init( - mig_object_t mig_object, - const IMIGObject *interface) + mig_object_t mig_object, + const IMIGObject *interface) { - if (mig_object == MIG_OBJECT_NULL) + if (mig_object == MIG_OBJECT_NULL) { return KERN_INVALID_ARGUMENT; + } mig_object->pVtbl = (const IMIGObjectVtbl *)interface; mig_object->port = MACH_PORT_NULL; return KERN_SUCCESS; @@ -828,7 +956,7 @@ mig_object_init( */ void mig_object_destroy( - __assert_only mig_object_t mig_object) + __assert_only mig_object_t mig_object) { assert(mig_object->port == MACH_PORT_NULL); return; @@ -844,7 +972,7 @@ mig_object_destroy( */ void mig_object_reference( - mig_object_t mig_object) + mig_object_t mig_object) { assert(mig_object != MIG_OBJECT_NULL); mig_object->pVtbl->AddRef((IMIGObject *)mig_object); @@ -860,10 +988,16 @@ mig_object_reference( */ void mig_object_deallocate( - mig_object_t mig_object) + mig_object_t mig_object) { assert(mig_object != MIG_OBJECT_NULL); - mig_object->pVtbl->Release((IMIGObject *)mig_object); + ipc_port_t port = mig_object->port; + if (mig_object->pVtbl->Release((IMIGObject *)mig_object) == 0) { + if (IP_VALID(port)) { + assert(!port->ip_srights); + ipc_port_dealloc_kernel(port); + } + } } /* @@ -880,56 +1014,22 @@ mig_object_deallocate( */ ipc_port_t convert_mig_object_to_port( - mig_object_t mig_object) + mig_object_t mig_object) { - ipc_port_t port; - boolean_t deallocate = TRUE; - - if (mig_object == MIG_OBJECT_NULL) + if (mig_object == MIG_OBJECT_NULL) { return IP_NULL; - - port = mig_object->port; - while ((port == IP_NULL) || - ((port = ipc_port_make_send(port)) == IP_NULL)) { - ipc_port_t previous; - - /* - * Either the port was never set up, or it was just - * deallocated out from under us by the no-senders - * processing. In either case, we must: - * Attempt to make one - * Arrange for no senders - * Try to atomically register it with the object - * Destroy it if we are raced. - */ - port = ipc_port_alloc_kernel(); - ip_lock(port); - ipc_kobject_set_atomically(port, - (ipc_kobject_t) mig_object, - IKOT_MIG); - - /* make a sonce right for the notification */ - port->ip_sorights++; - ip_reference(port); - - ipc_port_nsrequest(port, 1, port, &previous); - /* port unlocked */ - - assert(previous == IP_NULL); - - if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, - (void * volatile *)&mig_object->port)) { - deallocate = FALSE; - } else { - ipc_port_dealloc_kernel(port); - port = mig_object->port; - } } - if (deallocate) - mig_object->pVtbl->Release((IMIGObject *)mig_object); + /* + * make a send right and donate our reference for mig_object_no_senders + * if this is the first send right + */ + if (!ipc_kobject_make_send_lazy_alloc_port(&mig_object->port, + (ipc_kobject_t) mig_object, IKOT_MIG)) { + mig_object_deallocate(mig_object); + } - return (port); + return mig_object->port; } @@ -948,14 +1048,15 @@ convert_mig_object_to_port( */ mig_object_t convert_port_to_mig_object( - ipc_port_t port, - const MIGIID *iid) + ipc_port_t port, + const MIGIID *iid) { - mig_object_t mig_object; - void *ppv; + mig_object_t mig_object; + void *ppv; - if (!IP_VALID(port)) + if (!IP_VALID(port)) { return NULL; + } ip_lock(port); if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) { @@ -968,7 +1069,7 @@ convert_port_to_mig_object( * query it to get a reference to the desired interface. */ ppv = NULL; - mig_object = (mig_object_t)port->ip_kobject; + mig_object = (mig_object_t) ip_get_kobject(port); mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv); ip_unlock(port); return (mig_object_t)ppv; @@ -980,60 +1081,19 @@ convert_port_to_mig_object( * Base implementation of a no-senders notification handler * for MIG objects. If there truly are no more senders, must * destroy the port and drop its reference on the object. - * Returns: - * TRUE - port deallocate and reference dropped - * FALSE - more senders arrived, re-registered for notification * Conditions: * Nothing locked. */ - -boolean_t +void mig_object_no_senders( - ipc_port_t port, - mach_port_mscount_t mscount) + ipc_port_t port) { - mig_object_t mig_object; - - ip_lock(port); - if (port->ip_mscount > mscount) { - ipc_port_t previous; - - /* - * Somebody created new send rights while the - * notification was in-flight. Just create a - * new send-once right and re-register with - * the new (higher) mscount threshold. - */ - /* make a sonce right for the notification */ - port->ip_sorights++; - ip_reference(port); - ipc_port_nsrequest(port, mscount, port, &previous); - /* port unlocked */ - - assert(previous == IP_NULL); - return (FALSE); - } + require_ip_active(port); + assert(IKOT_MIG == ip_kotype(port)); - /* - * Clear the port pointer while we have it locked. - */ - mig_object = (mig_object_t)port->ip_kobject; - mig_object->port = IP_NULL; - - /* - * Bring the sequence number and mscount in - * line with ipc_port_destroy assertion. - */ - port->ip_mscount = 0; - port->ip_messages.imq_seqno = 0; - ipc_port_destroy(port); /* releases lock */ - - /* - * Release the port's reference on the object. - */ - mig_object->pVtbl->Release((IMIGObject *)mig_object); - return (TRUE); -} + /* consume the reference donated by convert_mig_object_to_port */ + mig_object_deallocate((mig_object_t) ip_get_kobject(port)); +} /* * Kernel implementation of the notification chain for MIG object