X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4e3aa066abc0728aacb4bbeb86f53f9737156e..db6096698656d32db7df630594bd9617ee54f828:/osfmk/kern/ipc_mig.c diff --git a/osfmk/kern/ipc_mig.c b/osfmk/kern/ipc_mig.c index 2b22fcf1f..512073675 100644 --- a/osfmk/kern/ipc_mig.c +++ b/osfmk/kern/ipc_mig.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ @@ -50,9 +56,6 @@ /* */ -#include -#include - #include #include #include @@ -60,13 +63,14 @@ #include #include -#include #include #include +#include #include #include #include #include + #include #include #include @@ -75,8 +79,11 @@ #include #include #include +#include #include +#include + /* * Routine: mach_msg_send_from_kernel * Purpose: @@ -89,10 +96,18 @@ * Nothing locked. * Returns: * MACH_MSG_SUCCESS Sent the message. - * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer * MACH_SEND_INVALID_DEST Bad destination port. + * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer + * or destination is above kernel limit */ +#if IKM_SUPPORT_LEGACY + +#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_return_t mach_msg_send_from_kernel( mach_msg_header_t *msg, @@ -101,19 +116,84 @@ mach_msg_send_from_kernel( ipc_kmsg_t kmsg; mach_msg_return_t mr; - if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port)) - return MACH_SEND_INVALID_DEST; + mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); + if (mr != MACH_MSG_SUCCESS) + return mr; + + mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_free(kmsg); + return mr; + } + + mr = ipc_kmsg_send_always(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_destroy(kmsg); + } + + return mr; +} + +#endif /* IKM_SUPPORT_LEGACY */ + +mach_msg_return_t +mach_msg_send_from_kernel_proper( + mach_msg_header_t *msg, + mach_msg_size_t send_size) +{ + ipc_kmsg_t kmsg; + mach_msg_return_t mr; mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) return mr; - ipc_kmsg_copyin_from_kernel(kmsg); - ipc_kmsg_send_always(kmsg); + mr = ipc_kmsg_copyin_from_kernel(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_free(kmsg); + return mr; + } - return MACH_MSG_SUCCESS; + mr = ipc_kmsg_send_always(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_destroy(kmsg); + } + + return mr; } +#if IKM_SUPPORT_LEGACY + +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) +{ + ipc_kmsg_t kmsg; + mach_msg_return_t mr; + + mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); + if (mr != MACH_MSG_SUCCESS) + return mr; + + mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_free(kmsg); + return mr; + } + + mr = ipc_kmsg_send(kmsg, option, timeout_val); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_destroy(kmsg); + } + + return mr; +} + +#endif /* IKM_SUPPORT_LEGACY */ + /* * Routine: mach_msg_rpc_from_kernel * Purpose: @@ -129,11 +209,47 @@ mach_msg_send_from_kernel( * 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_return_t +mach_msg_rpc_from_kernel( + 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); +} + +#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) +{ + return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, FALSE); +} + +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, +#if !IKM_SUPPORT_LEGACY + __unused +#endif + boolean_t legacy) { thread_t self = current_thread(); ipc_port_t reply; @@ -141,20 +257,15 @@ mach_msg_rpc_from_kernel( mach_port_seqno_t seqno; mach_msg_return_t mr; - assert(MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port)); assert(msg->msgh_local_port == MACH_PORT_NULL); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) return mr; - rpc_lock(self); - reply = self->ith_rpc_reply; if (reply == IP_NULL) { - rpc_unlock(self); reply = ipc_port_alloc_reply(); - rpc_lock(self); if ((reply == IP_NULL) || (self->ith_rpc_reply != IP_NULL)) panic("mach_msg_rpc_from_kernel"); @@ -162,16 +273,29 @@ mach_msg_rpc_from_kernel( } /* insert send-once right for the reply port */ - kmsg->ikm_header.msgh_local_port = reply; - kmsg->ikm_header.msgh_bits |= + kmsg->ikm_header->msgh_local_port = reply; + kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); - ipc_port_reference(reply); - rpc_unlock(self); - - ipc_kmsg_copyin_from_kernel(kmsg); - - ipc_kmsg_send_always(kmsg); + ip_reference(reply); + +#if IKM_SUPPORT_LEGACY + 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); +#endif + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_free(kmsg); + return mr; + } + mr = ipc_kmsg_send_always(kmsg); + if (mr != MACH_MSG_SUCCESS) { + ipc_kmsg_destroy(kmsg); + return mr; + } for (;;) { ipc_mqueue_t mqueue; @@ -179,12 +303,12 @@ mach_msg_rpc_from_kernel( ip_lock(reply); if ( !ip_active(reply)) { ip_unlock(reply); - ipc_port_release(reply); + ip_release(reply); return MACH_RCV_PORT_DIED; } - if (!self->top_act || !self->top_act->active) { + if (!self->active) { ip_unlock(reply); - ipc_port_release(reply); + ip_release(reply); return MACH_RCV_INTERRUPTED; } @@ -211,51 +335,61 @@ mach_msg_rpc_from_kernel( assert(mr == MACH_RCV_INTERRUPTED); - if (self->top_act && self->top_act->handlers) { - ipc_port_release(reply); + if (self->handlers) { + ip_release(reply); return(mr); } } - ipc_port_release(reply); + ip_release(reply); - /* - * XXXXX Set manually for now ... - * No, why even bother, since the effort is wasted? - * - { mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) - ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size); - trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; - trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; + /* + * 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); + + 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) { + /* no room for even the basic (default) trailer */ + trailer->msgh_trailer_size = 0; + } + assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0); + rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size; + mr = MACH_MSG_SUCCESS; + } else { + mr = MACH_RCV_TOO_LARGE; } - *****/ - if (rcv_size < kmsg->ikm_header.msgh_size) { - ipc_kmsg_copyout_dest(kmsg, ipc_space_reply); - ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size); - return MACH_RCV_TOO_LARGE; - } /* * We want to preserve rights and memory in reply! * We don't have to put them anywhere; just leave them * as they are. */ - - ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); - ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size); - return MACH_MSG_SUCCESS; +#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); +#else + ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); +#endif + ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); + return mr; } -/************** These Calls are set up for kernel-loaded tasks **************/ -/************** Apple does not plan on supporting that. These **************/ -/************** need to be reworked to deal with the kernel **************/ -/************** proper to eliminate the kernel specific code MIG **************/ -/************** must generate. **************/ - +/************** These Calls are set up for kernel-loaded tasks/threads **************/ /* - * Routine: mach_msg + * Routine: mach_msg_overwrite * Purpose: * Like mach_msg_overwrite_trap except that message buffers * live in kernel space. Doesn't handle any options. @@ -270,29 +404,56 @@ mach_msg_rpc_from_kernel( mach_msg_return_t mach_msg_overwrite( - mach_msg_header_t *msg, - mach_msg_option_t option, + 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, - mach_msg_timeout_t timeout, - mach_port_name_t notify, - mach_msg_header_t *rcv_msg, - mach_msg_size_t rcv_msg_size) + mach_port_name_t rcv_name, + __unused mach_msg_timeout_t msg_timeout, + __unused mach_port_name_t notify, + __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(); ipc_kmsg_t kmsg; mach_port_seqno_t seqno; mach_msg_return_t mr; - mach_msg_format_0_trailer_t *trailer; + mach_msg_trailer_size_t trailer_size; if (option & MACH_SEND_MSG) { - mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); - if (mr != MACH_MSG_SUCCESS) - panic("mach_msg"); + mach_msg_size_t msg_and_trailer_size; + mach_msg_max_trailer_t *max_trailer; + + if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) + return MACH_SEND_MSG_TOO_SMALL; + + if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) + return MACH_SEND_TOO_LARGE; + + msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; + kmsg = ipc_kmsg_alloc(msg_and_trailer_size); + + if (kmsg == IKM_NULL) + return MACH_SEND_NO_BUFFER; + + (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); + + kmsg->ikm_header->msgh_size = send_size; - mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL); + /* + * 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 + * the cases where no implicit data is requested. + */ + max_trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); + max_trailer->msgh_sender = current_thread()->task->sec_token; + max_trailer->msgh_audit = current_thread()->task->audit_token; + max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; + max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; + + mr = ipc_kmsg_copyin(kmsg, space, map, FALSE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); return mr; @@ -328,41 +489,40 @@ mach_msg_overwrite( kmsg = self->ith_kmsg; seqno = self->ith_seqno; - ipc_object_release(object); + io_release(object); } while (mr == MACH_RCV_INTERRUPTED); if (mr != MACH_MSG_SUCCESS) return mr; - trailer = (mach_msg_format_0_trailer_t *) - ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size); - if (option & MACH_RCV_TRAILER_MASK) { - trailer->msgh_seqno = seqno; - trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); - } - if (rcv_size < (kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size)) { + trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, current_thread(), seqno, TRUE, + kmsg->ikm_header->msgh_remote_port->ip_context); + + if (rcv_size < (kmsg->ikm_header->msgh_size + trailer_size)) { ipc_kmsg_copyout_dest(kmsg, space); - ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg); + (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); + ipc_kmsg_free(kmsg); return MACH_RCV_TOO_LARGE; } - mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, - MACH_MSG_BODY_NULL); + mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); if (mr != MACH_MSG_SUCCESS) { if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ipc_kmsg_put_to_kernel(msg, kmsg, - kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size); + kmsg->ikm_header->msgh_size + trailer_size); } else { ipc_kmsg_copyout_dest(kmsg, space); - ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg); + (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); + ipc_kmsg_free(kmsg); } return mr; } - ipc_kmsg_put_to_kernel(msg, kmsg, - kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size); + (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, + kmsg->ikm_header->msgh_size + trailer_size); + ipc_kmsg_free(kmsg); } return MACH_MSG_SUCCESS; @@ -372,41 +532,24 @@ mach_msg_overwrite( * Routine: mig_get_reply_port * Purpose: * Called by client side interfaces living in the kernel - * to get a reply port. This port is used for - * mach_msg() calls which are kernel calls. + * to get a reply port. */ mach_port_t mig_get_reply_port(void) { - thread_t self = current_thread(); - - assert(self->ith_mig_reply == (mach_port_t)0); - - /* - * JMM - for now we have no real clients of this under the kernel - * loaded server model because we only have one of those. In order - * to avoid MIG changes, we just return null here - and return] - * references to ipc_port_t's instead of names. - * - * if (self->ith_mig_reply == MACH_PORT_NULL) - * self->ith_mig_reply = mach_reply_port(); - */ - return self->ith_mig_reply; + return (MACH_PORT_NULL); } /* * Routine: mig_dealloc_reply_port * Purpose: * Called by client side interfaces to get rid of a reply port. - * Shouldn't ever be called inside the kernel, because - * kernel calls shouldn't prompt Mig to call it. */ void mig_dealloc_reply_port( - mach_port_t reply_port) + __unused mach_port_t reply_port) { - panic("mig_dealloc_reply_port"); } /* @@ -417,7 +560,7 @@ mig_dealloc_reply_port( */ void mig_put_reply_port( - mach_port_t reply_port) + __unused mach_port_t reply_port) { } @@ -439,9 +582,9 @@ mig_put_reply_port( */ int mig_strncpy( - char *dest, - char *src, - int len) + char *dest, + const char *src, + int len) { int i = 0; @@ -468,7 +611,7 @@ mig_user_deallocate( char *data, vm_size_t size) { - kfree((vm_offset_t)data, size); + kfree(data, size); } /* @@ -482,9 +625,11 @@ mig_object_init( mig_object_t mig_object, const IMIGObject *interface) { - assert(mig_object != MIG_OBJECT_NULL); - mig_object->pVtbl = (IMIGObjectVtbl *)interface; + 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; } /* @@ -500,7 +645,7 @@ mig_object_init( */ void mig_object_destroy( - mig_object_t mig_object) + __assert_only mig_object_t mig_object) { assert(mig_object->port == MACH_PORT_NULL); return; @@ -589,9 +734,8 @@ convert_mig_object_to_port( assert(previous == IP_NULL); - if (OSCompareAndSwap((UInt32)IP_NULL, - (UInt32)port, - (UInt32 *)&mig_object->port)) { + if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, + (void * volatile *)&mig_object->port)) { deallocate = FALSE; } else { ipc_port_dealloc_kernel(port);